Skip to content

ck: checked fork sum in Rust branch-table validation [host PASS] - #232

Merged
aien-dev merged 2 commits into
mainfrom
hive/CK-5-RUSTSUM-fork-sum-overflow
Oct 1, 2026
Merged

aien-dev merged 2 commits into
mainfrom
hive/CK-5-RUSTSUM-fork-sum-overflow

Conversation

@aien-dev

@aien-dev aien-dev commented Oct 1, 2026 •

Copy link
Copy Markdown
Owner

What

Two oracle fixes in AgentState::validate (crates/aienos-kernel/src/continuity.rs) so the Rust oracle (ADR 0024 Q2) refuses what the C codec (#227) refuses.

Commit 1 (09a0bab): checked fork sum

The fork sum used plain .sum() (was :476). Kernel images build with --release and no Cargo profile enables overflow checks (source: ~/handoffs/2026-10-01-CK-5-CODEC-inspector.md, "Builder finding 2"), so the sum wraps. Table {root forks = 2^64-1, child index 0 forks = 2} summed to 1 == children and was accepted by Rust release, while C refuses it.

Fix: try_fold(0u64, |acc, b| acc.checked_add(b.forks)); refusal ContinuityError::Corrupt("fork indexes are not contiguous"), the same class and text as C fail(why, CC_E_CORRUPT, "fork indexes are not contiguous") at native/kernel/svc/continuity_codec.c:482-491 (branch hive/CK-5-CODEC-continuity-codec).

Commit 2 (214527f): cap the lineage index scan

validate scanned 0..parent.forks with no bound (was :468, inspector finding 1). forks is input-controlled, so a table with forks = 2^64-1 and a child id that is no derived index made Rust spin for ~2^64 hashes. The scan is now capped at MAX_BRANCHES (256) exactly as C does (continuity_codec.c:468); such a child is refused Corrupt("branch lineage is inconsistent"), C's class and text (continuity_codec.c:474-479). A valid table has every forks <= 255, so no valid outcome changes. Difference from old Rust: a child at index >= 256 under a huge parent used to be refused later as "fork indexes are not contiguous"; it now gets the lineage text, matching C. Implemented as a cap (C's approach) rather than a refusal before the loop, because an early refusal would give a different reason text than C for a huge-forks parent whose child sits at a low index.

Tests (continuity_tests.rs)

  • wrapping_fork_sum_is_refused_like_the_c_codec: hostile wrap table refused via validate() and via decode() of patched honest bytes (layout asserted before patching); honest bytes still decode.
  • branch_table_at_the_maximum_legal_fork_sum_is_accepted: 256 rows (root + 255 children, fork sum 255) validates and round-trips; a 257th fork is Limit("too many branches").
  • huge_fork_count_with_underivable_child_is_refused_without_spinning: forks = 2^64-1 with a rogue child id (asserted not to be any index < 256) refused with the lineage text.

Mutations:

  • Reverting to .sum() makes the wrap test fail under --release (sum wraps to 1, table accepted). In debug the revert panics on overflow instead, so the release run is the one that proves the wrap case.
  • Removing the scan cap makes the huge-fork test hang (~2^64 hashes).

Other arithmetic on decoded counts/lengths (continuity.rs, recovery_core.rs)

  • continuity.rs:118 bytes.len() - HEADER_BYTES: safe, 16 header bytes already taken.
  • continuity.rs fork() index + 1 (:382 before this PR): unchanged. C does the same unguarded add (continuity_codec.c:516); after commit 1 any validated/decoded table has every forks <= 255, so unreachable from decoded input.
  • continuity.rs manifest loop i as u64 + 1: i < manifests.len(), safe.
  • continuity.rs provision() store.generation() + 1 (:738 before this PR): left unchanged on purpose. At u64::MAX it wraps in release, but transact then refuses cleanly with GenerationExhausted and zero writes (store/engine.rs:418, test :1201-1211); debug would panic.
  • recovery_core.rs:169 entries.len() - roots - manifests: disjoint filter counts, safe. :251 1 - active: slot_id checked <= 1 at decode (store/v1.rs:550).

Evidence

All four runs are host unit runs on the light lane, and all four ran on PR head 214527f. Run 1 was queued before commit 2 but executed after it was pushed: its logs list huge_fork_count_with_underivable_child_is_refused_without_spinning. Each log reports 13 passed; 0 failed and lists all three new tests (forge receipt: ~/workspace/test-queue-results.md:196-199).

Run Command Log Result
1 -p aienos-kernel --lib continuity (debug) CK-5-RUSTSUM-light-185736.log host PASS (13/13)
1 -p aienos-kernel --release --lib continuity CK-5-RUSTSUM-light-185741.log host PASS (13/13)
2 RUSTSUM_RUN=2 ... -p aienos-kernel --lib continuity (debug) CK-5-RUSTSUM-light-185745.log host PASS (13/13)
2 RUSTSUM_RUN=2 ... -p aienos-kernel --release --lib continuity (proves the wrap case) CK-5-RUSTSUM-light-185746.log host PASS (13/13)

Logs live in ~/workspace/test-queue-logs/ on the Spark.

Inspector: VERDICT: merge (~/handoffs/2026-10-01-CK-5-RUSTSUM-INSPECT-inspector.md, head 214527f). Both divergences are fixed with C's refusal class and text, each fix has a hostile test that fails on the old code, and the maximum legal table still passes.

QEMU: not applicable. Hardware: NOT_RUN.

No C code, GATES.md or contract doc touched.

🤖 Generated with Claude Code

aien-dev and others added 2 commits October 1, 2026 13:33
The branch-table fork sum used plain `.sum()`. Kernel images build with
--release and no Cargo profile enables overflow checks, so the sum wrapped:
{root forks = 2^64-1, child forks = 2} summed to 1 == children and was
accepted, while the C codec refuses it (continuity_codec.c:482-491 on
hive/CK-5-CODEC-continuity-codec). The Rust oracle (ADR 0024 Q2) now uses
try_fold + checked_add and refuses with the same class and text:
Corrupt("fork indexes are not contiguous").

Tests: hostile wraparound table refused via validate() and decode();
a full table (256 rows, fork sum 255) still validates and round-trips.
Mutation: reverting to `.sum()` makes the hostile-table test fail under
--release (wrap -> accepted).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AgentState::validate scanned 0..parent.forks with no bound; forks is
input-controlled, so a hostile table (forks = 2^64-1, child id not a derived
index) made the Rust oracle spin. The scan is now capped at MAX_BRANCHES,
as C does (continuity_codec.c:468 on hive/CK-5-CODEC-continuity-codec), and
such a child is refused Corrupt("branch lineage is inconsistent"), C's class
and text (continuity_codec.c:474-479). Valid tables have every forks <= 255,
so no valid outcome changes.

Test: huge_fork_count_with_underivable_child_is_refused_without_spinning.
Mutation: removing the cap makes that test hang (~2^64 hashes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aien-dev aien-dev changed the title ck: checked fork sum in Rust branch-table validation [NOT_RUN] ck: checked fork sum in Rust branch-table validation [host PASS] Oct 1, 2026
@aien-dev
aien-dev marked this pull request as ready for review October 1, 2026 19:04
@aien-dev
aien-dev merged commit 5849a7a into main Oct 1, 2026
6 checks passed
@aien-dev
aien-dev deleted the hive/CK-5-RUSTSUM-fork-sum-overflow branch October 1, 2026 19:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant