From c4f9458ad658764e7f5fb8065dcfd5a5de572933 Mon Sep 17 00:00:00 2001 From: Robert Allan James Date: Thu, 27 Aug 2026 14:30:30 -0400 Subject: [PATCH] FABRIC-3.md: scope BINDSTEP -- extends the live, unguarded USE word Traced the actual retarget path before assuming new plumbing: USE (mama_forth_words.c:430-480) already looks up a VM by name and calls sk_repl_set_active_vm() directly, completely unguarded. BINDSTEP is concretely "add the ACLKEY comparison to this one call site." Found one real gap: usb_blk_dev/xdev are function-static inside sk_repl_idle(), invisible to USE -- needs a small new accessor mirroring sk_repl_get_active_vm()'s own precedent. Decisions: re-verify the attached drive live on every USE call rather than trust a cached pubkey; VMs with no VMIdentity installed yet (Hera/Hermes/Artemis today) stay freely targetable, no regression; installed=1 targets refuse on no-drive-attached or pubkey mismatch, matching USE's existing refusal style. Zuse's override UX stays deferred per direct instruction. --- FABRIC-3.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/FABRIC-3.md b/FABRIC-3.md index ef8152f..d39e21e 100644 --- a/FABRIC-3.md +++ b/FABRIC-3.md @@ -682,7 +682,10 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR - [ ] Implement the actual attach/bind step — extending `sk_repl_set_active_vm()` (confirmed to exist, currently an unguarded raw pointer-set) with the key-match check from above, so a - console can only bind to the one VM whose lock matches its key. + console can only bind to the one VM whose lock matches its key. **SCOPED 2026-08-27 + (`FABRIC-3.md` §F.9)**: real gate is `USE` (`mama_forth_words.c:430-480`), the live, + already-working, currently-unguarded retarget word — check re-verifies the attached drive + live on every call; `installed=0` VMs stay freely targetable. - [ ] Implement detach behavior on console disconnect or VM teardown. @@ -1426,7 +1429,7 @@ graph TD ACLKEY["❓ ACL 'bumps and holes' comparison
semantics — SAME GAP in M5 and D.4"] WIREBIND["❌ Wire hotplug → capsule_birth_baby() (M5)"] - BINDSTEP["❌ Extend sk_repl_set_active_vm()
with key-match (M5)"] + BINDSTEP["❌ Extend sk_repl_set_active_vm()
with key-match (M5) — SCOPED 2026-08-27 (§F.9)"] DETACH["❌ Detach behavior (M5)"] EXPIRE["✅ EXPIRE reframed: session end
= VM detach via COOL (§B + D.2)"] @@ -1519,6 +1522,10 @@ finished). Dashed arrows = softer "gates/informs" relationships. (`CERTVERIFY`, `WIREBIND`, `RUNCAP`, `HOTPLUG`) was already treating raw devblock-0 as the working format. Dropping GPT converts all of those from "interim, revisit later" to simply "the design," retroactively. +- **`BINDSTEP` already has a live target to gate, not new plumbing** (§F.9) — `USE` + (`mama_forth_words.c`) is a real, working, currently-unguarded retarget word. The only + genuinely new code this node needs is a small cross-file accessor for the currently-attached + device (mirroring `sk_repl_get_active_vm()`'s own precedent) plus the comparison itself. **Not yet done:** an ordered plan (which node to attack first, given the graph). Per Captain Bob's own framing, that's the next pass — "start asking and answering questions iteratively @@ -1876,6 +1883,47 @@ refuse-on-non-blank-media posture — reasonable by analogy, not decided here. T is unchanged and already modeled in the graph: `WRITE(10)` still doesn't exist, so `MINT` cannot write anything to real or QEMU-emulated USB media yet regardless of the above. +### F.9 — `BINDSTEP` (extending `sk_repl_set_active_vm()` with the `ACLKEY` check) + +Traced against the live retarget path before assuming new plumbing was needed: +`USE` (`mama_forth_words.c:430-480`) is the real, already-working console-retarget word — +`S" name" USE` looks a VM up by name (case-insensitive) and calls `sk_repl_set_active_vm()` +directly, completely unguarded today. `BINDSTEP` is concretely "add the `ACLKEY` (§F.2) +comparison to this one call site," not a new mechanism. + +**Real gap found, not just a policy question:** the "re-verify live" approach (decided below) +needs access to whatever drive is currently attached, but `usb_blk_dev`/`xdev` +(`repl.c:107-108`) are function-static inside `sk_repl_idle()` — invisible to `USE`, which +lives in `mama_forth_words.c`. `BINDSTEP` needs a small new accessor exposing "the currently +attached home-blocks device," mirroring the existing `sk_repl_get_active_vm()` precedent +(`repl.h:67-69`) for exactly this kind of cross-file REPL-state access. + +**Decisions made 2026-08-27 (iterative Q&A pass):** + +1. **Check freshness: re-verify live, not cached.** Every `USE` call re-runs the + drive-check/`CERTVERIFY` path against whatever is currently attached, rather than trusting a + pubkey cached at original attach time. `USE` is a rare, human-triggered, interactive + operation — the repeated DER-parse + `ed25519_verify()` cost is a non-issue, and this avoids + any staleness question if a drive was swapped without a clean detach. +2. **VMs with no `VMIdentity` installed yet (`installed=0`) — Hera/Hermes/Artemis today, until + `D.5`'s per-VM-identity work lands — stay freely targetable, no check applied.** Preserves + `USE`'s current working behavior exactly; refusing on `installed=0` would be a real + regression today for VMs that were never in scope for this lock in the first place. +3. **For an `installed=1` target:** `BINDSTEP` refuses (matching `USE`'s existing clean + early-refusal style for not-found/dead-VM cases) whenever either no drive is currently + attached, or the freshly re-verified cert's owner pubkey doesn't match the target's + `VMIdentity.owner_pubkey`. No drive attached is a plain refusal, not a special case — it + simply means "no identity presented," which can never match. +4. **Zuse's override UX: deferred**, per direct instruction — this pass confirms the + architectural constraint from `F.2` still stands (a distinct, explicit call path, not a + branch folded into `USE`'s own logic) without committing to the exact word/interaction yet. + +**Not yet scoped (deferred within this node):** the new accessor's exact name/signature; the +refusal message text (matching `USE`'s existing console-message style); whether a refused +`BINDSTEP` attempt should produce an audit-log record (this codebase has a real precedent for +this — `capsule_parity_log_birth_failed()` and friends, `parity.c` — but nothing says a +security-relevant refusal here needs the same treatment; not decided). + ### D.5 — Scope expansion (2026-08-27): identity is common to every VM, not just users Surfaced while scoping `ACLKEY`, stated directly: *"the whole object is to deliver a