Files
felhom.eu/documentation/audits/security-lane-2026-10-23/README.md
T

75 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# D39 = B — the security-fix lane, built and proven (2026-10-23)
Decision: `architecture/09-update-architecture.md` §3 decision 255 (the operator started the D39 brief ~12:00; R-1239
closed). Read before the work: `09` §3 decisions 13–17, 22, 25–26, 52 and §6.4 parts 4–7; `00-capability-map.md` (the
B rows); `13-threat-model.md`; `runbooks/target-selection.md`; `runbooks/publish-train-rules.md`.
Baselines at start: catalog `cde26ab`, controller `32e61d5` (0.340.0, global floor 06:41 UTC — read from the hub before
the first controller commit), felhom.eu `4b9b0af3`. Machines: DooPlex (builds, the writer), demo-hp (9202 scratch; the
release on 9201), Tester 1, demo-felhom (release only). Not touched: ep0, any household box.
## Venue
9202 was pointed at the drill catalog through its LOCAL mirror (`tools/repoint.py`, copied from
`audits/burndown-3-2026-10-17/tools/`, R-992 — no catalog credential on the box): `repoint-drill.txt`. The drill was
reset to live `main` (`cde26ab`) first. 9202's dashboard password is its own (`REHEARSAL_2026_10_20_9202_PW`; the
demo-hp one was refused — five failed logins hit the one-minute limit; `operations/nodes.md` corrected).
## Part 2 — the lane on the old controller (9202 on 0.340.0)
| Step | Result | File |
|---|---|---|
| First try of the negative control | `inconclusive` — the install was refused before anything was made (Plex wants the drive itself as `HDD_PATH`); the walk gained `--value` | `P2-negative-try1-install-refused/` |
| **Negative control**: FROM Plex 1.43.4.10903, TO `busybox:1.36.1` (exits at once) | **`failed`** — backing-up → … → verifying → undoing → **undone** after 335 s; Plex 1.43.4 back | `P2-negative/walk.txt`, `box-verdict-plex.json` |
| The writer on that walk | **refused**: „the box walk is 'security' with verdict 'failed' — only a PROVEN `box_walk.py --security` walk is written" | `P2-negative/writer-refusal.txt` |
| **The walk**: Plex 1.43.4.10903-e5521bd8c → 1.43.5.11029-6bf8af3f0 | **`proven`** — done in 36.9 s, no undo, no hold; pinned = installed = catalog = live compose = running = TO; digest `sha256:01bdf0ad6d53198da4331540c1e73ab65db7a72e961fff97ecb0847d46055c5f` (the registry's, re-read by the writer); soak 600 s, 60 samples, anon peak 10.7 % of 2 GiB (cgroup peak 11.5 %), 0 OOM kills, 0 restarts; `seed: none` (Plex's fixture is a `NoRoute` stub) | `P2-walk/` |
| Setup gate (unclaimed Plex) | a browser (`Accept: text/html`) → 302 to `felhom.<domain>/__gate/start`; a script → 401; the same after the update | `P2-walk/box-verdict-plex.json` |
| The writer, into the DRILL only | wrote the `security_fix` entry: ids CVE-2026-96652/-96654/-96655/-96656; advisory Plex's notice `https://forums.plex.tv/t/important-security-update-for-plex-media-server-v1-43-2-and-earlier/942319` (the one CISA KEV cites, all four added 2026-10-20 — `cisa-kev-plex2shell.json`, from CISA's own feed); `fixed_in` 1.43.3.10861; the gate accepts it with its WARN | `P2-walk/writer.txt`; drill `f46e1bc` |
| Old controller, night (`POST /api/debug/backup/night-chain`) | **`[update-leg] plex: skipped — not_proven`**; Plex stays 1.43.4 (control: the same leg judged privatebin) | `P2-oldctl/2-night-chain-0.340.0.txt` |
| Old controller, hand press | **done** in 25.7 s; Plex 1.43.5 at the step's digest; `/identity` 200 with 1.43.5 | `P2-oldctl/3-hand-press-0.340.0.txt` |
**How Plex was put back at 1.43.4 for Part 3:** removed through the product (with its data); drill commit `42945c9`
moved ONLY the compose's image line back to 1.43.4 (the ladder line untouched); a fresh install pinned 1.43.4; `17e0da0`
reverted that commit, so the step is the head again and the badge read „Frissítés elérhető" (`P3-newctl/0-…`).
## Part 3 — the new controller (0.341.0-rc.1 on 9202)
Controller `63dcccf` (CI run 2264 / #471 success), image `0.341.0-rc.1` set by hand (9202's self-update is off). The
night chain: `[update-leg] plex: step pressed …`, **`[update-leg] plex: security fix
CVE-2026-96652,CVE-2026-96654,CVE-2026-96655,CVE-2026-96656 taken (plex=…1.43.4… → plex=…1.43.5…)`**, `step ended done
after 30.1 s`; the summary line ends `[security fix plex: … done]`. Backup first: the update's precondition met by a
second-drive copy 0 s old, the undo copy of 2 named volumes (2.8 MiB), then the pin. `/identity` 200 with 1.43.5
(`P3-newctl/1-…`, `2-…`).
## Part 4 — release 0.341.0
Image `0.341.0` (`sha256:8aa4ce60…c0bc`) from `63dcccf`; per-box floors on tester-1, demo-hp, demo-felhom (303
`floor_set`); all three ran 0.341.0 by 11:15:31 UTC. Box walk: 0 unhealthy, 0 restarting, 0 exited, 0 `[ERROR]` lines since
the start (126 / 135 / 141 `[INFO]` lines — the control); selfupdate „0.341.0 is up to date"; the https-only check passes
on every public name; the dashboard login works on demo-hp and Tester 1 (`/api/stacks` 200), the N100's `/api/health`
200 (`P4-release/`). **The operator said yes in chat; the global floor 0.341.0 / MinAgent 0.158.1 was set at 11:24:47
UTC** (303 `floor_set`; the running hub's page reads „Effective floor: v0.341.0 — source: DB"); the per-box floors
cleared.
## Teardown (three layers)
- **Machine (9202):** Plex removed through the product (no plex container or volume left); `controller.yaml` restored
byte-identical (`cmp`) and the catalog cache re-cloned from the live catalog (R-615); this run's saved copy deleted
after the `cmp`; image `0.341.0`. 34 older saved copies from earlier sessions stay — filed R-1240. The drill
repository keeps this run's commits as the record.
- **Host (demo-hp):** nothing provisioned.
- **Hub:** the global floor 0.341.0 (the operator's yes); per-box floors cleared.
## Observations
- FILED: R-1240 — 9202 holds 34 saved `controller.yaml` copies with the catalog token.
- FIXED without a row: drill commits never reached a box pointed at the drill's local mirror (`box_walk.refresh_box_mirror`);
two stale catalog tests (9202 address, gate count + missing sibling in the shallow clone); Tester 1's guest moved
`.101` → `.148` and the box walk had it typed (now read from the guest); `operations/nodes.md` (9202's password,
Tester 1's address).
- NOT-A-FINDING: the writer's own engine-major check is redundant with `check_entry` (two layers on purpose; the test
asserts the refusal); `/opt/docker/stacks/plex` keeps the catalog's template files after a removal, as every catalog
app's folder does (72); the demo-hp start WARNs „new field … requires manual configuration" come from code 0.341.0 did
not change; a waiter of mine matched its own command line (a known trap, memory `pgrep-waiter-matches-itself`) and
was stopped.