Skip to content

fix(kernel): reject circular safe definitions and pin IxVM rejection - #637

Merged
arthurpaulino merged 1 commit into
mainfrom
ap/kernel
Sep 17, 2026
Merged

arthurpaulino merged 1 commit into
mainfrom
ap/kernel

Conversation

@arthurpaulino

Copy link
Copy Markdown
Member

The Rust kernel could accept a safe declaration whose value was a reference to itself: looking up the reference returned its declared type without establishing that its definition was well founded. For example, with only P : Prop as an axiom, theorem loop : P := loop was accepted. Raw Ixon can also encode an axiom-free circular definition of forall P : Prop, P, or put the same attack in a singleton or mutually dependent definition block. This is a soundness defect: invalid proofs were accepted.

Port the Rust admission guard from #630 (2f0b47c). Before typechecking a safe definition, traverse definition references in both its type and value, including binder domains, let initializers, shared syntax, and projection heads. Explicit worklists distinguish active declarations from completed ones and reject cycles, including cycles spanning internal blocks. Expression traversal deduplicates shared syntax without recursive host-stack calls. The host traversal fails closed at one million dependency tasks. Axioms, inductives, constructors, and recursors retain their own admission rules; partial and unsafe definitions retain their existing policy.

IxVM is already protected against this attack: ingress gives safe definitions neither a standalone self-reference slot nor mutual peer slots. Add hash-bound Ixon exploit fixtures to demonstrate that protection through the production verify_claim entrypoint, using both the bytecode interpreter and generated executor. Cover self-reference in definitions, theorems, and opaque declarations; mutual cycles; cycles hidden in types, let initializers, and sharing; and misleading theorem/opaque safety bytes. A closed identity proof must be accepted as a positive control. These tests require successful witness construction before checking rejection. No IxVM implementation, generated code, or FFT pin changes are needed.

The Rust unit regressions reproduced acceptance before the fix. They now reject the attacks and cover projection-head dependency collection and preservation of partial/unsafe behavior. The serialized fixtures also run through the Rust checker with hash verification enabled, requiring the cycle diagnostic for invalid targets. Positive Rust controls retain valid acyclic forward references and shared dependencies. Exported structural, well-founded, and mutual recursion fixtures check all 33, 1350, and 26 targets respectively, with no omitted requested definitions. The shared fixtures run in the focused kernel-dependencies runner and the IxVM suite.

Validation:

  • cargo test --locked --release -p ix-kernel: 846 passed, 8 ignored.
  • lake test --wfail -- --ignored kernel-dependencies: 44 checks passed.
  • cargo clippy --locked --release --workspace --all-targets --features ix-ffi/parallel,ix-ffi/net,ix-ffi/test-ffi -- -D warnings: passed.
  • cargo fmt --all -- --check and git diff --check: passed.
  • ix codegen --check: all three generated targets are up to date.

The Rust kernel could accept a safe declaration whose value was a reference
to itself: looking up the reference returned its declared type without
establishing that its definition was well founded. For example, with only
P : Prop as an axiom, `theorem loop : P := loop` was accepted. Raw Ixon can
also encode an axiom-free circular definition of `forall P : Prop, P`, or
put the same attack in a singleton or mutually dependent definition block.
This is a soundness defect: invalid proofs were accepted.

Port the Rust admission guard from #630 (2f0b47c).
Before typechecking a safe definition, traverse definition references in
both its type and value, including binder domains, let initializers,
shared syntax, and projection heads. Explicit worklists distinguish
active declarations from completed ones and reject cycles, including
cycles spanning internal blocks. Expression traversal deduplicates shared
syntax without recursive host-stack calls. The host traversal fails closed
at one million dependency tasks. Axioms, inductives, constructors, and
recursors retain their own admission rules; partial and unsafe definitions
retain their existing policy.

IxVM is already protected against this attack: ingress gives safe
definitions neither a standalone self-reference slot nor mutual peer
slots. Add hash-bound Ixon exploit fixtures to demonstrate that protection
through the production verify_claim entrypoint, using both the bytecode
interpreter and generated executor. Cover self-reference in definitions,
theorems, and opaque declarations; mutual cycles; cycles hidden in types,
let initializers, and sharing; and misleading theorem/opaque safety bytes.
A closed identity proof must be accepted as a positive control. These
tests require successful witness construction before checking rejection.
No IxVM implementation, generated code, or FFT pin changes are needed.

The Rust unit regressions reproduced acceptance before the fix. They now
reject the attacks and cover projection-head dependency collection and
preservation of partial/unsafe behavior. The serialized fixtures also run
through the Rust checker with hash verification enabled, requiring the
cycle diagnostic for invalid targets. Positive Rust controls retain valid
acyclic forward references and shared dependencies. Exported structural,
well-founded, and mutual recursion fixtures check all 33, 1350, and 26
targets respectively, with no omitted requested definitions. The shared
fixtures run in the focused kernel-dependencies runner and the IxVM suite.

Validation:
- cargo test --locked --release -p ix-kernel: 846 passed, 8 ignored.
- lake test --wfail -- --ignored kernel-dependencies: 44 checks passed.
- cargo clippy --locked --release --workspace --all-targets
  --features ix-ffi/parallel,ix-ffi/net,ix-ffi/test-ffi -- -D warnings: passed.
- cargo fmt --all -- --check and git diff --check: passed.
- ix codegen --check: all three generated targets are up to date.

Co-authored-by: John C. Burnham <john@agathic.com>
@arthurpaulino
arthurpaulino added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 0ec538e Sep 17, 2026
14 checks passed
@arthurpaulino
arthurpaulino deleted the ap/kernel branch September 17, 2026 17:01
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.

2 participants