Skip to content

Commit

Permalink
Important fix: make fuzzer able to tell different bugs appart (again)
Browse files Browse the repository at this point in the history
**Context:**

For the fuzzer to be able to "understand" that something went wrong,
like a panic, the process must terminate in an abnormal fashion.

The default panic hook will unwind the stack, run destructors,
optionally print a backtrace and exit with code 101. The fuzzer will
not be able to "understand" that something went particuliarly wrong.

One way to stop a process in a way that the fuzzer understands as
abnormal is to call `std::process::abort()`.

**Possible solutions:**

- build with "-C panic=abort":
  incompatible with compiler plugins
  rust-lang/cargo#2738 (comment)
  rust-fuzz/afl.rs#120
- use `panic::catch_unwind()` to catch unwinding stacks and call `std::process::abort()`:
  all kind of bugs will then unwind their stack up to the code calling this function
  and therefore render different bugs indistinguishable from the fuzzer's point of view.
- use a custom panic hook and call `std::process::abort()` here.

**Implemented solution**

We implemented both solution 2 and 3.
Solution 3 has no drawbacks that I know of, but could potentially be
missed if the fuzzed code modifies the panic hook. In this case, we fall
back to solution 2 as a last resort.
  • Loading branch information
PaulGrandperrin committed Apr 23, 2018
1 parent c848c31 commit abe2b4c
Showing 1 changed file with 14 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) {

#[cfg(all(fuzzing, not(fuzzing_debug)))]
pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
// get buffer from honggfuzz runtime
let buf;
unsafe {
let mut buf_ptr: *const u8 = std::mem::uninitialized();
Expand All @@ -244,11 +245,24 @@ pub fn fuzz<F>(closure: F) where F: Fn(&[u8]) + std::panic::RefUnwindSafe {
buf = ::std::slice::from_raw_parts(buf_ptr, len_ptr);
}

// Registers a panic hook that aborts the process before unwinding.
// It is useful to abort before unwinding so that the fuzzer will then be
// able to analyse the process stack frames to tell different bugs appart.
std::panic::set_hook(Box::new(|_| {
std::process::abort();
}));

// We still catch unwinding panics just in case the fuzzed code modifies
// the panic hook.
// If so, the fuzzer will be unable to tell different bugs appart and you will
// only be able to find one bug at a time before fixing it to then find a new one.
let did_panic = std::panic::catch_unwind(|| {
closure(buf);
}).is_err();

if did_panic {
// hopefully the custom panic hook will be called before and abort the
// process with instact stack frames.
std::process::abort();
}
}
Expand Down

0 comments on commit abe2b4c

Please sign in to comment.