diff --git a/deploy/files/usr/local/lib/systemd/system/left4me-server@.service b/deploy/files/usr/local/lib/systemd/system/left4me-server@.service index f9148ec..db291b3 100644 --- a/deploy/files/usr/local/lib/systemd/system/left4me-server@.service +++ b/deploy/files/usr/local/lib/systemd/system/left4me-server@.service @@ -19,7 +19,13 @@ WorkingDirectory=-/var/lib/left4me/runtime/%i/merged/left4dead2 # start_instance only stages cfg files and asks systemd to enable+start # this unit; the actual `mount -t overlay` lives here so reboot auto-start # works the same as a UI-driven start. Helper is idempotent. -ExecStartPre=/usr/bin/sudo -n /usr/local/libexec/left4me/left4me-overlay mount %i +# +# `+` prefix runs the helper as PID 1 (root, no sandbox). Required because +# the unit has NoNewPrivileges=true, which blocks sudo's setuid escalation +# — and the helper itself needs root to nsenter into PID 1's mnt namespace +# anyway, so bypassing sandbox here is no looser than the sudoers rule +# the web app uses for its own helper invocations. +ExecStartPre=+/usr/local/libexec/left4me/left4me-overlay mount %i ExecStart=/var/lib/left4me/installation/srcds_run -game left4dead2 +hostport ${L4D2_PORT} $L4D2_ARGS Restart=on-failure RestartSec=5 diff --git a/deploy/tests/test_deploy_artifacts.py b/deploy/tests/test_deploy_artifacts.py index 5f2057b..efd15d5 100644 --- a/deploy/tests/test_deploy_artifacts.py +++ b/deploy/tests/test_deploy_artifacts.py @@ -88,8 +88,11 @@ def test_server_unit_mounts_overlay_via_exec_start_pre(): idempotency check (test_overlay_helper_mount_is_idempotent_when_mounted). """ unit = SERVER_UNIT.read_text() + # `+` prefix: ExecStartPre runs as PID 1 (root, no sandbox). Required + # because the unit has NoNewPrivileges=true, which blocks sudo's setuid + # escalation — and the helper needs root for nsenter anyway. assert ( - "ExecStartPre=/usr/bin/sudo -n /usr/local/libexec/left4me/left4me-overlay mount %i" + "ExecStartPre=+/usr/local/libexec/left4me/left4me-overlay mount %i" in unit ) # Bound the restart loop; without these, a CHDIR-failure (or any other