mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-08-07 10:20:46 +00:00
fix(linux/xdgportal): allow unified systemd service for all capture methods (#4854)
This commit is contained in:
@@ -19,11 +19,6 @@ IF (NOT WIN32)
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE SYSTEMD_USER_UNIT_INSTALL_DIR)
|
||||
|
||||
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
|
||||
--variable=systemd_user_preset_dir systemd
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
OUTPUT_VARIABLE SYSTEMD_USER_PRESET_INSTALL_DIR)
|
||||
|
||||
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
|
||||
--variable=systemd_system_unit_dir systemd
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
@@ -36,7 +31,6 @@ IF (NOT WIN32)
|
||||
|
||||
mark_as_advanced(
|
||||
SYSTEMD_USER_UNIT_INSTALL_DIR
|
||||
SYSTEMD_USER_PRESET_INSTALL_DIR
|
||||
SYSTEMD_SYSTEM_UNIT_INSTALL_DIR
|
||||
SYSTEMD_MODULES_LOAD_DIR
|
||||
)
|
||||
|
||||
@@ -18,10 +18,6 @@ if(${SUNSHINE_BUILD_APPIMAGE} OR ${SUNSHINE_BUILD_FLATPAK})
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}/modules-load.d")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/app-${PROJECT_FQDN}.service"
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service"
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/00-app-${PROJECT_FQDN}.preset"
|
||||
DESTINATION "${SUNSHINE_ASSETS_DIR}/systemd/user-preset")
|
||||
else()
|
||||
find_package(Systemd)
|
||||
find_package(Udev)
|
||||
@@ -33,10 +29,6 @@ else()
|
||||
if(SYSTEMD_FOUND)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/app-${PROJECT_FQDN}.service"
|
||||
DESTINATION "${SYSTEMD_USER_UNIT_INSTALL_DIR}")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service"
|
||||
DESTINATION "${SYSTEMD_USER_UNIT_INSTALL_DIR}")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/00-app-${PROJECT_FQDN}.preset"
|
||||
DESTINATION "${SYSTEMD_USER_PRESET_INSTALL_DIR}")
|
||||
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/60-sunshine.conf"
|
||||
DESTINATION "${SYSTEMD_MODULES_LOAD_DIR}")
|
||||
endif()
|
||||
|
||||
@@ -25,8 +25,6 @@ elseif(UNIX)
|
||||
|
||||
# configure service
|
||||
configure_file(packaging/linux/app-${PROJECT_FQDN}.service.in app-${PROJECT_FQDN}.service @ONLY)
|
||||
configure_file(packaging/linux/sunshine.service.in sunshine.service @ONLY)
|
||||
configure_file(packaging/linux/00-app-${PROJECT_FQDN}.preset.in 00-app-${PROJECT_FQDN}.preset @ONLY)
|
||||
|
||||
# configure the arch linux pkgbuild
|
||||
if(${SUNSHINE_CONFIGURE_PKGBUILD})
|
||||
|
||||
@@ -447,21 +447,20 @@ After adding yourself to the group, log out and log back in for the changes to t
|
||||
|
||||
#### Services
|
||||
|
||||
> [!NOTE]
|
||||
> Two service unit files are available. Pick "app-dev.lizardbyte.app.Sunshine" for unprivileged XDG Portal
|
||||
> or X11 capture, otherwise pick "sunshine" for privileged KMS capture.
|
||||
|
||||
**Start once**
|
||||
```bash
|
||||
systemctl --user start sunshine
|
||||
systemctl --user start app-dev.lizardbyte.app.Sunshine
|
||||
```
|
||||
|
||||
**Start on boot (privileged; swap names for unprivileged XDG capture)**
|
||||
**Start on boot**
|
||||
```bash
|
||||
systemctl --user --now disable app-dev.lizardbyte.app.Sunshine
|
||||
systemctl --user --now enable sunshine
|
||||
systemctl --user --now enable app-dev.lizardbyte.app.Sunshine
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The service has been renamed to "app-dev.lizardbyte.app.Sunshine" in order to increase compatibility with
|
||||
> XDG Desktop Portal, but it is also aliased to "sunshine.service" for convenience.
|
||||
|
||||
### macOS
|
||||
The first time you start Sunshine, you will be asked to grant access to screen recording and your microphone.
|
||||
|
||||
|
||||
+10
-7
@@ -160,18 +160,21 @@ sudo usermod -aG input $USER
|
||||
```
|
||||
|
||||
### KMS Streaming fails
|
||||
If screencasting fails with KMS, you may be using the unprivileged app-dev.lizardbyte.app.Sunshine service unit.
|
||||
Switch to the privileged sunshine service:
|
||||
KMS screencasting requires elevated privileges which are not allowed for Flatpak or AppImage packages.
|
||||
This means that you must install Sunshine using the native package format of your distribution, if available.
|
||||
KMS capture will soon be phased out in favour of XDG Portal Capture (which works with all package types).
|
||||
|
||||
### KMS Streaming; some windows flicker/disappear on KDE Plasma 6.5+
|
||||
KWin's overlay support interferes with KMS capture. As of KWin 6.5 this is not yet set by default, but
|
||||
for future versions that enables this by default, you may be able to disable again via a special
|
||||
[environment variable](https://invent.kde.org/plasma/kwin/-/wikis/Environment-Variables#kwin_use_overlays):
|
||||
|
||||
```bash
|
||||
systemctl --user --now disable app-dev.lizardbyte.app.Sunshine
|
||||
systemctl --user --now enable sunshine
|
||||
export KWIN_USE_OVERLAYS=0
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> The above commands will not work with the AppImage or Flatpak packages, as KMS screencasting
|
||||
> requires elevated privileges which are not allowed by their respective packaging security policies.
|
||||
> As an alternative, XDG Portal capture is recommended.
|
||||
> Disabling overlays will reduce KWin's rendering efficiency. Consider using XDG Portal Capture instead.
|
||||
|
||||
### KMS streaming fails on Nvidia GPUs
|
||||
If KMS screen capture results in a black screen being streamed, you may need to
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# @PROJECT_DESCRIPTION@
|
||||
# The unprivileged service should preset to disabled
|
||||
|
||||
disable app-@PROJECT_FQDN@.service
|
||||
@@ -2,7 +2,6 @@
|
||||
Description=@PROJECT_DESCRIPTION@
|
||||
StartLimitIntervalSec=500
|
||||
StartLimitBurst=5
|
||||
Conflicts=sunshine.service
|
||||
After=graphical-session.target xdg-desktop-autostart.target xdg-desktop-portal.service
|
||||
|
||||
[Service]
|
||||
@@ -12,7 +11,7 @@ ExecStartPre=/bin/sleep 5
|
||||
@SUNSHINE_SERVICE_STOP_COMMAND@
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
Alias=sunshine.service
|
||||
|
||||
@@ -390,9 +390,8 @@ fi
|
||||
%caps(cap_sys_admin+p) %{_bindir}/sunshine
|
||||
%caps(cap_sys_admin+p) %{_bindir}/sunshine-*
|
||||
|
||||
# Systemd unit/preset files for user services
|
||||
# Systemd unit files for user services
|
||||
%{_userunitdir}/*.service
|
||||
%{_userpresetdir}/*.preset
|
||||
|
||||
# Udev rules
|
||||
%{_udevrulesdir}/*-sunshine.rules
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
[Unit]
|
||||
Description=@PROJECT_DESCRIPTION@
|
||||
StartLimitIntervalSec=500
|
||||
StartLimitBurst=5
|
||||
Conflicts=app-@PROJECT_FQDN@.service
|
||||
After=graphical-session.target xdg-desktop-autostart.target
|
||||
|
||||
[Service]
|
||||
# Avoid starting Sunshine before the desktop is fully initialized.
|
||||
ExecStartPre=/bin/sleep 5
|
||||
@SUNSHINE_SERVICE_START_COMMAND@
|
||||
@SUNSHINE_SERVICE_STOP_COMMAND@
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
@@ -1684,17 +1684,6 @@ namespace platf {
|
||||
#if defined(SUNSHINE_BUILD_FLATPAK) || defined(SUNSHINE_BUILD_APPIMAGE)
|
||||
BOOST_LOG((config::video.capture == "kms") ? fatal : error)
|
||||
<< "AppImage and Flatpak do not support KMS capture. Use another capture method."sv;
|
||||
#else
|
||||
{
|
||||
const std::string kms_msg =
|
||||
"You must use the 'sunshine' service instead of the 'app-" +
|
||||
std::string(PROJECT_FQDN) +
|
||||
"' service for KMS capture.\n"
|
||||
"Please refer to the official documentation:\n"
|
||||
" stable: https://docs.lizardbyte.dev/projects/sunshine/latest/md_docs_2getting__started.html#linux-1\n"
|
||||
" beta: https://docs.lizardbyte.dev/projects/sunshine/master/md_docs_2getting__started.html#linux-1";
|
||||
BOOST_LOG((config::video.capture == "kms") ? fatal : error) << kms_msg;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,12 @@
|
||||
#include "vaapi.h"
|
||||
#include "wayland.h"
|
||||
|
||||
#if !defined(__FreeBSD__)
|
||||
// platform includes
|
||||
#include <sys/capability.h>
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
// Buffer and limit constants
|
||||
constexpr int SPA_POD_BUFFER_SIZE = 4096;
|
||||
@@ -223,12 +229,43 @@ namespace portal {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void finalize_portal_security() {
|
||||
#if !defined(__FreeBSD__)
|
||||
BOOST_LOG(debug) << "Finalizing Portal security: dropping CAP_SYS_ADMIN and resetting dumpable"sv;
|
||||
|
||||
cap_t caps = cap_get_proc();
|
||||
if (!caps) {
|
||||
BOOST_LOG(error) << "Failed to get process capabilities"sv;
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<cap_value_t, 1> remove_list {CAP_SYS_ADMIN};
|
||||
|
||||
cap_set_flag(caps, CAP_PERMITTED, remove_list.size(), remove_list.data(), CAP_CLEAR);
|
||||
cap_set_flag(caps, CAP_EFFECTIVE, remove_list.size(), remove_list.data(), CAP_CLEAR);
|
||||
|
||||
if (cap_set_proc(caps) != 0) {
|
||||
BOOST_LOG(error) << "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) << "Failed to set PR_SET_DUMPABLE: "sv << std::strerror(errno);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int connect_to_portal() {
|
||||
g_autoptr(GMainLoop) loop = g_main_loop_new(nullptr, FALSE);
|
||||
g_autofree gchar *session_path = nullptr;
|
||||
g_autofree gchar *session_token = nullptr;
|
||||
create_session_path(conn, nullptr, &session_token);
|
||||
|
||||
// Drop CAP_SYS_ADMIN and set DUMPABLE flag to allow XDG /root access
|
||||
finalize_portal_security();
|
||||
|
||||
// Try combined RemoteDesktop + ScreenCast session first
|
||||
bool use_screencast_only = !try_remote_desktop_session(loop, &session_path, session_token);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user