# 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): - `7c64910` — `spec(hardening-refactor): resolve emitter open items` (verified ckn-bw systemd-bundle emitter handles tuples + empty values) - `8e678b6` — `deploy/files: annotate reference units with per-directive hardening comments` - `37309ba` — `spec(hardening-test-plan): fix four bugs surfaced by executor` - `f615d0d` — `spec(user-uid-split): mark superseded by the hardening refactor` **ckn-bw commits** (this session, in order; all on `master`, pushed): - `85b9af0` — `bundles/left4me: add HARDENING_{COMMON,SERVER,WEB} constants` - `640461c` — `bundles/left4me: spread HARDENING_SERVER into left4me-server@.service` - `c6721e7` — `bundles/left4me: spread HARDENING_WEB into left4me-web.service` - `130b0b1` — `bundles/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.env` → `No such file or directory` - **D1.c — srcds sees /opt**: empty listing - **D2.b — srcds sees gunicorn PID via /proc**: `cannot access /proc/` (PrivatePIDs in effect; PID doesn't exist in the namespace) - **D5 — cross-instance ptrace**: `cannot access /proc/` (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/`