Punch list item 3: UNATTENDED-BIRTH call site, verified live end-to-end
Implements the unattended-birth mechanism FABRIC-3.md §XXXII.2 designed: UNATTENDED-BIRTH ( name-c name-u -- ok? ) births a VM from a named (p) capsule via capsule_birth_baby() (completely unmodified, the same generic build-time-capsule path CAPSULE-BIRTH already uses), then installs its identity the same way capsule_wirebind.c already does live for WIREBIND attaches -- vm_identity_from_cert() verification followed by a plain post-birth struct assignment -- rather than anything RUNCAP-shaped, since RUNCAP requires a real blkio_dev+ homeblocks_sig_t an unattended identity never has. The born VM's own capsule payload is expected to lay down two CREATE'd buffers (UNATTENDED-ID-UUID, UNATTENDED-ID-CERT) via MINT-SCRATCH- EMIT's own literal format; their addresses are fetched by interpreting a two-word line inside the *new* VM's own context (vm_interpret(born_vm, ...)), the same "run inside that VM's own dictionary" idiom capsule_wirebind.c already uses for VM-NAME-REG. Explicit invariant preserved: never touches g_wirebind_attached_username or any console-pairing state, births no console VM -- an unattended identity stays un-promptable (§VIII.1) until a human pairs a console to it later via the already-working VM-NAME-REG mechanism. Verified live end-to-end on amd64: minted a real test identity via MINT-SCRATCH, captured its MINT-SCRATCH-EMIT output, built a throwaway test capsule from it (discovered along the way: mkcapsule's real block constraints are range [2048,5120) and max 16 content lines per block -- neither matches this repo's own doc comment, corrected via ground truth from the tool itself, not assumed), then ran UNATTENDED-BIRTH against it: cert verified against Zuse's root pubkey, identity installed, "no console attached" reported, Hera stayed healthy afterward (5 6 + . -> 11). Test capsule reverted after capture per this project's own probe convention -- not a real identity, never committed. Clean 3-arch qemu boot (amd64/aarch64/riscv64) on the real committed C-only change. Remaining punch-list item (the ACL cap bit for console attachment) not started. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BWpNjdwPtFLuVLaAq44L9K
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5fc709a228
commit
5879c8b3bc
@@ -48,6 +48,7 @@
|
||||
#include "freestanding/stdio.h"
|
||||
#include "starkernel/capsule_mint.h"
|
||||
#include "starkernel/user_identity_seed.h"
|
||||
#include "starkernel/vm_identity.h"
|
||||
#include "starkernel/zuse_eligibility.h"
|
||||
#include "starkernel/capsule_loader.h"
|
||||
#include "starkernel/capsule_run.h"
|
||||
@@ -1613,6 +1614,124 @@ void mama_word_capsule_birth(VM *vm)
|
||||
vm_push(vm, (cell_t)new_vm_id.hi);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UNATTENDED-BIRTH ( name-c name-u -- ok? )
|
||||
* Birth an unattended identity from a named (p) capsule -- the
|
||||
* punch-list item 3 call site (FABRIC-3.md §XXXII.2, 2026-09-16):
|
||||
* capsule_birth_baby() unmodified (same generic build-time-capsule
|
||||
* birth path CAPSULE-BIRTH above already uses), then a post-birth
|
||||
* identity install matching capsule_wirebind.c's own proven pattern
|
||||
* (verified cert -> plain struct assignment onto the born VM's own
|
||||
* identity field) rather than anything RUNCAP-shaped -- RUNCAP requires
|
||||
* a real blkio_dev+homeblocks_sig_t an unattended identity never has.
|
||||
*
|
||||
* The capsule's own IDENTITY code (run as part of capsule_birth_baby()
|
||||
* itself) is expected to have already laid down two CREATE'd buffers
|
||||
* in the new VM's own dictionary -- UNATTENDED-ID-UUID (16 bytes) and
|
||||
* UNATTENDED-ID-CERT (4096 bytes), exactly the shape MINT-SCRATCH-EMIT
|
||||
* prints for hand-transcription. Their addresses are fetched by
|
||||
* interpreting a two-word line inside the *new* VM's own context
|
||||
* (vm_interpret(born_vm, ...)) -- the same "run inside that VM's own
|
||||
* dictionary" idiom capsule_wirebind.c already uses for VM-NAME-REG,
|
||||
* not a new mechanism.
|
||||
*
|
||||
* Explicit invariant (FABRIC-3.md §XXXII.2's own ratified text): this
|
||||
* word never touches g_wirebind_attached_username or any other
|
||||
* WIREBIND/console-pairing state, and births no console VM -- an
|
||||
* unattended identity stays un-promptable (§VIII.1) until a human
|
||||
* pairs a console to it later via the existing VM-NAME-REG mechanism,
|
||||
* a separate, already-working step this word does not perform.
|
||||
*/
|
||||
static void mama_word_unattended_birth(VM *vm)
|
||||
{
|
||||
char capsule_name[VM_NAME_MAX];
|
||||
cell_t u, caddr;
|
||||
uint32_t i;
|
||||
|
||||
if (vm->dsp < 1) {
|
||||
console_println("UNATTENDED-BIRTH: expects S\" capsule-name\" UNATTENDED-BIRTH");
|
||||
vm->error = 1;
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
u = vm_pop(vm);
|
||||
caddr = vm_pop(vm);
|
||||
if (u <= 0 || (uint32_t)u >= VM_NAME_MAX) {
|
||||
console_println("UNATTENDED-BIRTH: capsule name too long or empty");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
{
|
||||
const uint8_t *p = vm_ptr(vm, (vaddr_t)caddr);
|
||||
if (!p) {
|
||||
console_println("UNATTENDED-BIRTH: invalid address on the stack");
|
||||
vm->error = 1;
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < (uint32_t)u; i++) capsule_name[i] = (char)p[i];
|
||||
}
|
||||
capsule_name[u] = '\0';
|
||||
|
||||
if (!vm->zuse_root_pubkey_known) {
|
||||
console_println("UNATTENDED-BIRTH: refused -- Zuse's root pubkey not yet loaded");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
VMUuid new_vm_id = vm_uuid_none();
|
||||
void *new_vm_ctx = (void *)0;
|
||||
CapsuleRunResult result = capsule_birth_baby(
|
||||
capsule_name,
|
||||
capsule_get_directory(),
|
||||
capsule_get_descriptors(),
|
||||
capsule_get_names(),
|
||||
capsule_get_arena(),
|
||||
vm->stadium_vm_id,
|
||||
0, /* skip_pki_sig: normal build-time capsule, same as CAPSULE-BIRTH */
|
||||
&new_vm_id,
|
||||
&new_vm_ctx
|
||||
);
|
||||
if (result != CAPSULE_RUN_OK || !new_vm_ctx) {
|
||||
console_println("UNATTENDED-BIRTH: birth FAILED");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
VM *born_vm = (VM *)new_vm_ctx;
|
||||
|
||||
cell_t dsp_before = born_vm->dsp;
|
||||
vm_interpret(born_vm, "UNATTENDED-ID-UUID UNATTENDED-ID-CERT");
|
||||
if (born_vm->error || born_vm->dsp != dsp_before + 2) {
|
||||
console_println("UNATTENDED-BIRTH: refused -- capsule never defined "
|
||||
"UNATTENDED-ID-UUID/UNATTENDED-ID-CERT");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
cell_t cert_addr = vm_pop(born_vm);
|
||||
cell_t uuid_addr = vm_pop(born_vm);
|
||||
|
||||
const uint8_t *cert = vm_ptr(born_vm, (vaddr_t)cert_addr);
|
||||
const uint8_t *uuid = vm_ptr(born_vm, (vaddr_t)uuid_addr);
|
||||
if (!cert || !uuid) {
|
||||
console_println("UNATTENDED-BIRTH: refused -- invalid identity data address");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
VMIdentity identity;
|
||||
if (vm_identity_from_cert(&identity, cert, 4096,
|
||||
vm->zuse_root_pubkey, uuid,
|
||||
0 /* acl_caps: no bits assigned yet, §F.2 */) != 0) {
|
||||
console_println("UNATTENDED-BIRTH: refused -- cert verification FAILED");
|
||||
vm_push(vm, 0);
|
||||
return;
|
||||
}
|
||||
born_vm->identity = identity;
|
||||
|
||||
console_println("UNATTENDED-BIRTH: identity installed, no console attached");
|
||||
vm_push(vm, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CAPSULE-RUN ( capsule-id -- )
|
||||
* Run an experiment (e) capsule on Mama.
|
||||
@@ -1953,6 +2072,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "MINT", mama_word_mint);
|
||||
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
|
||||
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
|
||||
register_word(vm, "UNATTENDED-BIRTH", mama_word_unattended_birth);
|
||||
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
||||
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
||||
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
||||
@@ -2014,6 +2134,7 @@ void register_mama_forth_words(VM *vm)
|
||||
register_word(vm, "MINT", mama_word_mint);
|
||||
register_word(vm, "MINT-SCRATCH", mama_word_mint_scratch);
|
||||
register_word(vm, "MINT-SCRATCH-EMIT", mama_word_mint_scratch_emit);
|
||||
register_word(vm, "UNATTENDED-BIRTH", mama_word_unattended_birth);
|
||||
register_word(vm, "ZUSE-ELIGIBILITY-ADD", mama_word_zuse_eligibility_add);
|
||||
register_word(vm, "ZUSE-ELIGIBLE?", mama_word_zuse_eligible_query);
|
||||
register_word(vm, "NAME>XT", mama_word_name_to_xt);
|
||||
|
||||
Reference in New Issue
Block a user