Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Depends: ${shlibs:Depends},
dde-seatd,
treeland,
libpam-systemd,
libcap2-bin,
Description: a modern display manager for Wayland sessions aiming to be fast, simple and beautiful.

Package: libddm
Expand Down
20 changes: 20 additions & 0 deletions debian/ddm.postinst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ fi
touch /var/log/ddm.log
chown dde:dde /var/log/ddm.log

# Xwayland runs as the display-manager user (e.g. "dde") while X11 clients
# (e.g. Electron apps) may be launched by the real login user. MIT-SHM
# (XShmPutImage) fails with BadAccess when the SysV shared memory segment UID
# differs from the X server UID, leaving such windows blank. Grant cap_ipc_owner
# to the Xwayland binary so shmat() can attach segments of any user; the X
# server still enforces its own per-client access check (Xext/shm.c:shm_access).
# The daemon re-applies this at startup too, in case an Xwayland package
# upgrade clears the file capability.
if command -v setcap >/dev/null 2>&1; then
XWAYLAND_BIN="$(command -v Xwayland 2>/dev/null || true)"
if [ -z "$XWAYLAND_BIN" ]; then
XWAYLAND_BIN=/usr/bin/Xwayland
fi
if [ -x "$XWAYLAND_BIN" ]; then
if ! setcap cap_ipc_owner=ep "$XWAYLAND_BIN" 2>/dev/null; then
echo "ddm: warning: failed to set cap_ipc_owner on $XWAYLAND_BIN" >&2
fi
fi
fi

#DEBHELPER#

exit 0
13 changes: 13 additions & 0 deletions debian/ddm.postrm
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@ set -e
DEFAULT_DISPLAY_MANAGER_FILE=/etc/X11/default-display-manager
DEFAULT_SERVICE=/etc/systemd/system/display-manager.service

# Remove the cap_ipc_owner file capability granted at install time (see
# ddm.postinst). Only runs on remove/purge; upgrades keep the cap.
cleanup_xwayland_cap() {
if command -v setcap >/dev/null 2>&1; then
for BIN in "$(command -v Xwayland 2>/dev/null || true)" /usr/bin/Xwayland; do
[ -z "$BIN" ] && continue
[ -x "$BIN" ] && setcap -r "$BIN" 2>/dev/null || true
done
fi
}

case "$1" in
purge)
update-rc.d ddm remove > /dev/null
cleanup_xwayland_cap

if [ -d /var/cache/ddm ]; then rm -r /var/cache/ddm; fi
if [ -d /var/lib/ddm ]; then rm -r /var/lib/ddm; fi
Expand Down Expand Up @@ -35,6 +47,7 @@ case "$1" in

;;
remove)
cleanup_xwayland_cap
# Update the display-manager.service symlink to point to the newly
# chosen display manager (written by prerm into DEFAULT_DISPLAY_MANAGER_FILE)
if [ -e "$DEFAULT_DISPLAY_MANAGER_FILE" ] && [ -d /etc/systemd/system/ ]; then
Expand Down
50 changes: 50 additions & 0 deletions src/daemon/DaemonApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,56 @@

#include "MessageHandler.h"

#include <QDBusConnectionInterface>

Check warning on line 34 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDBusConnectionInterface> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDBusInterface>

Check warning on line 35 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDBusInterface> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QDebug>

Check warning on line 36 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QDebug> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFile>

Check warning on line 37 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFile> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QFileInfo>

Check warning on line 38 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QFileInfo> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QHostInfo>

Check warning on line 39 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QHostInfo> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QProcess>

Check warning on line 40 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QProcess> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QStandardPaths>

Check warning on line 41 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QStandardPaths> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <QTimer>

Check warning on line 42 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <QTimer> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <iostream>

Check warning on line 44 in src/daemon/DaemonApp.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <iostream> not found. Please note: Cppcheck does not need standard library headers to get proper results.

namespace DDM {
DaemonApp *DaemonApp::self = nullptr;

static void applyXwaylandIpcCapability()
{
const QStringList candidates = [&]() -> QStringList {
QStringList list;
const QString found = QStandardPaths::findExecutable(QStringLiteral("Xwayland"));
if (!found.isEmpty())
list << found;
list << QStringLiteral("/usr/bin/Xwayland");
return list;
}();

const QString setcapBin = []() -> QString {
QString bin = QStandardPaths::findExecutable(QStringLiteral("setcap"));
if (bin.isEmpty() && QFile::exists(QStringLiteral("/usr/sbin/setcap")))
bin = QStringLiteral("/usr/sbin/setcap");
return bin;
}();
if (setcapBin.isEmpty()) {
qWarning() << "setcap not found, cannot grant cap_ipc_owner to Xwayland";
return;
}

for (const QString &path : std::as_const(candidates)) {
if (!QFile::exists(path) || !QFileInfo(path).isExecutable())
continue;
const int ret = QProcess::execute(setcapBin,
{ QStringLiteral("cap_ipc_owner=ep"), path });
if (ret == 0)
qInfo() << "Granted cap_ipc_owner to" << path;
else
qWarning() << "setcap on" << path << "failed (exit" << ret << ")";
break;
}
}

DaemonApp::DaemonApp(int &argc, char **argv) : QCoreApplication(argc, argv) {
// point instance to this
self = this;
Expand Down Expand Up @@ -95,6 +134,17 @@
// log message
qDebug() << "Starting...";

// Xwayland runs as the display manager's user (e.g. "dde") while
// desktop X11 clients may be launched by the real login user.
// MIT-SHM (XShmPutImage) fails with BadAccess when the SysV shared
// memory segment UID differs from the X server UID ── shmat() is
// denied by the kernel. Grant cap_ipc_owner to the Xwayland binary
// so it can attach segments created by any user on the machine.
// The X server still enforces its own per-client access check
// (Xext/shm.c:shm_access, which verifies the client owns the seg).
// See also: debian/ddm.postinst (install-time) and postrm (cleanup).
applyXwaylandIpcCapability();

m_seatManager->initialize();
}

Expand Down
Loading