fix(agent): make Endian::u32/i32 total in the BTF parser (ADR-0014) - #336
Merged
thejefflarson merged 1 commit intoAug 8, 2026
Conversation
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
enabled auto-merge (squash)
August 8, 2026 21:21
thejefflarson
deleted the
thejefflarson/jef-782-btf-parser-make-endianu32-total-never-expect-panic-on-the
branch
August 8, 2026 21:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
agent/protector-agent/src/preflight/btf.rs'sEndian::u32didb.try_into().expect("4-byte slice")on blob-derived slices — the oneexpect-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/vmlinuxinto an agent crash-loop instead of a fail-closed preflight.What changed
Endian::u32now returnsResult<u32, BtfParseError>, usingb.get(..4).ok_or(BtfParseError::Truncated)?.try_into().unwrap()— theget(..4)bounds-checks the length, making the followingtry_intoinfallible-by-construction rather than a panic risk.Endian::i32(which delegates tou32) follows the same signature change.RawBtf::parse's header read, 8 acrossparse_types's type-prefix/struct/union/enum/enum64 reads) now propagate with?— they already sit inside functions returningResult<_, BtfParseError>that fold tofail_closed()at the caller, so this threads cleanly with no other signature changes.u16/u64aren't read directly — enum64's 64-bit value is composed from twou32reads 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 thatEndian::u32/i32returnErr(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 existingBtfBuilderfixture, truncates it a couple of bytes into the type section (landing mid-integer), and confirmsRawBtf::parsereturnsErr(BtfParseError::Truncated)rather than panicking.preflight::btftests pass unchanged (happy-path behavior preserved).How I tested
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