Skip to content
Merged
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
10 changes: 6 additions & 4 deletions src/platform/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
7 changes: 1 addition & 6 deletions src/platform/linux/kwingrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<kwin::kwin_t>();
if (display->init(hwdevice_type, display_name, config)) {
return nullptr;
Expand All @@ -688,7 +683,7 @@ namespace platf {
}

std::vector<std::string> 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<std::string> display_names;
Expand Down
40 changes: 26 additions & 14 deletions src/platform/linux/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,19 @@ namespace platf {
}

std::shared_ptr<display_t> 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;
Expand All @@ -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;
Expand Down Expand Up @@ -1261,26 +1268,30 @@ namespace platf {
}

#if !defined(__FreeBSD__)
constexpr std::array<cap_value_t, 2> ELEVATED_PRIVILEGES_EFFECTIVE {CAP_SYS_ADMIN, CAP_SYS_NICE};
constexpr std::array<cap_value_t, 2> 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<const cap_value_t> ELEVATED_PRIVILEGES_FULL {FULL_CAPS};
constexpr std::span<const cap_value_t> 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) {
BOOST_LOG(debug) << "[misc] has_elevated_privileges found effective cap:"sv << c;
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) {
Expand All @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions src/platform/linux/portalgrab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<portal::portal_t>();
Expand All @@ -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");
Expand Down
Loading