Skip to content

security: cap untrusted-length allocations, add cargo-fuzz harness, fix overflow panics#32

Merged
Nathan-D-R merged 2 commits into
mainfrom
security/cap-allocations-and-fuzz
Jul 19, 2026
Merged

security: cap untrusted-length allocations, add cargo-fuzz harness, fix overflow panics#32
Nathan-D-R merged 2 commits into
mainfrom
security/cap-allocations-and-fuzz

Conversation

@Nathan-D-R

Copy link
Copy Markdown
Contributor

Summary

Handles #26 and #23 together since both need the same cargo-fuzz scaffolding.

  • Caps every length-prefixed read (BinaryReader::read_bytes) and every file-derived scan/error-log/scan-parameter count against the file's actual remaining size before allocating, instead of allocating first and letting the subsequent read fail. Closes the memory-DoS vector in Cap untrusted-length allocations in the low-level reader; no fuzz harness exists #26.
  • Adds a cargo-fuzz harness at crates/opentfraw/fuzz with two targets: open (RawFileReader::open) and read_scan_peaks (open + read every declared scan's peaks) - the two fully-adversarial-input entry points named in Add unit tests (and a fuzz harness) for the binary decoders #23/Cap untrusted-length allocations in the low-level reader; no fuzz harness exists #26.
  • Fuzzing the harness immediately found three real crash bugs (all fixed, with regression tests):
    • u32 multiplication overflow in PacketHeader label-stream skip lengths (descriptor_list_size / unknown_stream_size * 4 computed in u32 before widening to usize).
    • u32 addition overflow computing num_scans from first_scan/last_scan (extracted to a testable compute_num_scans helper).
    • u64 addition overflow combining data_addr with a scan offset, and a u32 subtraction underflow converting a requested scan number to a scan-index offset when it fell below the file's declared first_scan_number (extracted to scan_index_entry / scan_number_to_index).
  • Adds unit tests for the pure-decode functions in bytes.rs, header.rs, audit_tag.rs, generic_data.rs, and error_log.rs per Add unit tests (and a fuzz harness) for the binary decoders #23, using hand-built byte fixtures (valid/truncated/out-of-range), no vendor comparison per CONTRIBUTING.md's clean-room policy.
  • Adds a fuzz-smoke CI job: runs both fuzz targets for a fixed 60s each, gated on crates/opentfraw/src/** changing on pull requests (separate from any longer scheduled/manual run), seeded from a small real RAW fixture via the same PRIDE download pattern validate-mzml already uses.

Note: this branch's working tree also had pre-existing uncommitted changes unrelated to this task (a Python pytest suite referencing issue #21, with no tests/ directory present - appears to be orphaned WIP from an earlier session). Those were deliberately left uncommitted/untouched and are not part of this PR.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace --all-targets (100 unit tests + conformance test, all passing)
  • cargo +nightly clippy/fmt --check clean on the fuzz crate itself
  • Ran RawFileReader::open + dump example against 13 real Thermo RAW files spanning every instrument family in the local corpus (LCQ, LTQ, Orbitrap Fusion/Eclipse/Exploris/Ascend/Astral, Q Exactive, TSQ Altis/Quantiva) - no regressions from the allocation caps
  • cargo fuzz run open/read_scan_peaks for 60-180s each with a real-file-seeded corpus - clean (no crashes) after the three bugs above were fixed
  • CI (this PR) - watching for the new fuzz-smoke job and the rest of the matrix

Closes #26, Closes #23

…ix overflow panics

Caps every length-prefixed read and file-derived scan/error-log/parameter
count against the file's actual remaining size before allocating, closing
the memory-DoS vector described in #26 (a crafted/corrupt RAW file could
previously request an allocation sized from an attacker-controlled count
with no relation to the file's real size).

Adds a cargo-fuzz harness (crates/opentfraw/fuzz) with two targets,
`open` and `read_scan_peaks`, per #23 and #26. Fuzzing it immediately
found three real crash bugs, now fixed:

- u32 multiplication overflow in PacketHeader label-stream skip lengths
  (descriptor_list_size / unknown_stream_size * 4 computed in u32 before
  widening).
- u32 addition overflow computing num_scans from first_scan/last_scan.
- u64 addition overflow combining data_addr with a scan offset, and a u32
  subtraction underflow converting a requested scan number to a scan-index
  offset when it fell below the file's first_scan_number.

Also adds unit tests for the pure-decode functions in bytes.rs, header.rs,
audit_tag.rs, generic_data.rs, and error_log.rs (issue #23), plus
regression tests for the fixes above in reader.rs and scan_data.rs, and a
60-second fuzz smoke-test CI job gated on crates/opentfraw/src/** changing
on pull requests.

Closes #26, Closes #23
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 19, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
opentfraw-docs 0aeddd6 Jul 19 2026, 01:33 PM

…ons-and-fuzz

# Conflicts:
#	.github/workflows/ci.yml
#	CHANGELOG.md
@Nathan-D-R
Nathan-D-R merged commit 258de50 into main Jul 19, 2026
10 checks passed
@Nathan-D-R
Nathan-D-R deleted the security/cap-allocations-and-fuzz branch July 19, 2026 13:45
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.

Cap untrusted-length allocations in the low-level reader; no fuzz harness exists Add unit tests (and a fuzz harness) for the binary decoders

1 participant