From c5e91b94c4d74658c2b927df95dfcaa115236e0f Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Thu, 11 Feb 2021 23:42:08 +0200 Subject: [PATCH] xwayland: Refuse to create connection sockets if sockets dir doesn't exist Since kwin runs as a normal user, it cannot create the X11 connection socket directory because any user process can easily compromise the security of the system by unsetting the sticky bit. In order to guarantee the security of the system, the socket directory must be created by root and have the sticky bit on. --- src/xwl/xwaylandsocket.cpp | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/xwl/xwaylandsocket.cpp b/src/xwl/xwaylandsocket.cpp index 96c64d7c59..b7ba5ce657 100644 --- a/src/xwl/xwaylandsocket.cpp +++ b/src/xwl/xwaylandsocket.cpp @@ -8,12 +8,12 @@ #include "xwayland_logging.h" #include -#include #include #include #include #include +#include #include #include @@ -128,11 +128,41 @@ static int listen_helper(const QString &filePath, UnixSocketAddress::Type type) return fileDescriptor; } +static bool checkSocketsDirectory() +{ + struct stat info; + const char *path = "/tmp/.X11-unix"; + + if (lstat(path, &info) != 0) { + if (errno == ENOENT) { + qCWarning(KWIN_XWL) << path << "does not exist. Please check your installation"; + return false; + } + + qCWarning(KWIN_XWL, "Failed to stat %s: %s", path, strerror(errno)); + return false; + } + + if (!S_ISDIR(info.st_mode)) { + qCWarning(KWIN_XWL) << path << "is not a directory. Broken system?"; + return false; + } + if (info.st_uid != 0) { + qCWarning(KWIN_XWL) << path << "is not owned by root. Your system might be compromised!"; + return false; + } + if (!(info.st_mode & S_ISVTX)) { + qCWarning(KWIN_XWL) << path << "has no sticky bit on. Your system might be compromised!"; + return false; + } + + return true; +} + XwaylandSocket::XwaylandSocket() { - QDir socketDirectory(QStringLiteral("/tmp/.X11-unix")); - if (!socketDirectory.exists()) { - socketDirectory.mkpath(QStringLiteral(".")); + if (!checkSocketsDirectory()) { + return; } for (int display = 0; display < 100; ++display) {