diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 1cfbf0e1..6d0d8b1e 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1319,6 +1319,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "xwayland:create_abstract_socket", + .description = "Create the abstract Unix domain socket for XWayland", + .type = CONFIG_OPTION_BOOL, + .data = SConfigOptionDescription::SBoolData{false}, + }, /* * opengl: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 82fe2d41..90ec6305 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -652,6 +652,7 @@ CConfigManager::CConfigManager() { registerConfigVar("xwayland:enabled", Hyprlang::INT{1}); registerConfigVar("xwayland:use_nearest_neighbor", Hyprlang::INT{1}); registerConfigVar("xwayland:force_zero_scaling", Hyprlang::INT{0}); + registerConfigVar("xwayland:create_abstract_socket", Hyprlang::INT{0}); registerConfigVar("opengl:nvidia_anti_flicker", Hyprlang::INT{1}); diff --git a/src/xwayland/Server.cpp b/src/xwayland/Server.cpp index 99bcdf62..6f057f9e 100644 --- a/src/xwayland/Server.cpp +++ b/src/xwayland/Server.cpp @@ -20,6 +20,7 @@ #include "Server.hpp" #include "XWayland.hpp" +#include "config/ConfigValue.hpp" #include "debug/Log.hpp" #include "../defines.hpp" #include "../Compositor.hpp" @@ -32,31 +33,45 @@ constexpr int SOCKET_BACKLOG = 1; constexpr int MAX_SOCKET_RETRIES = 32; constexpr int LOCK_FILE_MODE = 0444; -static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t path_size) { - socklen_t size = offsetof(struct sockaddr_un, sun_path) + path_size + 1; - CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; +static CFileDescriptor createSocket(struct sockaddr_un* addr, size_t pathSize) { + const bool isRegularSocket(addr->sun_path[0]); + const char dbgSocketPathPrefix = isRegularSocket ? addr->sun_path[0] : '@'; + const char* const dbgSocketPathRem = addr->sun_path + 1; + + socklen_t size = offsetof(struct sockaddr_un, sun_path) + pathSize + 1; + CFileDescriptor fd{socket(AF_UNIX, SOCK_STREAM, 0)}; if (!fd.isValid()) { - Debug::log(ERR, "Failed to create socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); + Debug::log(ERR, "Failed to create socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem); return {}; } if (!fd.setFlags(fd.getFlags() | FD_CLOEXEC)) { + Debug::log(ERR, "Failed to set flags for socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem); return {}; } - if (addr->sun_path[0]) + if (isRegularSocket) unlink(addr->sun_path); if (bind(fd.get(), (struct sockaddr*)addr, size) < 0) { - Debug::log(ERR, "Failed to bind socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - if (addr->sun_path[0]) + Debug::log(ERR, "Failed to bind socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem); + if (isRegularSocket) unlink(addr->sun_path); return {}; } + // Required for the correct functioning of `xhost` #9574 + // The operation is safe because XWayland controls socket access by itself + // and rejects connections not matched by the `xhost` ACL + if (isRegularSocket && chmod(addr->sun_path, 0666) < 0) { + // We are only extending the default permissions, + // and I don't see the reason to make a full stop in case of a failed operation. + Debug::log(ERR, "Failed to set permission mode for socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem); + } + if (listen(fd.get(), SOCKET_BACKLOG) < 0) { - Debug::log(ERR, "Failed to listen to socket {}{}", addr->sun_path[0] ? addr->sun_path[0] : '@', addr->sun_path + 1); - if (addr->sun_path[0]) + Debug::log(ERR, "Failed to listen to socket {}{}", dbgSocketPathPrefix, dbgSocketPathRem); + if (isRegularSocket) unlink(addr->sun_path); return {}; } @@ -113,14 +128,32 @@ static std::string getSocketPath(int display, bool isLinux) { } static bool openSockets(std::array& sockets, int display) { + static auto CREATEABSTRACTSOCKET = CConfigValue("xwayland:create_abstract_socket"); + if (!ensureSocketDirExists()) return false; sockaddr_un addr = {.sun_family = AF_UNIX}; std::string path; +#ifdef __linux__ + if (*CREATEABSTRACTSOCKET) { + // cursed... + // but is kept as an option for better compatibility + addr.sun_path[0] = 0; + path = getSocketPath(display, true); + strncpy(addr.sun_path + 1, path.c_str(), path.length() + 1); + } else { + path = getSocketPath(display, false); + strncpy(addr.sun_path, path.c_str(), path.length() + 1); + } +#else + if (*CREATEABSTRACTSOCKET) { + Debug::log(WARN, "The abstract XWayland Unix domain socket might be used only on Linux systems. A regular one'll be created insted."); + } path = getSocketPath(display, false); strncpy(addr.sun_path, path.c_str(), path.length() + 1); +#endif sockets[0] = CFileDescriptor{createSocket(&addr, path.length())}; if (!sockets[0].isValid()) @@ -220,12 +253,10 @@ CXWaylandServer::~CXWaylandServer() { safeRemove(lockPath); std::string path; -#ifdef __linux__ - path = getSocketPath(display, true); -#else - path = getSocketPath(display, false); -#endif - safeRemove(path); + for (bool isLinux : {true, false}) { + path = getSocketPath(display, isLinux); + safeRemove(path); + } } void CXWaylandServer::die() {