diff --git a/src/platform/common.h b/src/platform/common.h index 9f11b8473..96c42f4de 100644 --- a/src/platform/common.h +++ b/src/platform/common.h @@ -895,13 +895,15 @@ namespace platf { /** * @brief Check is the current process is running with elevated privileges (e.g. system admin/etc.) - * @return True if system admin capabilities are present. + * @param all_caps Bool that specifies whether to check all caps or only CAP_SYS_ADMIN + * @return True if capabilities specified to be checked are present. */ - bool has_elevated_privileges(); + bool has_elevated_privileges(bool all_caps); /** - * @brief Drop elevated privileges (e.g. system admin/etc.) + * @brief Drop elevated privileges (e.g. system admin/nice etc.) + * @param all_caps Bool that specifies whether to drop all caps or only CAP_SYS_ADMIN */ - void drop_elevated_privileges(); + void drop_elevated_privileges(bool all_caps); } // namespace platf diff --git a/src/platform/linux/kwingrab.cpp b/src/platform/linux/kwingrab.cpp index b6861bbfc..85245fa40 100644 --- a/src/platform/linux/kwingrab.cpp +++ b/src/platform/linux/kwingrab.cpp @@ -674,11 +674,6 @@ namespace platf { return nullptr; } - // Drop CAP_SYS_ADMIN so KWin's permission check (if active) can see and match the executable - if (!kwin::screencast_permission_helper_t::is_permission_system_deactivated() && has_elevated_privileges()) { - drop_elevated_privileges(); - } - auto display = std::make_shared(); if (display->init(hwdevice_type, display_name, config)) { return nullptr; @@ -688,7 +683,7 @@ namespace platf { } std::vector kwin_display_names() { - if (!kwin::screencast_permission_helper_t::is_permission_system_deactivated() && has_elevated_privileges()) { + if (has_elevated_privileges(false)) { // 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. std::vector display_names; diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 32eb8cbfc..59d031d08 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -1076,6 +1076,19 @@ namespace platf { } std::shared_ptr display(mem_type_e hwdevice_type, const std::string &display_name, const video::config_t &config) { + // Keep KMS as first element to check before dropping CAP_SYS_ADMIN +#ifdef SUNSHINE_BUILD_DRM + if (sources[source::KMS]) { + BOOST_LOG(info) << "Screencasting with KMS"sv; + return kms_display(hwdevice_type, display_name, config); + } +#endif + + // KMS capture was passed; drop CAP_SYS_ADMIN only. + if (has_elevated_privileges(false)) { + drop_elevated_privileges(false); + } + #ifdef SUNSHINE_BUILD_CUDA if (sources[source::NVFBC] && hwdevice_type == mem_type_e::cuda) { BOOST_LOG(info) << "Screencasting with NvFBC"sv; @@ -1088,12 +1101,6 @@ namespace platf { return wl_display(hwdevice_type, display_name, config); } #endif -#ifdef SUNSHINE_BUILD_DRM - if (sources[source::KMS]) { - BOOST_LOG(info) << "Screencasting with KMS"sv; - return kms_display(hwdevice_type, display_name, config); - } -#endif #ifdef SUNSHINE_BUILD_X11 if (sources[source::X11]) { BOOST_LOG(info) << "Screencasting with X11"sv; @@ -1261,18 +1268,22 @@ namespace platf { } #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}; + static constexpr cap_value_t FULL_CAPS[] = {CAP_SYS_ADMIN, CAP_SYS_NICE}; + static constexpr cap_value_t ADMIN_CAPS[] = {CAP_SYS_ADMIN}; + + constexpr std::span ELEVATED_PRIVILEGES_FULL {FULL_CAPS}; + constexpr std::span ELEVATED_PRIVILEGES_ADMIN {ADMIN_CAPS}; #endif - bool has_elevated_privileges() { + bool has_elevated_privileges(bool all_caps) { #if !defined(__FreeBSD__) + const auto caps_to_check = all_caps ? ELEVATED_PRIVILEGES_FULL : ELEVATED_PRIVILEGES_ADMIN; 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) { + for (const auto c : caps_to_check) { cap_flag_value_t cap_flags_value; cap_get_flag(caps, c, CAP_EFFECTIVE, &cap_flags_value); if (cap_flags_value == CAP_SET) { @@ -1280,7 +1291,7 @@ namespace platf { return true; } } - for (const auto c : ELEVATED_PRIVILEGES_PERMITTED) { + for (const auto c : caps_to_check) { cap_flag_value_t cap_flags_value; cap_get_flag(caps, c, CAP_PERMITTED, &cap_flags_value); if (cap_flags_value == CAP_SET) { @@ -1293,17 +1304,18 @@ namespace platf { return false; } - void drop_elevated_privileges() { + void drop_elevated_privileges(bool all_caps) { #if !defined(__FreeBSD__) bool failed = false; + const auto caps_to_drop = all_caps ? ELEVATED_PRIVILEGES_FULL : ELEVATED_PRIVILEGES_ADMIN; 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); + cap_set_flag(caps, CAP_EFFECTIVE, caps_to_drop.size(), caps_to_drop.data(), CAP_CLEAR); + cap_set_flag(caps, CAP_PERMITTED, caps_to_drop.size(), caps_to_drop.data(), CAP_CLEAR); if (cap_set_proc(caps) != 0) { BOOST_LOG(error) << "[misc] drop_elevated_privileges failed to prune capabilities: "sv << std::strerror(errno); diff --git a/src/platform/linux/portalgrab.cpp b/src/platform/linux/portalgrab.cpp index 2d519cd89..dfd9bc3d3 100644 --- a/src/platform/linux/portalgrab.cpp +++ b/src/platform/linux/portalgrab.cpp @@ -705,9 +705,9 @@ namespace platf { return nullptr; } - // Drop CAP_SYS_ADMIN and set DUMPABLE flag to allow XDG /root access - if (has_elevated_privileges()) { - drop_elevated_privileges(); + // Drop CAP_SYS_ADMIN, CAP_SYS_NICE and set DUMPABLE flag to allow XDG /root access + if (has_elevated_privileges(true)) { + drop_elevated_privileges(true); } auto portal = std::make_shared(); @@ -727,7 +727,7 @@ namespace platf { return {}; } - if (has_elevated_privileges()) { + if (has_elevated_privileges(true)) { // 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");