rust-fuzz / libfuzzer

Rust bindings and utilities for LLVM’s libFuzzer
Apache License 2.0
208 stars 44 forks source link

Avoid the "replace main" trick #46

Open Manishearth opened 4 years ago

Manishearth commented 4 years ago

The way libfuzzer works is that libfuzzer itself contains a main(), and you link in a binary that contains a hook but not main().

This is kind of awkward, ideally we can get rid of this requirement and instead have a system where you define main() and call libfuzzer::fuzz(|x: &[u8]| {...}) when ready.

Of course, this won't work without changes to libFuzzer itself. Ideally we can add a compile time flag that disables main() and routes everything through FuzzerDriver.

Manishearth commented 4 years ago

This also lets us do things like add custom formatters to libFuzzer (https://github.com/rust-fuzz/libfuzzer-sys/issues/47), because last I checked we can't hook into any of the optional functions

That said, it seems like we're using LLVMFuzzerInitialize so perhaps we can, now!

Update: this is no longer necessary to use optional functions.

frewsxcv commented 3 years ago

Greetings from a year later 👋

How are you thinking this would work? We commit a .patch file that renames (or removes) main in FuzzerMain.cpp? And apply the patch everytime we update LLVM? Or were you thinking something else?

Manishearth commented 3 years ago

Something like that, yeah

nagisa commented 3 years ago

We could -Dmain=libfuzzer_main or something along those lines. It can then also be made optional through build-time features.

I'll see about making a PR for this today.

jameysharp commented 1 year ago

I'm interested in this because when I run a fuzz target against an existing corpus, I'd like to gather statistics from inside the fuzz target and report them when the fuzzer exits.

I could do that instead by factoring out the fuzz target function so I can call it from a separate program that just feeds it the contents of every file in a directory. I could also use the libc crate to set up an atexit handler, but carefully, since I understand none of the Rust I/O machinery works at that point.

But I think it'd be nicer to be able to wrap logic like this around a simple library call to the fuzzer driver.