Phase 8 C (2/n): expand cert storage; NVRAM persistence crashed, reverted

Cert storage expanded from the old 16-byte placeholder to a real
32-byte seed + 32-byte pubkey. vm_zuse_cert_install() now has a
kernel-side duplicate in src/starkernel/vm/vm_core.c -- the kernel
build's VM_EXCLUDE list drops src/vm.c entirely (same reason
vm_set_base() already has two independent copies), so the hosted-only
version added earlier this session was never actually linked into the
kernel. FORTH-side ZUSE-CERT-LO@/HI@ replaced with ZUSE-PUBKEY@ (i -- u)
over the public half only; ACL-ZUSE-BOOT now checks
ZUSE-CERT-INSTALLED? before authenticating instead of unconditionally.

Attempted NVRAM-based persistence (GetVariable/SetVariable) for the
first-boot mint flow: page-faulted inside OVMF's variable service
(CR2 in the flash MMIO window). Moving the call site to match the one
proven-safe existing SetVariable call site in this codebase produced
the identical crash -- not a timing issue. Localized with debug
markers (one boot): GetVariable works; SetVariable with real data
never returns. The existing "working" precedent call is actually a
delete-of-nonexistent-variable (size=0, data=NULL), a cheaper path
that never touches flash, so it proved nothing about real writes.
Root cause: this kernel's VMM never maps the region OVMF's variable
service needs for real flash writes -- a genuine gap in UEFI runtime-
services support, not Zuse-specific, and not obviously fixable in a
3-arch-uniform way (flash window location is firmware/arch-specific).

Independently, storing the raw seed in RUNTIME_ACCESS NVRAM would have
been a real security defect regardless of the crash -- readable by any
later-loaded UEFI app or the booted OS.

Reverted to a known-safe state: all NVRAM/mint code removed from
kernel_main.c, init.4th's ACL.4th line back to its documented
commented-out default. Verified clean compile and clean boot on all
three architectures. Cert storage expansion (the part that works)
stays. A dedicated system-identity disk (virtio-blk, already proven
for writes via Artemis) is the recommended next substrate -- not yet
decided or built. Full investigation documented in FABRIC-3.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U14ET9CWAtbQMbYqomKgXd
This commit is contained in:
Robert Allan James
2026-08-26 15:55:27 -04:00
co-authored by Claude Sonnet 5
parent f223a31cec
commit e5cbc71f46
17 changed files with 54299 additions and 46 deletions
+51
View File
@@ -475,6 +475,57 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
first-boot mint-vs-already-minted boot sequence using `SetVariable`/`GetVariable`, and the
`MINT` word itself.
**Cert struct expanded (2026-08-26):** `vm_zuse_cert_install()` (both `src/vm.c`'s hosted
copy and a new kernel-side duplicate in `src/starkernel/vm/vm_core.c` -- the kernel build's
`VM_EXCLUDE` list drops `src/vm.c` entirely, same reason `vm_set_base()` already has two
independent copies) now takes a real 32-byte seed + 32-byte pubkey instead of the old
16-byte placeholder. FORTH-side `ZUSE-CERT-LO@`/`HI@` replaced with `ZUSE-PUBKEY@ ( i -- u )`
(8-byte LE chunk `i`, 0..3, of the public half only -- the seed has no FORTH access at all).
`ACL-ZUSE-BOOT` now checks `ZUSE-CERT-INSTALLED?` before authenticating rather than
authenticating unconditionally. Verified: clean compile and clean boot on all three
architectures.
**NVRAM persistence attempt: crashed, root-caused, reverted -- do not retry as designed.**
First attempt placed the mint-or-load `GetVariable`/`SetVariable` logic right after
`virtio_rng_init()` (before `capsule_birth_mama()`); it page-faulted (`CR2` inside the OVMF
flash MMIO window, a supervisor write to a not-present page) partway through boot. Moved the
same logic to the one place in this codebase already calling `SetVariable` post-
`ExitBootServices` successfully (`SF_VAR_REBOOT_TRIES`, much later in boot) — **identical
crash, same RIP and CR2** — which disproved the "too early in boot" theory outright: it isn't
a timing issue.
**Localized precisely (advisor-directed, one boot, debug markers around each call):**
`GetVariable` returns fine. `SetVariable` **with real 64-byte data** never returns — that's
the exact fault site. The pre-existing `SF_VAR_REBOOT_TRIES` call that looked like a working
precedent is actually a **delete of a variable that's never existed** (`size=0, data=NULL`) —
a fundamentally different, much cheaper internal path than a real data write, so it proved
nothing about real persistence being safe. **Root cause: this kernel's VMM never maps
whatever memory region OVMF's variable service needs to actually write flash-backed variable
data** — a real gap in UEFI runtime-services support, not specific to Zuse. Fixing it for
real means walking the UEFI memory map for the relevant regions and mapping them into the
kernel's own page tables, and per Section U's own note, the flash window's location is
firmware/arch-specific (OVMF's differs from AAVMF's and EDK2-riscv64's), so "walk the map and
map everything" is not guaranteed 3-arch-uniform even once attempted.
**Second, independent finding (not a bug, a design flaw in the persistence choice): storing
the raw 32-byte seed in NVRAM was a real defect regardless of the crash.** `SetVariable` was
called with `EFI_VARIABLE_RUNTIME_ACCESS`, meaning any later-loaded UEFI application or the
booted OS itself could read Zuse's private key straight out of NVRAM. For an irrevocable
"one and only one Zuse, ever" root of trust, that undermines the property the design exists
to provide — this would have needed fixing even had the crash not happened.
**Decision needed, not yet made:** given virtio-blk writes are already proven working on all
three architectures in this repo (`vblk_write`, Artemis's own persistence across runs), a
dedicated file-backed system-identity disk (mirroring `disk/artemis.img`'s existing pattern,
separate from Artemis's internal storage and separate from home-blocks USB thumbdrives) is
the substrate with no open unknowns today — recommended over either fixing the UEFI
flash-mapping gap (real but large, unscoped VMM work) or accepting the NVRAM approach as
originally designed (has the exposed-seed defect regardless). Not decided or built yet.
**Reverted to a known-safe state:** all Zuse mint/NVRAM code removed from `kernel_main.c`
(only two harmless includes remain), `init.4th`'s `ACL.4th` line back to its documented
commented-out default. Verified clean compile and clean boot on all three architectures in
this reverted state.
### From FABRIC-2.md §X, Milestone 5 — Console/VM key-match binding
- [ ] Settle the still-open question: reuse `ACL-PIN`/`acl_allow` directly, or build a