Milestone 6: hard-refuse flip, scoped to INVALID only -- closes Milestone 6
Before flipping, found CAPSULE_SIG_MISSING (no signature at all) is the normal state everywhere except this machine -- CI and any other checkout have no access to the offline key, by design. Refusing on MISSING the same as INVALID would brick boot everywhere but here. Decided (on request): enforce ONLY on CAPSULE_SIG_INVALID (a signature that IS present but doesn't verify -- unambiguous tampering/corruption evidence). MISSING/NO_ROOT_KEY stay WARN-only permanently. All three capsule_birth.c call sites now return CAPSULE_RUN_ERR_INVALID on CAPSULE_SIG_INVALID, after logging the same WARN as before. Verified on all three architectures, both directions, per the original rollout commitment: positive case (real signed capsules) reboots clean with zero warnings on amd64/aarch64/riscv64. Negative case (same one-byte signature corruption used for the WARN-only proof, on Mama's own init.4th) now genuinely refuses identically on all three: "capsule sig: init.4th: INVALID" then "Init: Mama birth FAILED". The feared "no ok> at all" blast radius didn't materialize -- kernel_main.c already had graceful error handling for a failed Mama birth (log and continue, pre-existing code); the kernel reaches a degraded ok> rather than crashing, on all three architectures. Final acceptance pass (real signed capsules, tampering reverted) clean on all three. Milestone 6 is now fully closed except magic-number content-type detection (shared with Milestone 4, separate scope, not started). 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:
co-authored by
Claude Sonnet 5
parent
c640f99211
commit
030a3e6dc0
+26
@@ -823,6 +823,32 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
magic-number content-type detection (Section U item 14, shared with Milestone 4, not
|
||||
started) and the hard-refuse flip (deliberately deferred).**
|
||||
|
||||
**Hard-refuse flip, done 2026-08-26 -- and it landed narrower than the original plan
|
||||
assumed.** Before flipping, found that `CAPSULE_SIG_MISSING` (no signature at all) is the
|
||||
*normal* state on every machine except this one -- CI and any other checkout have no access
|
||||
to the offline key, by design. Refusing on `MISSING` the same as `INVALID` would brick boot
|
||||
everywhere but here, not catch anything real. **Decided (on request): enforce ONLY on
|
||||
`CAPSULE_SIG_INVALID`** (a signature that IS present but doesn't verify -- unambiguous
|
||||
tampering/corruption evidence, safe to refuse on regardless of who's building).
|
||||
`MISSING`/`NO_ROOT_KEY` stay WARN-only permanently, not as a transitional state.
|
||||
|
||||
All three `capsule_birth.c` call sites now `return CAPSULE_RUN_ERR_INVALID` on
|
||||
`CAPSULE_SIG_INVALID`, after logging the same WARN as before. **Verified on all three
|
||||
architectures, both directions, exactly per the original rollout commitment:** the positive
|
||||
case (real signed capsules) reboots clean with zero warnings on amd64/aarch64/riscv64,
|
||||
identical to before this flip. The negative case (the same one-byte signature corruption
|
||||
technique used for the WARN-only proof, on Mama's own `init.4th`) now genuinely refuses --
|
||||
`capsule_birth_mama()` returns the error -- on all three architectures identically:
|
||||
`capsule sig: init.4th: INVALID` followed by `Init: Mama birth FAILED`. **The feared "no
|
||||
ok> at all" blast radius didn't materialize**: `kernel_main.c` already had graceful
|
||||
error handling for a failed Mama birth (log and continue, pre-existing code, not written for
|
||||
this feature) -- the kernel reaches a degraded `ok>` rather than crashing or hanging, on all
|
||||
three architectures. Final acceptance pass (real, correctly-signed capsules, all tampering
|
||||
reverted) clean on all three, zero warnings, conservation intact, real disk untouched.
|
||||
|
||||
**Milestone 6 is now fully closed** except magic-number content-type detection (shared with
|
||||
Milestone 4, genuinely separate scope, not started).
|
||||
|
||||
### From FABRIC-2.md §X, Milestone 7 — Contributor capsules / trust tiers
|
||||
|
||||
- [ ] Create the `capsules/contrib/` directory (mechanically trivial, matches existing
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Capsule Block Manifest — Auto-generated
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-27T01:40:17Z -->
|
||||
<!-- Generated by mkcapsule --manifest 2026-08-27T02:05:00Z -->
|
||||
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||
<!-- Hand-written justifications and immutability notes live -->
|
||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
* signature/behavior stays untouched; this is a new, additive check
|
||||
* called alongside it, not folded into it.
|
||||
*
|
||||
* Currently WARN-only, not enforced -- see FABRIC-3.md's Milestone 6
|
||||
* rollout decision. A bug here has a larger blast radius than most of
|
||||
* this project's other checks: a false refusal on Mama's own capsule
|
||||
* would mean no `ok>` at all, on any architecture. Land warn-only,
|
||||
* prove correct against both a valid and a deliberately-corrupted
|
||||
* capsule on all three architectures, then flip to hard-refuse
|
||||
* separately.
|
||||
* Enforced ONLY on CAPSULE_SIG_INVALID (2026-08-26, after landing
|
||||
* WARN-only and proving correct on all three architectures against both
|
||||
* a valid and a deliberately-corrupted capsule -- see FABRIC-3.md's
|
||||
* Milestone 6 writeup). CAPSULE_SIG_MISSING and CAPSULE_SIG_NO_ROOT_KEY
|
||||
* stay WARN-only, deliberately: MISSING is the normal state on every
|
||||
* machine without access to the offline signing key (CI, any other
|
||||
* checkout) -- refusing on it would brick boot everywhere but the one
|
||||
* machine that minted the key, not catch anything real. Only INVALID
|
||||
* (a signature that IS present but does not verify) is unambiguous
|
||||
* tampering/corruption evidence, safe to refuse on regardless of who's
|
||||
* building.
|
||||
*/
|
||||
#ifndef STARKERNEL_CAPSULE_SIG_H
|
||||
#define STARKERNEL_CAPSULE_SIG_H
|
||||
|
||||
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
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
File diff suppressed because it is too large
Load Diff
@@ -416,9 +416,13 @@ CapsuleRunResult capsule_birth_mama(
|
||||
CapsuleValidateResult vr = capsule_validate(mama_cap, arena, dir->arena_size, 1);
|
||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
/* Milestone 6 (Phase 8): WARN-only signature check, not yet enforced --
|
||||
* see capsule_sig.h's own doc comment for why (blast radius: a false
|
||||
* refusal here means Mama herself never births, no ok> on any arch). */
|
||||
/* Milestone 6 (Phase 8): signature check. Enforced ONLY on INVALID (a
|
||||
* signature that IS present but does not verify -- unambiguous
|
||||
* tampering/corruption evidence). MISSING and NO_ROOT_KEY stay
|
||||
* WARN-only: MISSING is the normal state on every machine without
|
||||
* access to the offline signing key (CI, any other checkout) --
|
||||
* refusing on it would brick boot everywhere but the one machine
|
||||
* that minted this key, not catch anything real. See capsule_sig.h. */
|
||||
{
|
||||
int idx = (int)(mama_cap - descs);
|
||||
CapsuleSigResult sr = capsule_verify_signature(
|
||||
@@ -426,6 +430,7 @@ CapsuleRunResult capsule_birth_mama(
|
||||
if (sr != CAPSULE_SIG_OK) {
|
||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||
names[idx].name, capsule_sig_result_str(sr));
|
||||
if (sr == CAPSULE_SIG_INVALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +493,9 @@ CapsuleRunResult capsule_birth_baby(
|
||||
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
/* Milestone 6 (Phase 8): WARN-only, see capsule_sig.h. */
|
||||
/* Milestone 6 (Phase 8): enforced only on INVALID -- see the fuller
|
||||
* comment in capsule_birth_mama() above for why MISSING/NO_ROOT_KEY
|
||||
* stay WARN-only. */
|
||||
{
|
||||
int idx = (int)(cap - descs);
|
||||
CapsuleSigResult sr = capsule_verify_signature(
|
||||
@@ -496,6 +503,7 @@ CapsuleRunResult capsule_birth_baby(
|
||||
if (sr != CAPSULE_SIG_OK) {
|
||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||
names[idx].name, capsule_sig_result_str(sr));
|
||||
if (sr == CAPSULE_SIG_INVALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +642,9 @@ CapsuleRunResult capsule_run_experiment(
|
||||
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
|
||||
/* Milestone 6 (Phase 8): WARN-only, see capsule_sig.h. */
|
||||
/* Milestone 6 (Phase 8): enforced only on INVALID -- see the fuller
|
||||
* comment in capsule_birth_mama() above for why MISSING/NO_ROOT_KEY
|
||||
* stay WARN-only. */
|
||||
{
|
||||
int idx = (int)(cap - descs);
|
||||
CapsuleSigResult sr = capsule_verify_signature(
|
||||
@@ -642,6 +652,7 @@ CapsuleRunResult capsule_run_experiment(
|
||||
if (sr != CAPSULE_SIG_OK) {
|
||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||
names[idx].name, capsule_sig_result_str(sr));
|
||||
if (sr == CAPSULE_SIG_INVALID) return CAPSULE_RUN_ERR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user