left4me/docs/superpowers/specs/2026-05-15-session-handoff.md
mwiegand f5f8db84ef
spec(session-handoff): hardening refactor landed and verified on left4.me
12-task subagent-driven refactor complete. left4me-server@1: 7.5 → 1.3
systemd-analyze. left4me-web: 8.7 → 4.1. All 6 Test 8 attack vectors
blocked post-deploy. One acceptable SECCOMP audit line per gameserver
restart (Breakpad's ptrace fork, blocked by design). Test tooling
(gdb, seccomp, libseccomp-dev) apt-removed from left4.me. uid-split
spec marked superseded.

No queued follow-up. Adjacent work: build-overlay-unit refactor and
the deferred drop-in / configmgmt-responsibility reshape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 15:17:06 +02:00

6 KiB

Session handoff — hardening refactor landed

The hardening refactor planned at docs/superpowers/plans/2026-05-15-hardening-refactor.md is deployed to left4.me and verified. This session executed all 12 tasks subagent-driven; no follow-up implementation work is queued.

What landed

left4me commits (this session, in order; all on master, pushed):

  • 7c64910spec(hardening-refactor): resolve emitter open items (verified ckn-bw systemd-bundle emitter handles tuples + empty values)
  • 8e678b6deploy/files: annotate reference units with per-directive hardening comments
  • 37309baspec(hardening-test-plan): fix four bugs surfaced by executor
  • f615d0dspec(user-uid-split): mark superseded by the hardening refactor

ckn-bw commits (this session, in order; all on master, pushed):

  • 85b9af0bundles/left4me: add HARDENING_{COMMON,SERVER,WEB} constants
  • 640461cbundles/left4me: spread HARDENING_SERVER into left4me-server@.service
  • c6721e7bundles/left4me: spread HARDENING_WEB into left4me-web.service
  • 130b0b1bundles/left4me: ship kernel.yama.ptrace_scope=2 sysctl drop-in

Deploy: bw apply ovh.left4me ran clean in 10 s (194 OK, 4 fixed, 0 failed). left4me-web.service restarted automatically by bw; left4me-server@1 and @2 restarted manually post-apply.

What's live on left4.me

Unit systemd-analyze score State
left4me-server@1.service 1.3 OK (was 7.5 baseline) active since 13:13:39 UTC
left4me-server@2.service 1.3 OK active since 13:14:40 UTC
left4me-web.service 4.1 OK (was 8.7 baseline) active since 13:01:06 UTC

Sysctl: kernel.yama.ptrace_scope = 2 (managed by ckn-bw bundle now, not hand-applied).

Composition matches Test 7 of the test plan with two amendments (SystemCallArchitectures=native x86, PrivatePIDs=true) and one addition (SocketBindAllow=udp:27000-27999 tcp:27000-27999). MemoryDenyWriteExecute=true permanently excluded.

Attack vectors blocked (Test 8 subset rerun post-deploy)

  • D1.a — srcds reads DB: cat /var/lib/left4me/left4me.db from inside the unit's mount namespace → No such file or directory
  • D1.b — srcds reads web.env: cat /etc/left4me/web.envNo such file or directory
  • D1.c — srcds sees /opt: empty listing
  • D2.b — srcds sees gunicorn PID via /proc: cannot access /proc/<pid> (PrivatePIDs in effect; PID doesn't exist in the namespace)
  • D5 — cross-instance ptrace: cannot access /proc/<peer-srcds-pid> (cross-instance PID isolation)
  • Syscall filter compiled correctly: ptrace and process_vm_* not in the compiled allow list (verified via systemd-analyze syscall-filter)

Known acceptable noise

  • One SECCOMP audit line per gameserver restart (type=1326, i386 syscall 26 = ptrace, sig=31 SIGSYS, code=0x80000000 SECCOMP_RET_KILL_PROCESS). Source: srcds's Breakpad crash-reporter init forks a child that attempts ptrace; we block it by design. The child gets killed; the main srcds process is unaffected. Net effect: Valve doesn't get crash minidumps from this host. Acceptable trade-off given the threat model. If the audit-log noise becomes a problem, switch the SECCOMP filter's action from KILL_PROCESS to EPERM via SystemCallErrorNumber=EPERM (would let breakpad fail cleanly instead of getting killed; same security outcome).

Host cleanup done

gdb, libseccomp-dev, seccomp removed via apt remove --purge. Test tooling was installed during the test-plan execution session (commit 461b8d0); not needed in steady state. ~13 MB freed.

What's next

No queued follow-up from this work. Adjacent open work:

  • build-overlay-unit refactor (docs/superpowers/specs/2026-05-15-build-overlay-unit-design.md). Will reuse HARDENING_COMMON (or a sandbox-class variant) when it lands. Sequenced after this; not blocked.
  • Broader configmgmt-responsibility reshape — hardening as drop-in files living in left4me with ckn-bw as a thin file-shipper. Real direction, deliberately deferred to a dedicated session in this refactor's design doc.
  • Stale RCON port app bug flagged in the prior executor's handoff. Not a hardening issue; separate scope.

Open items the operator should sanity-check manually

I executed everything programmatically that I could. The following need an eyeballed check via the web UI from your laptop:

  1. Login to the web UI; confirm session works (would catch a SECRET_KEY regression or session-cookie issue).
  2. Start/stop a server from the UI (exercises the sudo path on the web unit; if the SystemCallFilter or any other web hardening broke sudo, this would fail).
  3. View live logs for a server (uses sudo left4me-journalctl).
  4. Trigger an overlay rebuild for a script overlay (exercises the sandbox; unchanged by this refactor, but a smoke against the full chain).

If any of those break, the most likely cause is the web unit's SystemCallFilter. Drop-in override at /etc/systemd/system/left4me-web.service.d/00-debug.conf with SystemCallLog=... instead of SystemCallFilter to identify the offending syscall, then narrow the filter.

Pointers

  • Threat model: docs/superpowers/specs/2026-05-15-hardening-threat-model.md
  • Defenses survey: docs/superpowers/specs/2026-05-15-hardening-defenses-survey.md
  • Test plan (with executor results + this session's bug fixes): docs/superpowers/specs/2026-05-15-hardening-test-plan.md
  • Design doc: docs/superpowers/specs/2026-05-15-hardening-refactor-design.md
  • Implementation plan: docs/superpowers/plans/2026-05-15-hardening-refactor.md
  • uid-split spec (marked superseded): docs/superpowers/specs/2026-05-15-user-uid-split-design.md
  • Live unit emission: ~/Projekte/ckn-bw/bundles/left4me/metadata.py (HARDENING_COMMON etc. near top; spreads at the left4me-server@.service and left4me-web.service entries)
  • Reference units (annotated): deploy/files/usr/local/lib/systemd/system/