From a982995d5b24bf9a09ffc616508dff7844908758 Mon Sep 17 00:00:00 2001 From: mwiegand Date: Sat, 9 May 2026 12:55:16 +0200 Subject: [PATCH] fix(deploy): ExecStartPre runs overlay helper with `+` prefix, not sudo The unit has NoNewPrivileges=true (security hardening for srcds), which blocks sudo's setuid escalation. The previous sudo'd ExecStartPre failed on every start with "sudo: the 'no new privileges' switch is set, which prevents sudo from running as root" -> Restart=on-failure loop. systemd's `+` prefix runs the Exec command as PID 1 (root, no sandbox), bypassing User=/Group=/NoNewPrivileges=. Equivalent privilege scope to the sudoers rule the web app already uses for the same helper, just without the sudo middleman. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../usr/local/lib/systemd/system/left4me-server@.service | 8 +++++++- deploy/tests/test_deploy_artifacts.py | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) 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