The claim that made the defect invisible, replaced by a mechanism.
Written on top of 7961233 (D.1.3c·2c·1c Phase B partial) and bc21b16 (C1.0b·2·2, FINAL-FROZEN, not reopened here).
host/src/carrier.rs's module header said, of the Carrier's four-descriptor table:
Everything the host holds is
SOCK_CLOEXECorO_CLOEXECby construction, so the allowlist is enforced by the kernel atexecrather than by a loop that must remember to run.
That is true of super-host, which opens almost nothing. It is a claim about a binary wearing the clothes of a claim about the host role, and it is false for any process that links super_host alongside anything else. The first one that did — the cockpit, a Tauri/GTK/WebKit process — could not start a Carrier at all: the floor refused observed:descriptor_set_exact, correctly, and 284 host checks and 45 sabotage probes had never been able to see it, because there had only ever been one host and it was the small one.
The new claim is about the spawn path:
A Carrier's inherited descriptor set is established by the Carrier spawn path itself and does not depend on unrelated descriptor hygiene in the parent executable. Everything above the base is marked for death before anything is placed; the Carrier's possessions are then rescued, one
dup_ontoat a time;execcloses the rest.
host/src/fdpass.rs — `seal_inheritance(first)`, one raw syscall:
close_range(4, UINT_MAX, CLOSE_RANGE_CLOEXEC) 436 / flag 1<<2
host/src/carrier.rs — called from pre_exec, after ensure_std_fds() and before any descriptor placement:
ensure_std_fds() 0/1/2 exist
seal_inheritance(4) every fd >= 4 marked close-on-exec
setsid / TIOCSCTTY the terminal relationship, if there is one
dup_onto(slave, 0/1/2) ─┐
dup_onto(control, 3) ├ the Carrier's possessions, rescued by name
dup_onto(extra…) ─┘ (`dup_onto` clears CLOEXEC on its target)
prepared.install() Landlock + seccomp, the ruleset still live
execve the kernel closes everything unrescued
Prepared's Landlock ruleset lives at or above fd 64 and must still be a
live descriptor when install runs, after the seal. A blind close_range(4, ~0, 0) closes it; landlock_restrict_self gets EBADF; install fails inside pre_exec. Measured under sabotage: the spawn does not happen at all, so the failure is loud rather than an unconfined Carrier — but only because install checks. Nothing about a blind sweep is safe.
The PTY slave, the control channel and every extra_fds source are
read by dup_onto after the seal. Closing them makes the Carrier's own possessions unreachable.
std::process::Command keeps a CLOEXEC pipe open across the fork and
detects successful exec by that pipe closing. A blind sweep closes it, and a pre_exec that then fails reports nothing to the parent — the sweep would break the reporting of its own breakage.
seal_inheritance propagates its error out of pre_exec and the spawn fails. There is no "sealing unavailable, continue anyway" branch. A Carrier whose descriptor table cannot be bounded does not start.
confine::RULESET_FD_FLOOR (64) is pub, and spawn_with refuses any extra_fds target < 0 or >= RULESET_FD_FLOOR before any placement happens. That constant's own docs already said the ruleset "sits above every number the Carrier's descriptor allowlist can name"; nothing enforced it, and extra_fds names its own target. Every falsifier that exists uses fd 9 or fd 0 and all of them stay legal.
super-host verify, 284 → 290)| check | what it refuses |
|---|---|
| the ambient-descriptor probe really is ambient — open, above 3, and NOT close-on-exec | a green result for not having set up the condition |
| an ambient inheritable descriptor the host never named does NOT reach the Carrier | the defect itself |
| an explicitly placed descriptor survives, at its target and nowhere else | a repair that sanitises indiscriminately and destroys the pre-open falsifier |
a possession placed on its OWN number survives — dup2(n, n) is a no-op | simplifying dup_onto to a bare dup2 |
| the ruleset survives the seal — still REFUSED a path the bare control reached | closing the thing that enforces the policy |
| an extra descriptor target at the reserved ruleset floor is refused before placement | overwriting the live ruleset from the vocabulary |
They run after the harness's own leak, deliberately. The comment they sit under recorded this exact defect and called it a harness bug:
Measured while writing this: the first version of this check ran AFTER the leak was set up and went red, because the harness's own leaked descriptor reached the Carrier. The check was correct; the thing it caught was the test.
It was not the test. The control was moved earlier and the floor kept its false claim for a revision. The whole property now is that the order does not matter.
The ruleset-survival check first asked /proc/<pid>/status for a Landlock: line and went red on a correctly confined Carrier. This kernel does not publish that field — 7.2.2, CONFIG_SECURITY_LANDLOCK=y, ABI 10, and no such line in /proc/self/status — so observe's landlock_domain is false for every process on this host and always has been. That is why nothing else in verify.rs reads it, and carrier.rs says why beside where the field is computed: Landlock is host-attested, and the differential battery is the out-of-band proof. The check is now a differential.
| probe | expected RED |
|---|---|
| a Carrier spawned without the inheritance seal is noticed | does NOT reach the Carrier |
| a seal that CLOSES instead of marking is noticed | still REFUSED a path the bare control reached |
a dup_onto that trusts dup2 to clear CLOEXEC is noticed | placed on its OWN number survives |
| an extra descriptor target that can overwrite the ruleset is noticed | refused before placement |
All four falsified. Probe 46 reproduces the original finding exactly: without the seal, the Carrier observed [0, 1, 2, 3, 8] — fd 8 being the harness's own ambient descriptor.
SUPER_COCKPIT_CARRIER=1 runs the full production chain inside the real cockpit: install_pack and register_repository on the bridge, open_workspace → open_goal → open_lane → open_worker on the human control channel, attach_worker and start_carrier on the agent channel. It makes no measurement; the census is taken from outside, by /proc, as carrier.rs requires of every Carrier observation.
The chain that found the original defect was not committed, so the finding could not be re-run. This one is.
Measured, on the restored tree:
parent — super-cockpit (Tauri/GTK/WebKit)
total open descriptors 49
without O_CLOEXEC 5
fd 0 /dev/null expected
fd 1 the log file expected
fd 2 the log file expected
fd 10 /dev/urandom ← would have been inherited
fd 28 /dev/urandom ←
child — the Carrier it started
fd 0 /dev/pts/9
fd 1 /dev/pts/9
fd 2 /dev/pts/9
fd 3 socket:[39513999]
Seccomp 2 · Seccomp_filters 1 · NoNewPrivs 1
Two ambient descriptors above fd 3 on this run, not the eight the finding recorded — the finding's cockpit had WebKit's memory-pressure monitor open on /proc/meminfo, /proc/zoneinfo and three cgroup files as well. One is enough; the count is whatever GTK and WebKit happen to be doing.
And it is a falsifier, not a green line. With seal_inheritance stubbed out and the cockpit rebuilt, the same chain reproduces the original finding verbatim:
ampd: carrier floor refused ["observed:descriptor_set_exact"]
start_carrier refused: carrier-confinement-unacceptable
The prior round observed that a refused Carrier start "left a drain retrying and churned the projection". Measured here on the production path, with the seal stubbed out to produce a real floor refusal, over 45 seconds after the refusal:
t log lines "staying fenced and retrying" "physical carrier set is empty"
0 3 0 0
… 3 0 0
45 3 0 0
One carrier floor refused line, one refusal reply, and nothing else. The refused process is reaped — the cockpit's child count drops by one within 30 s — and the Gate never re-fences. A control run with the seal restored, so the Carrier is accepted, burns more BEAM CPU over the same window (≈55 ticks/5 s vs ≈40), which is the live Carrier and its terminal pump: the refusal is the quieter case, not the churning one.
I cannot test the fixture that produced the original observation, because it was not committed. That is the finding about that finding. What is testable now says a single refusal converges.
Not closed by assertion: this is one refusal on one path. If a Phase-B run produces churn again, it is a separate lifecycle finding and must not be folded into a confinement slice.
descriptor exactness GREEN the seal establishes it, from any host
Landlock GREEN differential, through the seal
seccomp GREEN mode 2, 1 filter, no_new_privs
explicit-extra GREEN survives, at its target and nowhere else
ruleset collision GREEN refused before placement
host verify 290 held · 0 failed (was 284)
host sabotage 49 falsified · 0 did not (was 45)
cockpit battery 89 held · 0 failed
ExUnit 586 tests · 0 failures (see the anomaly below)
dispatch partition 11 held · 0 failed
ordered closure 53 roots · 380 functions · 26 crossings · CLOSED
webview acl 32 held · 0 failed
GO.
The ordered census is byte-identical to 7961233's — 380 functions, 26 crossings, CLOSED — which is what a confinement-only change should do to it.
Seeds default and 424242 each ran 586/0. Seed 909090 ran 586 tests, 4 failures once, and 586/0 on the five runs that followed it — four at the same seed with the same tree, then one more after clearing three orphaned mix run --no-halt runtimes my own cockpit measurements had left on the machine.
I do not know which four tests failed. That run's output went through a grep for the summary line and the rest was discarded, which is the same mistake tools/sabotage-host.sh's evidence header was written about — a run that found something, overwritten by the runs it triggered. It is recorded here as an unexplained single anomaly rather than as a flake I have a story for: the orphaned runtimes are a plausible cause and were still present for four of the clean runs, so they do not explain it.
Nothing in this slice touches the BEAM. It is the same 586 tests that were green at 7961233, and the confinement change is entirely on the host side of the boundary. That is a reason to expect it is unrelated, not evidence that it is.