journal(redfix): wake #19 — consumed review(redfix)@2ad38f5 (re-confirmation #17); my B-redfix-7 severity rationale was wrong on the axis ("no non-root login users" — but mode 644 lets any uid read; setpriv --reuid=1000 succeeds). Re-derived the correct containment first-hand rather than inheriting it: mount-namespace isolation (only dbus-daemon uid 4 shares pid1's mnt-ns; the uid-1000 warm-keycloak JVM is in ns 4026533305 and cannot see host /etc). Same LOW severity, different load-bearing reason — and a fragile one, so the case to fix strengthens. Corrected the bullet, cross-ref A-redfix-1; no verdict change, DONE stands, loop remains stopped

This commit is contained in:
2026-07-09 01:54:14 +00:00
parent 2ad38f507b
commit e64d8e7441
2 changed files with 52 additions and 4 deletions

View File

@ -87,10 +87,19 @@ hold). Concrete fix designs from M1 evidence:
- `/etc/cc-ci/.git/config` is mode **644** `root:root` and its `origin` URL embeds
`https://autonomic-bot:<password>@git.autonomic.zone/...` — the bot's Gitea credential at rest in
cleartext. (Value deliberately not reproduced here.)
- **Severity is LOW, not nil:** `awk` over `/etc/passwd` shows **no non-root login users** (no uid>=1000
with a real shell), so today only root can read it. It is defence-in-depth that is missing, not a live
compromise. It would become real the moment any unprivileged user or a container bind-mounting `/etc`
exists.
- **Severity is LOW, not nil — but my first rationale for that was WRONG** (corrected wake #19 after
Adversary re-confirmation #17; filed Adversary-side as **A-redfix-1**). I originally argued "no
non-root *login* users, so only root can read it." That is the wrong axis: a process needs no login
shell to run as uid 1000, and mode 644 permits **any** uid to read. Verified directly —
`setpriv --reuid=1000 … /etc/cc-ci/.git/config` **succeeds** in the host namespace.
- **What actually contains the blast radius is mount-namespace isolation**, re-derived first-hand:
exactly ONE non-root process shares pid1's mount ns (`dbus-daemon`, uid 4). Every other non-root
process is containerized — notably the uid-1000 Quarkus `java` that IS the internet-facing
warm-keycloak: its `ns/mnt` is `4026533305` vs pid1's `4026531841`, and
`ls /proc/<pid>/root/etc/cc-ci`**No such file or directory**. Mode-permits ≠ reachable.
- **Therefore the containment is load-bearing on a fragile property** and dies silently if a non-root
host-namespace daemon ever appears, or if `/etc` is bind-mounted into any container. That fragility —
not the current reachability — is the reason to fix it.
- `/etc/cc-ci` is a **real directory, not a `/nix/store` symlink**, and **no systemd unit references
it** — i.e. undeclared, unmanaged server state that nothing runs from. It violates the standing
"keep server state Nix-declared and reversible" rule.

View File

@ -1176,3 +1176,42 @@ fixed and verified.
Node untouched: every command this wake was read-only (`git -C … rev-parse/cat-file/symbolic-ref`, `stat`,
`awk`, `readlink`). Nothing claimed. DONE stands.
## Wake #19 — 2026-07-09T02:08Z — consumed review(redfix)@14c7dee (re-confirmation #17); my B-redfix-7 severity rationale was WRONG on the axis; corrected after re-deriving the Adversary's replacement
Consumed re-confirmation #17 (`14c7dee`). It accepted my `/etc/cc-ci` correction (after re-deriving it
rather than taking it on trust), confirmed B-redfix-7 as real + LOW, filed it Adversary-side as
**A-redfix-1** — and **corrected my reasoning**, which was wrong. No finding, no VETO, DONE stands, loop
stays stopped.
**Where I was wrong.** I justified "severity LOW" with *"no non-root login users, so only root can read it."*
That reasons about the wrong thing. A process does not need a login shell to run as uid 1000, and mode 644
lets any uid read the file regardless. I did not accept the Adversary's replacement on trust either — the
whole point of this exchange is that neither of us inherits a fact. Re-derived all three legs myself:
setpriv --reuid=1000 --clear-groups … /etc/cc-ci/.git/config → SUCCEEDS ⇒ my premise was false
non-root procs sharing pid1's mnt-ns (4026531841) → exactly 1: dbus-daemon, uid 4
uid-1000 quarkus java (the live warm-keycloak), pid 2327794 → mnt-ns 4026533305 ≠ host
ls /proc/2327794/root/etc/cc-ci → No such file or directory
So the credential is contained by **mount-namespace isolation**, not by the absence of login accounts. Same
LOW verdict, entirely different load-bearing reason. Rewrote the B-redfix-7 severity bullet accordingly and
cross-referenced A-redfix-1; the remedy ladder is unchanged.
**Why the distinction matters rather than being pedantry.** "No non-root users" reads as a static fact about
the box. Mount-namespace containment is a *fragile* property: it evaporates the moment a non-root host-ns
daemon appears, or `/etc` is bind-mounted into any container. My wrong rationale would have made the risk
look permanently dormant; the true one shows it is one config change away from live. That is now the stated
reason to fix it, and it strengthens rather than weakens the case for the operator to act.
Also noted: the Adversary recorded a near-miss against itself — its `setpriv` probe ran in the *host* ns, so
it nearly concluded "internet-facing Keycloak can exfiltrate the bot credential," which is false. Its own
tally is that two of its last three probes gave plausible answers for invalid reasons, both caught by
re-running the probe against the thing it claimed to measure rather than by re-checking the conclusion. Mine
this wake was the same class of error, caught the same way. Worth carrying forward: verifying a *conclusion*
is nearly worthless; verifying that the *probe measures what it purports to* is what catches these.
Scope unchanged: A-redfix-1 / B-redfix-7 is pre-existing infra state, touches no DoD item, and the credential
is a Class-A1 external input — the operator's to rotate. **The phase is not reopened.** All commands this
wake were read-only (`readlink`, `pgrep`, `ls /proc/…`, and a zero-byte `head -c 0` for the mode check).
Nothing claimed. DONE stands.