From e39dfb80be2cc5b4341f3f051ecae5b3c78de43b Mon Sep 17 00:00:00 2001 From: Kishi <41839133+Kishi85@users.noreply.github.com> Date: Mon, 20 Apr 2026 19:05:42 +0200 Subject: [PATCH] refactor(linux/xdgportal): Move elevated privilege check/drop to misc.cpp (#5026) --- src/platform/common.h | 11 +++++ src/platform/linux/misc.cpp | 65 ++++++++++++++++++++++++++++ src/platform/linux/portalgrab.cpp | 70 ++----------------------------- 3 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/platform/common.h b/src/platform/common.h index 0777a506..830c4662 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -896,4 +896,15 @@ namespace platf { */ std::unique_ptr create_high_precision_timer(); + /** + * @brief Check is the current process is running with elevated privileges (e.g. system admin/etc.) + * @return True if system admin capabilities are present. + */ + bool has_elevated_privileges(); + + /** + * @brief Drop elevated privileges (e.g. system admin/etc.) + */ + void drop_elevated_privileges(); + } // namespace platf diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 6839c0bb..4c783ae8 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -25,6 +25,10 @@ #include // For setpriority #include +#if !defined(__FreeBSD__) + #include + #include +#endif #ifdef __FreeBSD__ #include // For sockaddr_dl, LLADDR, and AF_LINK #include // For syscall: SYS_thr_self @@ -1226,4 +1230,65 @@ namespace platf { return detected.empty() ? "/dev/dri/renderD128" : detected; } +#if !defined(__FreeBSD__) + constexpr std::array ELEVATED_PRIVILEGES_EFFECTIVE {CAP_SYS_ADMIN, CAP_SYS_NICE}; + constexpr std::array ELEVATED_PRIVILEGES_PERMITTED {CAP_SYS_ADMIN, CAP_SYS_NICE}; +#endif + + bool has_elevated_privileges() { +#if !defined(__FreeBSD__) + const cap_t caps = cap_get_proc(); + if (!caps) { + BOOST_LOG(error) << "[misc] has_elevated_privileges failed to get process capabilities."sv; + return false; + } + for (const auto c : ELEVATED_PRIVILEGES_EFFECTIVE) { + cap_flag_value_t cap_flags_value; + cap_get_flag(caps, c, CAP_EFFECTIVE, &cap_flags_value); + if (cap_flags_value == CAP_SET) { + BOOST_LOG(debug) << "[misc] has_elevated_privileges found effective cap:"sv << c; + return true; + } + } + for (const auto c : ELEVATED_PRIVILEGES_PERMITTED) { + cap_flag_value_t cap_flags_value; + cap_get_flag(caps, c, CAP_PERMITTED, &cap_flags_value); + if (cap_flags_value == CAP_SET) { + BOOST_LOG(debug) << "[misc] has_elevated_privileges found permitted cap:"sv << c; + return true; + } + } + cap_free(caps); +#endif + return false; + } + + void drop_elevated_privileges() { +#if !defined(__FreeBSD__) + bool failed = false; + const cap_t caps = cap_get_proc(); + if (!caps) { + BOOST_LOG(error) << "[misc] drop_elevated_privileges failed to get process capabilities"sv; + return; + } + + cap_set_flag(caps, CAP_EFFECTIVE, ELEVATED_PRIVILEGES_EFFECTIVE.size(), ELEVATED_PRIVILEGES_EFFECTIVE.data(), CAP_CLEAR); + cap_set_flag(caps, CAP_PERMITTED, ELEVATED_PRIVILEGES_PERMITTED.size(), ELEVATED_PRIVILEGES_PERMITTED.data(), CAP_CLEAR); + + if (cap_set_proc(caps) != 0) { + BOOST_LOG(error) << "[misc] drop_elevated_privileges failed to prune capabilities: "sv << std::strerror(errno); + failed = true; + } + cap_free(caps); + + // Reset dumpable AFTER the caps have been pruned to ensure /proc/pid/root is accessible. + if (prctl(PR_SET_DUMPABLE, 1) != 0) { + BOOST_LOG(error) << "[misc] drop_elevated_privileges failed to set PR_SET_DUMPABLE: "sv << std::strerror(errno); + failed = true; + } + if (!failed) { + BOOST_LOG(info) << "[misc] drop_elevated_privileges succeeded in dropping capabilities"sv; + } +#endif + } } // namespace platf diff --git a/src/platform/linux/portalgrab.cpp b/src/platform/linux/portalgrab.cpp index 7f6feb7a..03f50b57 100644 --- a/src/platform/linux/portalgrab.cpp +++ b/src/platform/linux/portalgrab.cpp @@ -33,12 +33,6 @@ #include "vulkan_encode.h" #include "wayland.h" -#if !defined(__FreeBSD__) - // platform includes - #include - #include -#endif - namespace { // Portal configuration constants constexpr uint32_t SOURCE_TYPE_MONITOR = 1; @@ -728,64 +722,6 @@ namespace portal { } }; - /** - * @brief Singleton for portalgrab stuff persistent during an application run. - * - */ - class runtime_t { - public: - static runtime_t &instance(); - - bool is_portal_secured() const { - return is_portal_secured_; - } - - void finalize_portal_security() { -#if !defined(__FreeBSD__) - BOOST_LOG(debug) << "[portalgrab] Finalizing Portal security: dropping capabilities and resetting dumpable"sv; - - cap_t caps = cap_get_proc(); - if (!caps) { - BOOST_LOG(error) << "[portalgrab] Failed to get process capabilities"sv; - return; - } - - std::array effective_list {CAP_SYS_ADMIN, CAP_SYS_NICE}; - std::array permitted_list {CAP_SYS_ADMIN, CAP_SYS_NICE}; - - cap_set_flag(caps, CAP_EFFECTIVE, effective_list.size(), effective_list.data(), CAP_CLEAR); - cap_set_flag(caps, CAP_PERMITTED, permitted_list.size(), permitted_list.data(), CAP_CLEAR); - - if (cap_set_proc(caps) != 0) { - BOOST_LOG(error) << "[portalgrab] Failed to prune capabilities: "sv << std::strerror(errno); - } - cap_free(caps); - - // Reset dumpable AFTER the caps have been pruned to ensure the Portal can - // access /proc/pid/root. - if (prctl(PR_SET_DUMPABLE, 1) != 0) { - BOOST_LOG(error) << "[portalgrab] Failed to set PR_SET_DUMPABLE: "sv << std::strerror(errno); - } -#endif - is_portal_secured_ = true; - } - - private: - runtime_t() = default; - - // Prevent copying - runtime_t(const runtime_t &) = delete; - runtime_t &operator=(const runtime_t &) = delete; - - bool is_portal_secured_ = false; - }; - - runtime_t &runtime_t::instance() { - alignas(runtime_t) static std::array storage; - static auto instance_ = new (storage.data()) runtime_t(); - return *instance_; - } - class portal_t: public pipewire::pipewire_display_t { public: int configure_stream(const std::string &display_name, int &out_pipewire_fd, int &out_pipewire_node, int &out_pos_x, int &out_pos_y, int &out_width, int &out_height) override { @@ -870,7 +806,9 @@ namespace platf { } // Drop CAP_SYS_ADMIN and set DUMPABLE flag to allow XDG /root access - portal::runtime_t::instance().finalize_portal_security(); + if (has_elevated_privileges()) { + drop_elevated_privileges(); + } auto portal = std::make_shared(); if (portal->init(hwdevice_type, display_name, config)) { @@ -889,7 +827,7 @@ namespace platf { return {}; } - if (!portal::runtime_t::instance().is_portal_secured()) { + if (has_elevated_privileges()) { // We're still in the probing phase of Sunshine startup. Dropping portal security early will break KMS. // Just return a dummy screen for now. Display re-enumeration after encoder probing will yield full result. display_names.emplace_back("init");