Four bugs found live verifying the 8 identity thumbdrives (FABRIC-3.md §IX)
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
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0bae928aad
commit
2c1b3cd695
@@ -19,6 +19,7 @@
|
||||
#include "starkernel/rng.h"
|
||||
#include "block_subsystem.h" /* compute_crc64() */
|
||||
#include "blkio.h"
|
||||
#include "log.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -66,6 +67,80 @@ static int write_devblock(struct blkio_dev *dev, uint32_t devblock,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read exactly one devblock (4096 bytes) at devblock offset `devblock`,
|
||||
* mirroring write_devblock() above -- used only by the post-write
|
||||
* verification pass (2026-09-06), to read back what was just written
|
||||
* rather than trusting blkio_write()'s BLK_OK return alone. */
|
||||
static int read_devblock(struct blkio_dev *dev, uint32_t devblock,
|
||||
uint8_t *buf4096) {
|
||||
uint32_t base = devblock * 4u;
|
||||
for (uint32_t i = 0; i < 4u; i++) {
|
||||
if (blkio_read((blkio_dev_t *)dev, base + i,
|
||||
buf4096 + (size_t)i * BLKIO_FORTH_BLOCK_SIZE) != BLKIO_OK) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Post-write verification (2026-09-06, direct instruction after a live
|
||||
* xHCI enumeration failure raised the question of whether MINT itself
|
||||
* could silently succeed without the data actually being readable back):
|
||||
* re-reads the identity record and re-runs homeblocks_sig_check() --
|
||||
* the exact same check a real attach later performs -- instead of trusting
|
||||
* every write_devblock() call's own BLK_OK return as proof the drive will
|
||||
* actually read back correctly. blkio_write() succeeding only means the
|
||||
* BOT command chain completed; it says nothing about whether those bytes
|
||||
* survive to be read back under real hardware/emulation conditions.
|
||||
* Logged entirely through log_message() -- LOG_ERROR with the specific
|
||||
* mismatch on failure, LOG_INFO confirming success -- not console_println,
|
||||
* so this doesn't add unconditional console/serial noise to every mint;
|
||||
* the MINT word's own caller (mama_forth_words.c) still reports the final
|
||||
* pass/fail result to the console either way via its existing console_
|
||||
* println() switch. Returns 0 if everything reads back correctly, -1
|
||||
* otherwise. */
|
||||
static int verify_mint(struct blkio_dev *dev, uint32_t identity_src_offset,
|
||||
const user_identity_seed_t *written_idrec) {
|
||||
homeblocks_sig_t verify_sig;
|
||||
homeblocks_sig_result_t sig_rc =
|
||||
homeblocks_sig_check(dev, HOMEBLOCKS_SIG_START_FBLOCK, &verify_sig);
|
||||
if (sig_rc != HOMEBLOCKS_SIG_OK) {
|
||||
log_message(LOG_ERROR,
|
||||
"MINT verify: homeblocks_sig_check() did not read back OK (rc=%d)",
|
||||
(int) sig_rc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t readback_block[4096];
|
||||
if (read_devblock(dev, identity_src_offset, readback_block) != 0) {
|
||||
log_message(LOG_ERROR, "MINT verify: identity record read-back failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const user_identity_seed_t *readback_idrec =
|
||||
(const user_identity_seed_t *) readback_block;
|
||||
if (readback_idrec->magic != written_idrec->magic ||
|
||||
readback_idrec->version != written_idrec->version) {
|
||||
log_message(LOG_ERROR,
|
||||
"MINT verify: identity record magic/version mismatch on read-back");
|
||||
return -1;
|
||||
}
|
||||
uint64_t want_crc = compute_crc64((const uint8_t *) readback_idrec,
|
||||
offsetof(user_identity_seed_t, crc));
|
||||
if (want_crc != readback_idrec->crc) {
|
||||
log_message(LOG_ERROR, "MINT verify: identity record CRC mismatch on read-back");
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(readback_idrec, written_idrec, sizeof(*written_idrec)) != 0) {
|
||||
log_message(LOG_ERROR,
|
||||
"MINT verify: identity record content differs from what was written");
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_message(LOG_INFO, "MINT verify: identity reads back correctly");
|
||||
return 0;
|
||||
}
|
||||
|
||||
MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
||||
const char *full_name, const char *username,
|
||||
const char *email, const char *phone,
|
||||
@@ -188,5 +263,9 @@ MintResult capsule_mint_identity(struct blkio_dev *dev, VM *issuer_vm,
|
||||
|
||||
(void)blkio_flush((blkio_dev_t *)dev);
|
||||
|
||||
if (verify_mint(dev, MINT_IDENTITY_SRC_OFFSET, &idrec) != 0) {
|
||||
return MINT_ERR_VERIFY_FAILED;
|
||||
}
|
||||
|
||||
return MINT_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user