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
|
magic-number content-type detection (Section U item 14, shared with Milestone 4, not
|
||||||
started) and the hard-refuse flip (deliberately deferred).**
|
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
|
### From FABRIC-2.md §X, Milestone 7 — Contributor capsules / trust tiers
|
||||||
|
|
||||||
- [ ] Create the `capsules/contrib/` directory (mechanically trivial, matches existing
|
- [ ] Create the `capsules/contrib/` directory (mechanically trivial, matches existing
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Capsule Block Manifest — Auto-generated
|
# 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. -->
|
<!-- DO NOT EDIT — re-run mkcapsule --manifest to refresh. -->
|
||||||
<!-- Hand-written justifications and immutability notes live -->
|
<!-- Hand-written justifications and immutability notes live -->
|
||||||
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
<!-- in MANIFEST.md alongside this auto-generated index. -->
|
||||||
|
|||||||
@@ -5,13 +5,17 @@
|
|||||||
* signature/behavior stays untouched; this is a new, additive check
|
* signature/behavior stays untouched; this is a new, additive check
|
||||||
* called alongside it, not folded into it.
|
* called alongside it, not folded into it.
|
||||||
*
|
*
|
||||||
* Currently WARN-only, not enforced -- see FABRIC-3.md's Milestone 6
|
* Enforced ONLY on CAPSULE_SIG_INVALID (2026-08-26, after landing
|
||||||
* rollout decision. A bug here has a larger blast radius than most of
|
* WARN-only and proving correct on all three architectures against both
|
||||||
* this project's other checks: a false refusal on Mama's own capsule
|
* a valid and a deliberately-corrupted capsule -- see FABRIC-3.md's
|
||||||
* would mean no `ok>` at all, on any architecture. Land warn-only,
|
* Milestone 6 writeup). CAPSULE_SIG_MISSING and CAPSULE_SIG_NO_ROOT_KEY
|
||||||
* prove correct against both a valid and a deliberately-corrupted
|
* stay WARN-only, deliberately: MISSING is the normal state on every
|
||||||
* capsule on all three architectures, then flip to hard-refuse
|
* machine without access to the offline signing key (CI, any other
|
||||||
* separately.
|
* 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
|
#ifndef STARKERNEL_CAPSULE_SIG_H
|
||||||
#define 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);
|
CapsuleValidateResult vr = capsule_validate(mama_cap, arena, dir->arena_size, 1);
|
||||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
||||||
|
|
||||||
/* Milestone 6 (Phase 8): WARN-only signature check, not yet enforced --
|
/* Milestone 6 (Phase 8): signature check. Enforced ONLY on INVALID (a
|
||||||
* see capsule_sig.h's own doc comment for why (blast radius: a false
|
* signature that IS present but does not verify -- unambiguous
|
||||||
* refusal here means Mama herself never births, no ok> on any arch). */
|
* 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);
|
int idx = (int)(mama_cap - descs);
|
||||||
CapsuleSigResult sr = capsule_verify_signature(
|
CapsuleSigResult sr = capsule_verify_signature(
|
||||||
@@ -426,6 +430,7 @@ CapsuleRunResult capsule_birth_mama(
|
|||||||
if (sr != CAPSULE_SIG_OK) {
|
if (sr != CAPSULE_SIG_OK) {
|
||||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||||
names[idx].name, capsule_sig_result_str(sr));
|
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);
|
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
||||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
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);
|
int idx = (int)(cap - descs);
|
||||||
CapsuleSigResult sr = capsule_verify_signature(
|
CapsuleSigResult sr = capsule_verify_signature(
|
||||||
@@ -496,6 +503,7 @@ CapsuleRunResult capsule_birth_baby(
|
|||||||
if (sr != CAPSULE_SIG_OK) {
|
if (sr != CAPSULE_SIG_OK) {
|
||||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||||
names[idx].name, capsule_sig_result_str(sr));
|
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);
|
CapsuleValidateResult vr = capsule_validate(cap, arena, dir->arena_size, 1);
|
||||||
if (vr != CAPSULE_VALID) return CAPSULE_RUN_ERR_INVALID;
|
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);
|
int idx = (int)(cap - descs);
|
||||||
CapsuleSigResult sr = capsule_verify_signature(
|
CapsuleSigResult sr = capsule_verify_signature(
|
||||||
@@ -642,6 +652,7 @@ CapsuleRunResult capsule_run_experiment(
|
|||||||
if (sr != CAPSULE_SIG_OK) {
|
if (sr != CAPSULE_SIG_OK) {
|
||||||
log_message(LOG_WARN, "capsule sig: %s: %s",
|
log_message(LOG_WARN, "capsule sig: %s: %s",
|
||||||
names[idx].name, capsule_sig_result_str(sr));
|
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