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
+7
View File
@@ -624,6 +624,13 @@ typedef void (EFIAPI *EFI_RESET_SYSTEM)(
/* NVRAM variable names (UCS-2 string literals) */
#define SF_VAR_BOOT_ARGS L"StarForthBootArgs"
#define SF_VAR_REBOOT_TRIES L"StarForthRebootTries"
#define SF_VAR_ZUSE_CERT L"StarForthZuseCert" /* 64 bytes: 32-byte Ed25519
* seed || 32-byte pubkey.
* Written exactly once
* (Phase 8 first-boot mint,
* see FABRIC-3.md) --
* presence means the fuse
* is already blown. */
/* ---- BootInfo extension ------------------------------------------------ */
#include "kernel_args.h"
+14 -8
View File
@@ -392,11 +392,16 @@ typedef struct VM
uint8_t emergency_console; /**< 1 = fault handler active; bypasses all ACL checks (C-only write) */
uint8_t zuse_session; /**< 1 = zuse authenticated at console; shows zuse)ok> prompt */
uint8_t acl_skip; /**< 1 = skip all ACL hooks (Ananke enforcement VM; prevents recursion) */
uint8_t zuse_cert_installed; /**< 1 = zuse_cert_lo/hi hold a real minted cert (one-time fuse) */
uint64_t zuse_cert_lo; /**< Zuse cert value, low half. C-only write via vm_zuse_cert_install(). */
uint64_t zuse_cert_hi; /**< Zuse cert value, high half. No FORTH word can write these fields --
* deliberately kept out of the dictionary so ACL-PIN's redefinition-only
* guarantee can't be bypassed via >BODY on a CONSTANT (see FABRIC-3.md). */
uint8_t zuse_cert_installed; /**< 1 = zuse_cert_seed/pubkey hold a real minted cert (one-time fuse) */
uint8_t zuse_cert_seed[32]; /**< Ed25519 seed, this instance's Zuse identity. C-only write via
* vm_zuse_cert_install(); no FORTH word can read or write it --
* the seed is the private key, never exposed past this struct. */
uint8_t zuse_cert_pubkey[32]; /**< Ed25519 public key derived from the seed at mint time, cached
* here so callers don't need to re-derive it. No FORTH word can
* write it -- deliberately kept out of the dictionary so ACL-PIN's
* redefinition-only guarantee can't be bypassed via >BODY on a
* CONSTANT (see FABRIC-3.md). Read-only FORTH access via
* ZUSE-PUBKEY@. */
/** @} */
/** @name Dictionary Management
@@ -631,10 +636,11 @@ cell_t* vm_dictionary_get_data_field(DictEntry* entry);
void vm_compile_word(VM* vm, DictEntry* entry);
/* Zuse cert one-time install (blows the fuse). Returns 0 on success, -1 if
* already installed -- a second call is a caller bug, not a runtime error to
/* Zuse cert one-time install (blows the fuse). seed and pubkey are each 32
* bytes, copied into the VM struct. Returns 0 on success, -1 if already
* installed -- a second call is a caller bug, not a runtime error to
* recover from silently. C-only: no FORTH word wraps this. */
int vm_zuse_cert_install(VM* vm, uint64_t lo, uint64_t hi);
int vm_zuse_cert_install(VM* vm, const uint8_t seed[32], const uint8_t pubkey[32]);
/* Memory management */
void* vm_allot(VM* vm, size_t bytes);