Skip to content

fix(agent): make Endian::u32/i32 total in the BTF parser (ADR-0014) - #336

Merged
thejefflarson merged 1 commit into
mainfrom
thejefflarson/jef-782-btf-parser-make-endianu32-total-never-expect-panic-on-the
Aug 8, 2026
Merged

fix(agent): make Endian::u32/i32 total in the BTF parser (ADR-0014)#336
thejefflarson merged 1 commit into
mainfrom
thejefflarson/jef-782-btf-parser-make-endianu32-total-never-expect-panic-on-the

Conversation

@thejefflarson

Copy link
Copy Markdown
Owner

Summary

agent/protector-agent/src/preflight/btf.rs's Endian::u32 did b.try_into().expect("4-byte slice") on blob-derived slices — the one expect-panic on the untrusted-blob parse path. Unreachable today (all ~12 callers pass length-guarded 4-byte subslices), but the parser's ADR-0014 contract is never panic on the blob; degrade gracefully (fail-closed). A future wrong-sized caller would turn a malformed/truncated /sys/kernel/btf/vmlinux into an agent crash-loop instead of a fail-closed preflight.

What changed

  • Endian::u32 now returns Result<u32, BtfParseError>, using b.get(..4).ok_or(BtfParseError::Truncated)?.try_into().unwrap() — the get(..4) bounds-checks the length, making the following try_into infallible-by-construction rather than a panic risk.
  • Endian::i32 (which delegates to u32) follows the same signature change.
  • All 13 call sites (5 in RawBtf::parse's header read, 8 across parse_types's type-prefix/struct/union/enum/enum64 reads) now propagate with ? — they already sit inside functions returning Result<_, BtfParseError> that fold to fail_closed() at the caller, so this threads cleanly with no other signature changes.
  • No other fixed-width readers exist in the file (u16/u64 aren't read directly — enum64's 64-bit value is composed from two u32 reads already covered above).

Behavior on a well-formed blob is unchanged — only a malformed/short blob now yields a fail-closed preflight instead of a panic.

Tests

  • endian_u32_and_i32_are_total_on_a_too_short_slice — direct test that Endian::u32/i32 return Err(BtfParseError::Truncated) on slices shorter than 4 bytes (including empty), never panic.
  • a_blob_truncated_mid_integer_fails_closed_without_panicking — builds a well-formed blob with the existing BtfBuilder fixture, truncates it a couple of bytes into the type section (landing mid-integer), and confirms RawBtf::parse returns Err(BtfParseError::Truncated) rather than panicking.
  • All 13 pre-existing preflight::btf tests pass unchanged (happy-path behavior preserved).

How I tested

cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test          # agent workspace — 64 + 10 tests pass

All green. Ran /soundcheck:pr-review (no Critical/High findings — this is a pure userspace parser hardening, no user-input/network/credential/injection surface) and /simplify (diff already minimal, no changes applied) before opening this PR.

Closes JEF-782

🤖 Generated with Claude Code

Endian::u32 did b.try_into().expect("4-byte slice") on blob-derived
slices — the one expect-panic on the untrusted-blob parse path.
Unreachable today (all callers pass length-guarded 4-byte subslices),
but ADR-0014's contract is never panic on the blob, degrade
gracefully. A future wrong-sized caller would turn a malformed or
truncated /sys/kernel/btf/vmlinux into an agent crash-loop instead of
a fail-closed preflight.

Make Endian::u32 (and i32, which delegates to it) return
Result<_, BtfParseError>, using the existing BtfParseError::Truncated
variant, and thread the Result through all 13 call sites with `?` —
they already sit inside functions returning the parser's error type
and fold to fail_closed(). Well-formed BTF blobs parse identically;
only a malformed/short blob now yields a fail-closed preflight
instead of a panic.

Adds a direct totality test for Endian::u32/i32 on too-short slices,
plus a blob-level regression test (built with the existing
BtfBuilder fixture, then truncated mid-integer) confirming
RawBtf::parse fails closed rather than panicking.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VtjoJttCvBY4dzCoE4f9vP
@thejefflarson
thejefflarson enabled auto-merge (squash) August 8, 2026 21:21
@thejefflarson
thejefflarson merged commit 0e93a71 into main Aug 8, 2026
7 checks passed
@thejefflarson
thejefflarson deleted the thejefflarson/jef-782-btf-parser-make-endianu32-total-never-expect-panic-on-the branch August 8, 2026 21:29
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