All found by actually running the identity workflow §VII/§VIII made possible, not by code review: 1. Zuse/WIREBIND cross-contamination on detach: capsule_zuse_boot_logout() and capsule_wirebind_unclean_detach() both had no device parameter, so an unrelated device detaching (while the real owner's own stayed attached) incorrectly tore down the wrong session. Both now compare the departing device against their own tracked one, mirroring capsule_wirebind.c's pre-existing g_wirebind_attached_dev precedent. 2. Dictionary-entry memory leak: vm_create_word()'s sf_malloc()'d DictEntry (plus a second per-entry allocation for transition_metrics) was never freed by vm_cleanup(), in both the hosted and kernel implementations. Caused a real kernel PANIC after 8-9 repeated VM birth/kill cycles in one boot. Fixed by walking vm->latest in both. 3. sf_malloc/sf_free (alloc_kernel.c) was a 4MB bump arena with a deliberate no-op free, sized on "VM born once, never killed" -- fix #2 alone didn't stop the panic because free() itself discarded the pointer regardless. Given a real free list (first-fit reuse). 4. Headless-console gate didn't re-engage after a mid-boot logout: the original fix (sk_console_mark_login(), one-way sticky) only gated the first login of the boot. Replaced with a live check (sk_console_identity_present()) re-evaluated continuously, including inside sk_console_readline()'s own blocking idle loop -- the console is normally sitting blocked there when a hot-unplug logout happens, so checking only at the top of the REPL loop wasn't enough. Also: MINT now verifies its own write (verify_mint(), capsule_mint.c) by reading back through the same check a real attach performs, rather than trusting blkio_write()'s BLK_OK alone -- logged via log_message(), not console_println(), per direct instruction. Verified live, amd64: the full 8-identity repeated attach/detach cycle that previously panicked at the same point every time now completes clean, and a full serial-log sweep found zero bare unauthenticated prompts anywhere in the run. Three-arch clean-qemu acceptance passed. Still open, not fixed here: a 3+-simultaneous-device USB enumeration failure found in a separate live test, not yet root-caused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018EjXFo7mPXjUMjfJeuUUz4
121 lines
6.3 KiB
C
121 lines
6.3 KiB
C
/*
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
|
||
Copyright (c) 2023–2025 Robert A. James
|
||
All rights reserved.
|
||
|
||
Licensed under the StarForth License, Version 1.0
|
||
*/
|
||
|
||
/**
|
||
* capsule_mint.h - MINT: mint a fresh identity onto a blank thumbdrive
|
||
* (FABRIC-2.md §F.8/§F.19), the last piece of the original Tripod
|
||
* vision. Writes a real keypair, a Zuse-signed cert, and a minimal
|
||
* working default personality -- everything RUNCAP (capsule_runcap.h)
|
||
* and CERTVERIFY need at a later attach.
|
||
*/
|
||
|
||
#ifndef STARKERNEL_CAPSULE_MINT_H
|
||
#define STARKERNEL_CAPSULE_MINT_H
|
||
|
||
#ifdef __STARKERNEL__
|
||
|
||
#include <stdint.h>
|
||
#include "vm.h"
|
||
|
||
struct blkio_dev;
|
||
|
||
typedef enum {
|
||
MINT_OK = 0,
|
||
MINT_ERR_ALREADY_MINTED, /* dev already reads as a recognized home-blocks
|
||
* drive -- refuses rather than overwrite,
|
||
* mirroring WRITE(10)'s own blank-media
|
||
* posture (§F.8, decided 2026-08-28). */
|
||
MINT_ERR_NO_ZUSE_CERT, /* issuer_vm->zuse_cert_installed is 0 -- no
|
||
* key to sign the new cert with. */
|
||
MINT_ERR_NO_ENTROPY, /* virtio_rng not ready. */
|
||
MINT_ERR_CERT_BUILD, /* x509_build_user_cert() failed (shouldn't
|
||
* happen with fixed-size fields, but not
|
||
* assumed away). */
|
||
MINT_ERR_WRITE_FAIL, /* a devblock write failed partway through --
|
||
* the drive may be left partially minted. */
|
||
MINT_ERR_INVALID_PROFILE, /* full_name/username missing or too long for
|
||
* user_identity_seed_t's fixed fields, or
|
||
* email/phone too long (both may be NULL/empty
|
||
* -- that's "null", not invalid). */
|
||
MINT_ERR_VERIFY_FAILED, /* every devblock write reported success, but a
|
||
* post-write read-back (2026-09-06) found the
|
||
* drive doesn't actually read back as a valid,
|
||
* complete home-blocks identity -- caught
|
||
* live: a device that enumerates and accepts
|
||
* writes can still fail to read back correctly
|
||
* under real hardware/emulation conditions
|
||
* (e.g. concurrent multi-device USB load), and
|
||
* blkio_write() returning BLK_OK is not by
|
||
* itself proof the bytes landed. The drive may
|
||
* be left partially or incorrectly minted --
|
||
* treat identically to MINT_ERR_WRITE_FAIL for
|
||
* retry purposes. */
|
||
} MintResult;
|
||
|
||
/**
|
||
* capsule_mint_identity - Mint a fresh identity onto dev.
|
||
*
|
||
* Layout written (devblock offsets from dev's own start; devblock 0 is
|
||
* left alone, reserved for the block-subsystem's own generic header):
|
||
* devblock 1 homeblocks_sig_t (HOMEBLOCKS_SIG_START_FBLOCK)
|
||
* devblock 2 DER cert, Zuse-signed (cert_offset)
|
||
* devblock 3 user_identity_seed_t (identity_src_offset)
|
||
* devblock 4 default personality source (identity_src_offset+1)
|
||
*
|
||
* @param dev Already-open block device for the target drive.
|
||
* @param issuer_vm The signing identity -- in practice always Hera's own
|
||
* VM (Zuse's cert lives there, vm.h's zuse_cert_seed).
|
||
* NULL means genesis mode (§F.21): no cert is built or
|
||
* written (cert_offset/cert_devblocks stay 0) and
|
||
* issuer_vm->zuse_cert_installed is never checked --
|
||
* used exactly once, to mint Zuse's own root identity,
|
||
* which by definition has no existing Zuse to sign it.
|
||
* @param full_name Required, NUL-terminated, fits user_identity_seed_t's
|
||
* full_name field (§F.20).
|
||
* @param username Required, NUL-terminated, fits its username field.
|
||
* @param email NULL or empty string = null (field stays empty).
|
||
* @param phone NULL or empty string = null (field stays empty).
|
||
* @param out_pubkey Optional (may be NULL): filled with the newly
|
||
* generated identity's own Ed25519 public key on
|
||
* success. Genesis mode's only caller needs this, to
|
||
* write it into the system-resident zuse_genesis_
|
||
* marker_t.
|
||
* @param out_seed Optional (may be NULL): filled with the newly
|
||
* generated identity's own Ed25519 seed on success.
|
||
* Genesis mode's only caller needs this too, to
|
||
* install the cert into Hera's own VM immediately
|
||
* (vm_zuse_cert_install()) -- the seed otherwise only
|
||
* ever lives on the minted thumbdrive.
|
||
* @param drive_known_blank Pass 1 when the caller has *already* just run
|
||
* homeblocks_sig_check() on dev and confirmed
|
||
* HOMEBLOCKS_SIG_BLANK (e.g. capsule_zuse_boot_try_
|
||
* attach(), which must check sig_rc before it can even
|
||
* decide to call this) -- skips this function's own
|
||
* internal "refuse to overwrite" re-check, which
|
||
* otherwise repeats the exact same full BOT read
|
||
* sequence a second time for no reason (found live,
|
||
* FABRIC-2.md §F.25/§F.26: the redundant check was
|
||
* mistaken for a hang before the real cause -- leaked
|
||
* `tail -f` processes from repeated hard kills during
|
||
* the same debugging session -- was found). Pass 0 from
|
||
* any caller (like MINT, mama_forth_words.c) that has
|
||
* not already checked -- the safety check still applies
|
||
* there.
|
||
* @return MINT_OK on success, an error code otherwise.
|
||
*/
|
||
MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
||
const char *full_name, const char *username,
|
||
const char *email, const char *phone,
|
||
uint8_t out_pubkey[32], uint8_t out_seed[32],
|
||
int drive_known_blank);
|
||
|
||
#endif /* __STARKERNEL__ */
|
||
|
||
#endif /* STARKERNEL_CAPSULE_MINT_H */
|