3 ms·
I have run "cargo fuzz" (based on the AFL fuzzer) over a binary-format parsing library I wrote, generating roughly a billion inputs. Here's what I learned: 1.
by ekidd 4y ago
I have run "cargo fuzz" (based on the AFL fuzzer) over a binary-format parsing library I wrote, generating roughly a billion inputs. Here's what I learned:
1. Rust does not protect you at compile time against "index out of bounds" errors. If you want that, you'll want a dependently-typed language like Idris. Which still wouldn't help much in this case.
2. However, Rust catches index errors perfectly well at runtime, and performs a controlled panic. This does not result in a privilege escalation, but it may cause a denial of service. So fuzzing in (safe) Rust is normally a "lower stakes" activity.
3. "cargo fuzz" is super easy to use, and AFL is pretty amazing.
4. If you think you can parse complex, badly-documented low-level binary formats without ever having an index error, you're probably wildly overconfident. In the case of the minidump parser, it's worse: The data was generated by a crashing process, and in many cases, the data caused the crash.
Let's look at what the author concludes:
> And what did we screw up? Some legit stuff! It’s Rust code, so I am fairly confident none of the issues were security concerns, but they were definitely quality of implementation issues, and could have been used to at very least denial-of-service the minidump processor.
A whole bunch of issues, probably none of them leading to security escalations. And unlike many C fuzzing experiences, it was largely painless:
> By comparison I am absolutely thriving under “Yeah you can deterministically trip this assertion with this tiny input you can just check in as a unit test”.
This happens because Rust catches most of these errors very early, using assertions in the standard library. So your fuzz reports often need to be tracked for only a few lines.
TL;Dr: Parsing complex binary formats usually involves subtle bugs. Rust does not promise to catch index-out-of-bounds at compile-time, but it catches them at runtime. This makes fuzzing easy and productive.
Overall, I'd call this a success story. The author underwent an inevitably humbling experience for low stakes under controlled conditions. And now the library can parse corrupted examples of an incredibly nasty format, with high confidence that the worst thing that will happen is a runtime error (not even a DoS).