Three panics from fuzzing: unchecked slice indexing in RAF, X3F, and TIFF parsers
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 379
- Forks
- 75
- PR merge metrics
- No merged PRs in 30d
Description
While fuzzing a downstream consumer of rawloader 0.37.1, I found three distinct panics caused by unchecked slice indexing on crafted inputs. These are caught by rawloader's internal catch_unwind in RawLoader::decode(), but become aborts under panic=abort (which is the default for release profiles in many projects and all WASM targets).
1. RAF (FUJIFILM header): basics.rs:64 — BEu32 out of bounds
TiffIFD::new_file() in tiff.rs:128 matches the FUJIFILM magic at buf[0..8] and immediately calls BEu32(buf, 84) without checking that the buffer is long enough.
Minimal input: 8 bytes — just the ASCII string FUJIFILM.
Suggested fix: Check buf.len() >= 108 (or similar minimum) before accessing offsets 84, 92, and 100 in the FUJIFILM branch of new_file().
2. X3F (FOVb header): x3f.rs:37 — slice index out of bounds
X3fFile::new() reads a 4-byte directory offset from the end of the file (LEu32(&buf.buf, buf.size-4)) and uses it as a slice index without bounds checking. A crafted file can set this to any value (e.g., 0xf1f1f1f1), causing an OOB panic at &buf.buf[offset..].
Additionally, X3fDecoder::new() at line 100 calls .unwrap() on the X3fFile::new() result.
Minimal input: 257 bytes — FOVb magic + padding with 0xf1 bytes.
Suggested fix:
- Add
if offset >= buf.size { return Err(...) }before the slice at line 37. - Change
.unwrap()to?inX3fDecoder::new().
3. TIFF with large IFD count: basics.rs:80 — LEu16 out of bounds
TiffIFD::new() reads the IFD entry count at tiff.rs:196 and caps it at 4000, but does not validate that the buffer actually contains num * 12 + 2 + 4 bytes from the offset. When num is large relative to the actual buffer size, the loop reads past the end.
Minimal input: 1026 bytes — valid TIFF little-endian header with IFD offset 8, entry count 136, but only enough data for ~84 entries.
Suggested fix: Validate offset + 2 + (num as usize) * 12 + 4 <= buf.len() before entering the entry loop.
Notes
I understand that RawLoader::decode() wraps the decode path in catch_unwind, which masks these panics in the default API. However:
catch_unwinddoes not work underpanic=abort, which is common in release builds and required for WASM.- The
get_decoder()andTiffIFD::new_file()methods are public and can be called without thecatch_unwindwrapper. - Converting panics to errors is a band-aid; the underlying slice accesses should be bounds-checked.
All three inputs are available as minimized fuzz artifacts — happy to provide the exact bytes if helpful. Thank you for maintaining rawloader!
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the minimized inputs in tiff.rs and x3f.rs, focusing on TiffIFD::new_file(), TiffIFD::new(), X3fFile::new(), and X3fDecoder::new(). Verify that the RAF, X3F, and oversized-IFD inputs return errors without out-of-bounds panics, including when decoding is built with panic=abort.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- computer-vision, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100