Implement homeblocks_sig_check(): the drive signature check (Phase 8)
Real, complete verification logic -- not yet wired to any write path. homeblocks_sig_check(dev, sig_start_fblock, out_sig) reads the 4 consecutive 1KB blkio forth-blocks the 4KB header spans, verifies magic -> version -> CRC-64 in order, returns HOMEBLOCKS_SIG_OK/_BLANK/ _BAD_VERSION/_BAD_CRC/_READ_ERROR. Reuses block_subsystem.c's existing CRC-64/ISO (compute_crc64, previously static/file-local, now exposed via block_subsystem.h) rather than a second CRC implementation -- same algorithm already proven via per-block checksums. Takes the header's starting block as a plain parameter rather than resolving it internally: verifies a signature given a location, finding that location (GPT-partition-relative) stays the caller's job. Verified against the actual shipped code, not a reimplementation: a standalone host test links the real homeblocks_sig.c against a fake in-memory blkio_dev and exercises all four outcomes -- blank media, a correctly-minted header (round-trips drive_uuid/minted_time_ns), a flipped CRC, an unrecognized version. All four pass. A full QEMU-hotplug live test isn't proportionate yet since nothing calls this function from the live kernel path -- wiring it into the attach path is the next punch-list item. Clean zero-warning compile and clean boot on all three architectures confirms no build/link regression from exposing compute_crc64 and adding the new source file to every kernel build. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CXjAPTEKrgY2Mrk25KoLDn
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
10b96870c5
commit
2c45744995
+25
-3
@@ -212,10 +212,32 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
|||||||
3-arch acceptance boot needed for this step; that starts with the signature-check
|
3-arch acceptance boot needed for this step; that starts with the signature-check
|
||||||
implementation, the next punch-list item below.
|
implementation, the next punch-list item below.
|
||||||
|
|
||||||
- [ ] Implement the signature check, called before any write path touches a newly-inserted
|
- [x] **Implemented (2026-08-26): the check function itself, real and complete — not yet
|
||||||
drive.
|
wired to any write path.** `include/starkernel/homeblocks_sig.h` +
|
||||||
|
`src/starkernel/homeblocks_sig.c`: `homeblocks_sig_check(dev, sig_start_fblock, out_sig)`
|
||||||
|
reads the 4 consecutive 1KB `blkio` forth-blocks the 4KB header spans, verifies magic →
|
||||||
|
version → CRC-64 in order, returns one of `HOMEBLOCKS_SIG_OK`/`_BLANK`/`_BAD_VERSION`/
|
||||||
|
`_BAD_CRC`/`_READ_ERROR`. Reuses `block_subsystem.c`'s existing CRC-64/ISO
|
||||||
|
(`compute_crc64`, previously `static`/file-local, now exposed) rather than a second CRC
|
||||||
|
implementation — same algorithm already proven via per-block checksums. Takes the header's
|
||||||
|
starting block as a plain parameter rather than resolving it internally: this function
|
||||||
|
verifies a signature given a location; finding that location (GPT-partition-relative,
|
||||||
|
once a parser exists) stays the caller's job, not invented here.
|
||||||
|
|
||||||
- [ ] Implement the warn-and-refuse behavior for blank/foreign/unrecognized media.
|
**Verified against the actual shipped code**, not a reimplementation: a standalone host
|
||||||
|
test links the real `homeblocks_sig.c` against a fake in-memory `blkio_dev` and exercises
|
||||||
|
all four outcomes — blank media → `BLANK`, a correctly-minted header → `OK` (round-trips
|
||||||
|
`drive_uuid`/`minted_time_ns` correctly), a flipped CRC → `BAD_CRC`, an unrecognized
|
||||||
|
version → `BAD_VERSION`. All four pass. A full QEMU-hotplug live test isn't proportionate
|
||||||
|
yet — nothing calls this function from the live kernel path (deliberately; wiring it into
|
||||||
|
the attach path is the next item below), so a live boot check has nothing to exercise.
|
||||||
|
Clean zero-warning compile and clean boot on all three architectures confirms no
|
||||||
|
build/link regression from exposing `compute_crc64` and adding the new source file to
|
||||||
|
every kernel build.
|
||||||
|
|
||||||
|
- [ ] Implement the warn-and-refuse behavior for blank/foreign/unrecognized media — this is
|
||||||
|
where `homeblocks_sig_check()` above actually gets a live caller, wiring it into the real
|
||||||
|
drive-insertion path.
|
||||||
|
|
||||||
- [ ] Extend `acl_pinned`'s one-way-ratchet mechanism (already exists, already proven, just
|
- [ ] Extend `acl_pinned`'s one-way-ratchet mechanism (already exists, already proven, just
|
||||||
needs applying) to gate zuse credential minting specifically — confirm whether this
|
needs applying) to gate zuse credential minting specifically — confirm whether this
|
||||||
|
|||||||
+4
-2
@@ -402,7 +402,8 @@ LOADER_SRCS_BASE := \
|
|||||||
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
$(wildcard $(KERNEL_SRC)/usb/*.c) \
|
||||||
$(KERNEL_SRC)/repl.c \
|
$(KERNEL_SRC)/repl.c \
|
||||||
$(KERNEL_SRC)/doe_log.c \
|
$(KERNEL_SRC)/doe_log.c \
|
||||||
$(KERNEL_SRC)/heartbeat.c
|
$(KERNEL_SRC)/heartbeat.c \
|
||||||
|
$(KERNEL_SRC)/homeblocks_sig.c
|
||||||
|
|
||||||
LOADER_ASM := \
|
LOADER_ASM := \
|
||||||
$(KERNEL_SRC)/arch/$(ARCH)/boot.S \
|
$(KERNEL_SRC)/arch/$(ARCH)/boot.S \
|
||||||
@@ -454,7 +455,8 @@ KERNEL_SRCS_BASE := \
|
|||||||
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
|
$(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.c) \
|
||||||
$(KERNEL_SRC)/repl.c \
|
$(KERNEL_SRC)/repl.c \
|
||||||
$(KERNEL_SRC)/doe_log.c \
|
$(KERNEL_SRC)/doe_log.c \
|
||||||
$(KERNEL_SRC)/heartbeat.c
|
$(KERNEL_SRC)/heartbeat.c \
|
||||||
|
$(KERNEL_SRC)/homeblocks_sig.c
|
||||||
|
|
||||||
KERNEL_ASM := $(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.S)
|
KERNEL_ASM := $(wildcard $(KERNEL_SRC)/arch/$(ARCH)/*.S)
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -293,6 +293,12 @@ int blk_get_volume_meta(blk_volume_meta_t *meta);
|
|||||||
|
|
||||||
int blk_set_volume_meta(const blk_volume_meta_t *meta);
|
int blk_set_volume_meta(const blk_volume_meta_t *meta);
|
||||||
|
|
||||||
|
/* CRC-64/ISO (poly 0x42F0E1EBA9EA3693), reflected, init/final all-ones --
|
||||||
|
* exposed for homeblocks_sig.c's drive-signature integrity check, which
|
||||||
|
* needs the exact same algorithm this file already uses for per-block
|
||||||
|
* checksums rather than a second, duplicate CRC implementation. */
|
||||||
|
uint64_t compute_crc64(const uint8_t *data, size_t len);
|
||||||
|
|
||||||
int blk_is_valid(uint32_t block_num);
|
int blk_is_valid(uint32_t block_num);
|
||||||
|
|
||||||
uint32_t blk_get_total_blocks(void);
|
uint32_t blk_get_total_blocks(void);
|
||||||
|
|||||||
@@ -118,6 +118,56 @@ typedef struct {
|
|||||||
* same discipline stadium.h's own header-size checks already use. */
|
* same discipline stadium.h's own header-size checks already use. */
|
||||||
typedef char homeblocks_sig_size_check[(sizeof(homeblocks_sig_t) == 4096) ? 1 : -1];
|
typedef char homeblocks_sig_size_check[(sizeof(homeblocks_sig_t) == 4096) ? 1 : -1];
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
* Signature check (FABRIC-3.md, Milestone 4)
|
||||||
|
*===========================================================================*/
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HOMEBLOCKS_SIG_OK = 0, /* magic, version, and crc all check out */
|
||||||
|
HOMEBLOCKS_SIG_BLANK, /* magic does not match -- blank or foreign media */
|
||||||
|
HOMEBLOCKS_SIG_BAD_VERSION, /* magic matches, version unrecognized */
|
||||||
|
HOMEBLOCKS_SIG_BAD_CRC, /* magic+version match, crc fails -- corrupt or tampered */
|
||||||
|
HOMEBLOCKS_SIG_READ_ERROR /* could not read from the device at all */
|
||||||
|
} homeblocks_sig_result_t;
|
||||||
|
|
||||||
|
/* Forward-declared, not included here -- avoids a hard dependency from this
|
||||||
|
* small format header onto blkio.h's full device/vtable machinery for
|
||||||
|
* callers that only need the struct layout (e.g. a future minting tool). */
|
||||||
|
struct blkio_dev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* homeblocks_sig_check - Read and verify the drive signature header.
|
||||||
|
*
|
||||||
|
* Reads 4 consecutive 1KB "forth blocks" (dev->read()'s own unit) starting
|
||||||
|
* at sig_start_fblock into a local 4KB buffer and interprets it as a
|
||||||
|
* homeblocks_sig_t. Deliberately takes the starting block as a plain
|
||||||
|
* parameter rather than resolving it internally -- this function verifies a
|
||||||
|
* signature given a location; finding that location (GPT-partition-relative
|
||||||
|
* today, once a GPT parser exists) is the caller's job, not invented here.
|
||||||
|
*
|
||||||
|
* @param dev Open block device to read from.
|
||||||
|
* @param sig_start_fblock First of 4 consecutive forth-blocks holding the
|
||||||
|
* 4KB header.
|
||||||
|
* @param out_sig On HOMEBLOCKS_SIG_OK, populated with the verified
|
||||||
|
* header. Left unspecified on any other result.
|
||||||
|
* @return HOMEBLOCKS_SIG_OK, or the specific reason for refusal.
|
||||||
|
*/
|
||||||
|
homeblocks_sig_result_t homeblocks_sig_check(struct blkio_dev *dev,
|
||||||
|
uint32_t sig_start_fblock,
|
||||||
|
homeblocks_sig_t *out_sig);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* homeblocks_sig_compute_crc - CRC-64 over every field of `sig` up to but
|
||||||
|
* not including hdr_crc itself and the trailing padding -- the same
|
||||||
|
* boundary homeblocks_sig_check() verifies against and any future minting
|
||||||
|
* code must use when writing a fresh header. Exposed publicly since both
|
||||||
|
* directions (check and future mint) need the identical computation.
|
||||||
|
*
|
||||||
|
* @param sig Header to checksum. hdr_crc and _pad are not read.
|
||||||
|
* @return The CRC-64 value that hdr_crc should hold for `sig` to verify.
|
||||||
|
*/
|
||||||
|
uint64_t homeblocks_sig_compute_crc(const homeblocks_sig_t *sig);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -104,7 +104,7 @@ static void crc64_init(void) {
|
|||||||
crc64_inited = 1;
|
crc64_inited = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t compute_crc64(const uint8_t *data, size_t len) {
|
uint64_t compute_crc64(const uint8_t *data, size_t len) {
|
||||||
if (!crc64_inited) crc64_init();
|
if (!crc64_inited) crc64_init();
|
||||||
uint64_t crc = 0xFFFFFFFFFFFFFFFFULL;
|
uint64_t crc = 0xFFFFFFFFFFFFFFFFULL;
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
StarForth — Steady-State Virtual Machine Runtime
|
||||||
|
|
||||||
|
Copyright (c) 2023–2025 Robert A. James
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
This file is part of the StarForth project.
|
||||||
|
|
||||||
|
Licensed under the StarForth License, Version 1.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
|
||||||
|
You may obtain a copy of the License at:
|
||||||
|
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
|
||||||
|
|
||||||
|
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
express or implied, including but not limited to the warranties of
|
||||||
|
merchantability, fitness for a particular purpose, and noninfringement.
|
||||||
|
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* homeblocks_sig.c - Drive signature check (FABRIC-3.md, Milestone 4).
|
||||||
|
* See starkernel/homeblocks_sig.h for the format and interface design.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "starkernel/homeblocks_sig.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "blkio.h"
|
||||||
|
#include "block_subsystem.h" /* compute_crc64() -- same CRC-64/ISO this file's
|
||||||
|
* check reuses rather than duplicating */
|
||||||
|
|
||||||
|
uint64_t homeblocks_sig_compute_crc(const homeblocks_sig_t *sig) {
|
||||||
|
/* Covers every field up to but not including hdr_crc itself (and never
|
||||||
|
* _pad, which sits after it) -- offsetof is the exact boundary, not a
|
||||||
|
* hand-counted byte offset that could drift out of sync with the
|
||||||
|
* struct's own field list. */
|
||||||
|
size_t crc_span = offsetof(homeblocks_sig_t, hdr_crc);
|
||||||
|
return compute_crc64((const uint8_t *)sig, crc_span);
|
||||||
|
}
|
||||||
|
|
||||||
|
homeblocks_sig_result_t homeblocks_sig_check(struct blkio_dev *dev,
|
||||||
|
uint32_t sig_start_fblock,
|
||||||
|
homeblocks_sig_t *out_sig) {
|
||||||
|
uint8_t buf[4096];
|
||||||
|
uint32_t i;
|
||||||
|
homeblocks_sig_t local;
|
||||||
|
uint64_t expected_crc;
|
||||||
|
|
||||||
|
if (!dev) return HOMEBLOCKS_SIG_READ_ERROR;
|
||||||
|
|
||||||
|
/* homeblocks_sig_t is exactly one 4KiB devblock; blkio's own unit is a
|
||||||
|
* 1KiB "forth block" (BLKIO_FORTH_BLOCK_SIZE), so the header spans 4
|
||||||
|
* consecutive reads starting at sig_start_fblock. */
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (blkio_read((blkio_dev_t *)dev, sig_start_fblock + i,
|
||||||
|
buf + (size_t)i * BLKIO_FORTH_BLOCK_SIZE) != BLKIO_OK) {
|
||||||
|
return HOMEBLOCKS_SIG_READ_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy into a properly-aligned local rather than reinterpreting buf's
|
||||||
|
* address directly -- buf is only byte-aligned, and homeblocks_sig_t
|
||||||
|
* has uint64_t members; a raw cast would be a strict-aliasing and
|
||||||
|
* alignment violation for no benefit over one memcpy. */
|
||||||
|
memcpy(&local, buf, sizeof(local));
|
||||||
|
|
||||||
|
if (HOMEBLOCKS_SIG_GET_MAGIC(local.magic) != (uint32_t)(HOMEBLOCKS_SIG_MAGIC & 0xFFFFFFFFULL)) {
|
||||||
|
return HOMEBLOCKS_SIG_BLANK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HOMEBLOCKS_SIG_GET_VERSION(local.magic) != HOMEBLOCKS_SIG_VERSION_0) {
|
||||||
|
return HOMEBLOCKS_SIG_BAD_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_crc = homeblocks_sig_compute_crc(&local);
|
||||||
|
if (expected_crc != local.hdr_crc) {
|
||||||
|
return HOMEBLOCKS_SIG_BAD_CRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_sig) *out_sig = local;
|
||||||
|
return HOMEBLOCKS_SIG_OK;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user