Skip to content

M5-2d0: establish what (d) still contains - #96

Open
mgrossmann wants to merge 1 commit into
mainfrom
m5-2d0-survey
Open

M5-2d0: establish what (d) still contains#96
mgrossmann wants to merge 1 commit into
mainfrom
m5-2d0-survey

Conversation

@mgrossmann

Copy link
Copy Markdown
Contributor

Docs-only. No code, no live run. A survey: docs/measurements/m5-2d0/survey.md.

(d) had never run — the #64 investigation landed between c0 and c1, the order was
resequenced around it, and afterwards no memo named it as next. It surfaced when (e)'s
stage a went to write the exit gate's isolation sentence and found the property is not
in the code.

Four questions, each answered from source against a criterion fixed in advance. This is
the evidence base d1 rests on, which is why it is its own PR rather than part of d1's diff.

Q1 — ubuf/ulen validation: the answer SPLITS

  • Cross-address-space security half: CLOSED. Every store into caller storage derived
    from ubuf is one of exactly three BAL R15,MOVEOUT sites (asm/nsfvsvc.asm:845,
    :961, :971), all inside MOVEOUT's borrowed-key SPKA window (:1036-1041), so a
    store the caller could not itself make faults instead of corrupting. Length is
    clamped to XFCHUNK 2048 in both directions and every loop guard is signed (LTR/BNP),
    so a negative ulen degenerates to a no-op.
  • Caller-side robustness half: open, and RECLASSIFIED. Nothing validates ubuf/ulen
    against the caller's actual buffer extent, so an over-declared ulen overruns the
    caller's own storage — inside its own address space, which is not a §17.3 concern
    and should stop being carried as one.
  • The 20 key-0 stores into the caller's NSFV_REQ block are a different destination,
    not derived from ubuf, and stay open (ADR-0041 category 3). Count re-confirmed exact.

Exhaustiveness needed TWO searches, and neither alone establishes it. A search for
stores with an R8 base structurally cannot find a store through a register loaded
from the caller's block — which is exactly how ubuf is written. The second search
(any store through R4/R5) returns exactly one instruction: MOVEOUT's own EX target.
The first attempt at it silently returned empty because the pattern could not match the
length form 0(1,R4); it was re-run with MVCPIEC as a positive control, since an
empty result and a broken pattern are otherwise identical.

Q2 — guard arithmetic: CLOSED with evidence

Four extracted functions in src/nsfreqx.c; both STCs (nsfsx.c, nsfv.c) call them,
with no hand-written copy anywhere; all four classifier rows, the reap predicate and the
two-helper consistency pinned in test/tstreqx.c.

Recorded because a reader will get it backwards later: c2 stage c removed a live
DRIVER, not host coverage.

Q3 — #67 is unreachable during (e)

TSTRQXC stages only QUERY, SLOT and RQE at both revisions, never ECHO or
XFER. And QUERY/UNSTAGE/SLOT dispatch before the claim loop (:390-395 vs
CLAIMLP :445) and return BR R14 — they claim no slot, never publish, never park, and
the contention counters live only in the claim path. So no (e) role can move EXHAUSTED
or COLLISIONS through a probe verb.

Decision 3's stated reason did not apply. Reported as the kickoff asks; not proposed
as a change.

Q4 — d2 is small in code, with one decision nobody has taken

The reap is pure C (nsfsx_reap via __cas): no assembler, no layout move, no
ANCVERNO bump, no re-run-every-gate. b3's fourth-state problem is about a CLAIMED
slot and does not apply — an UNKNOWN slot at shutdown is PENDING or HELD, both already
in reap_ok's published states.

But force-reap flips drained, which takes nsfsx_stop's else branch and
unloads the router under a possibly-parked client — which that branch's own comment
calls "STRICTLY WORSE than leaking both". The 2026-08-22 ruling was about the slot; it
never ruled on the module. The escape-hatch condition (d2 has grown into an
investigation) is not met.

§5 gathered for d1

THREE descriptor resolution points, not one: req_socket (src/nsfreq.c:547),
sel_scan (src/nsfsel.c:83) — which a req_socket-only check would miss entirely —
and soc_complete's internal one (src/nsfsoc.c:273), where a check would be wrong.

Plus the inherited-child behaviour, where the caller identity arrives, and the Phase-1
zero-identity enforcement point.

Verification

make test-host 3414 PASS / 0 FAIL, unchanged — a no-regression check only, since
this change contains no code. Diff is one added file.

(d) had never run -- the #64 investigation landed between c0 and c1, the order
was resequenced around it, and afterwards no memo named it as next. It surfaced
when (e)'s stage a went to write the exit gate's isolation sentence and found
the property is not in the code. This is the survey, not the work: no code, no
live run, four questions answered from source against criteria fixed in advance.

The ubuf/ulen obligation SPLITS. The cross-address-space security half is
closed: every store into caller storage derived from ubuf is one of exactly
three MOVEOUT sites, all inside the borrowed-key SPKA window, and the length is
clamped to 2048 in both directions with every loop guard signed, so a negative
ulen is a no-op rather than a hazard. The caller-side robustness half stays open
and is reclassified -- nothing validates ubuf/ulen against the caller's real
buffer extent, so an over-declared ulen overruns the caller's OWN storage, which
is not a 17.3 concern and should stop being carried as one.

Exhaustiveness needed two searches and neither alone establishes it. A search
for stores with an R8 base structurally cannot find a store through a register
loaded FROM the caller's block, which is exactly how ubuf is written; the second
search returns exactly one instruction, MOVEOUT's own EX target. The first
attempt at that search silently returned empty because the pattern could not
match the length form 0(1,R4), so it was re-run with MVCPIEC as a positive
control -- an empty result and a broken pattern are otherwise identical.

The guard-arithmetic obligation closes with evidence: four extracted functions,
both STCs calling them with no hand-written copy, and all four classifier rows,
the reap predicate and the two-helper consistency pinned in test/tstreqx.c.
Recorded there because a reader will get it backwards later: c2 stage c removed
a live DRIVER, not host coverage.

#67 is unreachable during (e). TSTRQXC stages only QUERY, SLOT and RQE at both
revisions and never ECHO or XFER, and QUERY/UNSTAGE/SLOT dispatch before the
claim loop and return BR R14 -- so they claim no slot and cannot move COLLISIONS
or EXHAUSTED. Decision 3's stated reason did not apply; reported, not proposed
as a change.

d2 is small in code -- the reap is pure C via __cas, so no assembler, no layout
move, no re-run-every-gate, and b3's fourth-state problem is about a CLAIMED
slot and does not apply. But it carries one decision nobody has taken:
force-reap flips `drained`, which takes nsfsx_stop's else branch and unloads the
router under a possibly-parked client. The 2026-08-22 ruling was about the slot,
not the module.

Gathered for d1: there are THREE descriptor resolution points, not one --
req_socket, sel_scan (which a req_socket-only check would miss entirely), and
soc_complete's internal one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant