FABRIC-3.md §I.3/§I.8: WIREBIND EJECT/detach + EXPIRE re-scoped as logout

Closes §I.3 (Milestone 5 remainder): WIREBIND now tracks which VM is
attached via the home-blocks USB path, and a new EJECT word plus the
existing hot-unplug signal both flush/reset-console/kill through it
(FABRIC-3.md §F.10).

Closes §I.8 (EXPIRE/ACL), re-scoped: the original "admit the zuse
session as a Stadium patron and reap on TTL" plan was invalidated a
second time -- Zuse authenticates directly onto Hera, who is patron
zero and permanently pinned, so there is no patron for a reap sweep to
ever find. Built instead as a detach-triggered logout
(capsule_zuse_boot_logout()), the same trigger EJECT/hot-unplug use for
regular WIREBIND users, so neither identity is a special case. Required
a companion fix: install_and_activate() used to skip re-running
ACL-ZUSE-BOOT whenever the cert was already installed, which made a
logout permanent for the rest of the boot; the outer re-attach gate now
checks zuse_session (clears on logout) instead of zuse_cert_installed
(a deliberate permanent one-way ratchet, left untouched).

Verified 3-arch boot to ok> (amd64/aarch64/riscv64, each in the
foreground) after both steps; logs and DoE CSVs from this session's
verification runs included per this repo's own audit-artifact
convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YcT3H2PQeyujrzjqS3Var
This commit is contained in:
Robert Allan James
2026-09-04 09:21:01 -04:00
co-authored by Claude Sonnet 5
parent 34203613bb
commit 60d9c2520e
40 changed files with 165701 additions and 16 deletions
+75
View File
@@ -18,12 +18,23 @@
#include "starkernel/vm_identity.h"
#include "starkernel/user_identity_seed.h"
#include "starkernel/console.h"
#include "starkernel/repl.h" /* sk_repl_get/set_active_vm() -- FABRIC-3.md §F.10 EJECT */
#include "blkio.h"
#include "block_subsystem.h" /* compute_crc64() */
#include "word_source/include/block_words.h" /* blk_vm_flush_all() -- §F.10 EJECT */
#include "freestanding/stdio.h"
#include <string.h>
#include <stddef.h>
/* FABRIC-3.md §F.10: "the VM currently attached via the home-blocks USB
* path" -- WIREBIND's own to track, set at successful birth in
* capsule_wirebind_try_attach(), read and cleared by both
* capsule_wirebind_eject() and capsule_wirebind_unclean_detach(). Single-
* USB-device constraint (§F.8) means there is never more than one
* candidate, so one tracked id is enough -- no set/list. */
static VMUuid g_wirebind_attached_vm_id;
static int g_wirebind_attached_valid = 0;
/* WIREBIND_CERT_MAX_DEVBLOCKS: a sane upper bound on how much cert
* content this reads, independent of whatever sig->cert_devblocks
* claims -- MINT (capsule_mint.c) only ever writes 1 devblock's worth
@@ -162,6 +173,13 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
((VM *)user_ctx)->identity = identity;
}
/* FABRIC-3.md §F.10: this is the successful-birth point EJECT/UNCLEAN
* need a tracked VMUuid from -- the user VM, not the console VM
* (blk_vm_flush_all()/capsule_vm_kill() below both act on the VM that
* actually owns block-subsystem state). */
g_wirebind_attached_vm_id = user_id;
g_wirebind_attached_valid = 1;
/* Register the pairing in the console's own routing table, index 3
* -- the fixed convention sk_repl_dispatch_line() (repl.c) uses. */
{
@@ -176,3 +194,60 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
console_puts(username);
console_println(" attached and ready -- USE it to begin");
}
/* Shared by capsule_wirebind_eject() and capsule_wirebind_unclean_detach():
* resolve the tracked attached-VM id to a live entry, or clear the tracked
* state and report "nothing attached" if it's already gone (idempotent --
* matches capsule_vm_kill()'s own convention). */
static int wirebind_resolve_attached(VMRegistryEntry *out) {
if (!g_wirebind_attached_valid) return -1;
if (capsule_vm_registry_get(g_wirebind_attached_vm_id, out) != 0 ||
out->state != VM_STATE_LIVE) {
g_wirebind_attached_valid = 0;
return -1;
}
return 0;
}
int capsule_wirebind_eject(void) {
VMRegistryEntry entry;
if (wirebind_resolve_attached(&entry) != 0) {
console_println("EJECT: nothing attached via WIREBIND");
return -1;
}
/* Drive is still physically present -- flush before it's safe to
* remove (§F.10 decision 1). */
blk_vm_flush_all((VM *)entry.vm_ptr);
if (sk_repl_get_active_vm() == (VM *)entry.vm_ptr) {
sk_repl_set_active_vm((VM *)0);
}
capsule_vm_kill(entry.name);
g_wirebind_attached_valid = 0;
console_puts("EJECT: ");
console_puts(entry.name);
console_println(" flushed and detached");
return 0;
}
void capsule_wirebind_unclean_detach(void) {
VMRegistryEntry entry;
if (wirebind_resolve_attached(&entry) != 0) return;
/* Device is already gone (§F.10 decision 2) -- no flush attempted;
* data since the last flush is lost, matching real-OS unclean-removal
* semantics. */
if (sk_repl_get_active_vm() == (VM *)entry.vm_ptr) {
sk_repl_set_active_vm((VM *)0);
}
capsule_vm_kill(entry.name);
g_wirebind_attached_valid = 0;
console_puts("WIREBIND: ");
console_puts(entry.name);
console_println(" detached without flush (device already gone)");
}