Skip to content

Commit

Permalink
Pr/fasan multithreading fixes upstream (#2955)
Browse files Browse the repository at this point in the history
* Fixing the test_harness library name

* Fasan works, but testing of all features is pending

* Tests pass, before fixing clippy and fmt

* CLippy+fmt

* CLippy+fmt+tests running on linux

* Clippy

* Not stalkering the fuzzer. In the correct way

* Removing the instrumentation upon crash. Proper hooking of UnmapViewOfFile

* Fixes after the merge from the upstream (before 0.15.0). Still need to add the observer, clippy, fmt, and at least linux compilation

* Adding the helper observer and using it in the test

* Removing the observer from the wrong location

* Adapting to the new helper ownership model

* Adding an observer to shut down instrumentation upon crash

* Clippy + fmt

* Using mimalloc everywhere

* Deactivating before activating with the harness. Otherwise, gets stuck on Linux.

* Fixing imports for windows

* Using the new way of passing the handler

* Using frida_helper_shutdown_observer

* Clippy+fmt

* no-std, clippy

* Fmt

* Stable thread_id

* Clippy 18

* More clippy

* Formatting toml

* Fixing apples

* Fixing apples 2

* Fixing apples 3

* Upping to 0.16.7 (necessary for Windows)

* Clippy+fmt

* Enabling the allocator test after the fix and clarifying the importantce of the static runtime linking.

* Moving has_tls to bolts

* Proper handling of no-std, hopefully

* Another attempt to fix win no-std

* Not mine clippy complaint...

* Not mine clippy complaint #2...

* Dlmalloc not used, removing from dependencies

* Restoring target in config.toml (otherwise fails CI on Linux)

* lots of digging around, pray for us

* fixup?

* Revert "lots of digging around, pray for us"

This reverts commit 706c272.

* Revert "fixup?"

This reverts commit 1d7c5d4.

* Revert artifact

* Revert fixups

* Removing unused

* Reverting to upstream/main

---------

Co-authored-by: Addison Crump <[email protected]>
Co-authored-by: Dongjia "toka" Zhang <[email protected]>
  • Loading branch information
3 people authored Feb 14, 2025
1 parent f971539 commit b3fe744
Show file tree
Hide file tree
Showing 25 changed files with 1,162 additions and 312 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,5 @@ harness
program
fuzzer_libpng*
forkserver_simple

*.patch
2 changes: 1 addition & 1 deletion fuzzers/binary_only/frida_executable_libpng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ libafl = { path = "../../../libafl", features = [
"frida_cli",
] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../../libafl_bolts" }
frida-gum = { version = "0.16.5", features = [
frida-gum = { version = "0.16.7", features = [
"auto-download",
"event-sink",
"invocation-listener",
Expand Down
73 changes: 52 additions & 21 deletions fuzzers/binary_only/frida_executable_libpng/src/fuzzer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng.
use std::{path::PathBuf, ptr::null};
use std::{cell::RefCell, path::PathBuf, ptr::null, rc::Rc};

use frida_gum::Gum;
use libafl::{
Expand Down Expand Up @@ -43,6 +43,7 @@ use libafl_frida::{
cmplog_rt::CmpLogRuntime,
coverage_rt::{CoverageRuntime, MAP_SIZE},
executor::FridaInProcessExecutor,
frida_helper_shutdown_observer::FridaHelperObserver,
helper::FridaInstrumentationHelper,
};
use libafl_targets::cmplog::CmpLogObserver;
Expand Down Expand Up @@ -113,16 +114,22 @@ unsafe fn fuzz(
let asan = AsanRuntime::new(options);

#[cfg(unix)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage, asan));
let frida_helper = Rc::new(RefCell::new(FridaInstrumentationHelper::new(
&gum,
options,
tuple_list!(coverage, asan),
)));
#[cfg(windows)]
let mut frida_helper =
FridaInstrumentationHelper::new(&gum, &options, tuple_list!(coverage));
let frida_helper = Rc::new(RefCell::new(FridaInstrumentationHelper::new(
&gum,
&options,
tuple_list!(coverage),
)));

// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr(
"edges",
frida_helper.map_mut_ptr().unwrap(),
frida_helper.borrow_mut().map_mut_ptr().unwrap(),
MAP_SIZE,
))
.track_indices();
Expand All @@ -131,6 +138,7 @@ unsafe fn fuzz(
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
let frida_helper_observer = FridaHelperObserver::new(Rc::clone(&frida_helper));

// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
Expand Down Expand Up @@ -196,9 +204,14 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
let observers = tuple_list!(
frida_helper_observer,
edges_observer,
time_observer,
asan_observer
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
let observers = tuple_list!(frida_helper_observer, edges_observer, time_observer);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand All @@ -210,7 +223,7 @@ unsafe fn fuzz(
&mut state,
&mut mgr,
)?,
&mut frida_helper,
Rc::clone(&frida_helper),
);

// In case the corpus is empty (on first run), reset
Expand Down Expand Up @@ -238,13 +251,16 @@ unsafe fn fuzz(
let coverage = CoverageRuntime::new();
let cmplog = CmpLogRuntime::new();

let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage, cmplog));
let mut frida_helper = Rc::new(RefCell::new(FridaInstrumentationHelper::new(
&gum,
options,
tuple_list!(coverage, cmplog),
)));

// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr(
"edges",
frida_helper.map_mut_ptr().unwrap(),
frida_helper.borrow_mut().map_mut_ptr().unwrap(),
MAP_SIZE,
))
.track_indices();
Expand All @@ -253,6 +269,7 @@ unsafe fn fuzz(
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
let frida_helper_observer = FridaHelperObserver::new(Rc::clone(&frida_helper));

// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
Expand Down Expand Up @@ -316,9 +333,14 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
let observers = tuple_list!(
frida_helper_observer,
edges_observer,
time_observer,
asan_observer
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
let observers = tuple_list!(frida_helper_observer, edges_observer, time_observer);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand All @@ -330,7 +352,7 @@ unsafe fn fuzz(
&mut state,
&mut mgr,
)?,
&mut frida_helper,
Rc::clone(&frida_helper),
);

// In case the corpus is empty (on first run), reset
Expand Down Expand Up @@ -373,13 +395,16 @@ unsafe fn fuzz(

let coverage = CoverageRuntime::new();

let mut frida_helper =
FridaInstrumentationHelper::new(&gum, options, tuple_list!(coverage));
let mut frida_helper = Rc::new(RefCell::new(FridaInstrumentationHelper::new(
&gum,
options,
tuple_list!(coverage),
)));

// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_ptr(
"edges",
frida_helper.map_mut_ptr().unwrap(),
frida_helper.borrow_mut().map_mut_ptr().unwrap(),
MAP_SIZE,
))
.track_indices();
Expand All @@ -388,6 +413,7 @@ unsafe fn fuzz(
let time_observer = TimeObserver::new("time");
#[cfg(unix)]
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
let frida_helper_observer = FridaHelperObserver::new(Rc::clone(&frida_helper));

// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
Expand Down Expand Up @@ -451,9 +477,14 @@ unsafe fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

#[cfg(unix)]
let observers = tuple_list!(edges_observer, time_observer, asan_observer);
let observers = tuple_list!(
frida_helper_observer,
edges_observer,
time_observer,
asan_observer
);
#[cfg(windows)]
let observers = tuple_list!(edges_observer, time_observer);
let observers = tuple_list!(frida_helper_observer, edges_observer, time_observer);

// Create the executor for an in-process function with just one observer for edge coverage
let mut executor = FridaInProcessExecutor::new(
Expand All @@ -465,7 +496,7 @@ unsafe fn fuzz(
&mut state,
&mut mgr,
)?,
&mut frida_helper,
Rc::clone(&frida_helper),
);

// In case the corpus is empty (on first run), reset
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/binary_only/frida_libpng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ libafl = { path = "../../../libafl", features = [
"errors_backtrace",
] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../../libafl_bolts" }
frida-gum = { version = "0.16.5", features = [
frida-gum = { version = "0.16.7", features = [
"auto-download",
"event-sink",
"invocation-listener",
Expand Down
23 changes: 17 additions & 6 deletions fuzzers/binary_only/frida_libpng/src/fuzzer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng.
use std::path::PathBuf;
use std::{cell::RefCell, path::PathBuf, rc::Rc};

use frida_gum::Gum;
use libafl::{
Expand Down Expand Up @@ -40,6 +40,7 @@ use libafl_frida::{
cmplog_rt::CmpLogRuntime,
coverage_rt::{CoverageRuntime, MAP_SIZE},
executor::FridaInProcessExecutor,
frida_helper_shutdown_observer::FridaHelperObserver,
helper::{FridaInstrumentationHelper, IfElseRuntime},
};
use libafl_targets::cmplog::CmpLogObserver;
Expand Down Expand Up @@ -104,7 +105,7 @@ fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let options_clone = options.clone();
let client_description_clone2 = client_description.clone();
let options_clone2 = options.clone();
let mut frida_helper = FridaInstrumentationHelper::new(
let frida_helper = Rc::new(RefCell::new(FridaInstrumentationHelper::new(
&gum,
options,
tuple_list!(
Expand All @@ -120,17 +121,22 @@ fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
),
coverage
),
);
)));

// Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe {
StdMapObserver::from_mut_ptr("edges", frida_helper.map_mut_ptr().unwrap(), MAP_SIZE)
StdMapObserver::from_mut_ptr(
"edges",
frida_helper.borrow_mut().map_mut_ptr().unwrap(),
MAP_SIZE,
)
})
.track_indices();

// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let asan_observer = AsanErrorsObserver::from_static_asan_errors();
let frida_helper_observer = FridaHelperObserver::new(Rc::clone(&frida_helper));

// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
Expand Down Expand Up @@ -187,7 +193,12 @@ fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

let observers = tuple_list!(edges_observer, time_observer, asan_observer);
let observers = tuple_list!(
frida_helper_observer,
edges_observer,
time_observer,
asan_observer
);

// Create the executor for an in-process function with just one observer for edge coverage
let executor = FridaInProcessExecutor::new(
Expand All @@ -200,7 +211,7 @@ fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
&mut mgr,
options.timeout,
)?,
&mut frida_helper,
Rc::clone(&frida_helper),
);
// Create an observation channel using cmplog map
let cmplog_observer = CmpLogObserver::new("cmplog", true);
Expand Down
2 changes: 2 additions & 0 deletions fuzzers/binary_only/frida_windows_gdiplus/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[build]
rustflags = ["-C", "target-feature=+crt-static"]
2 changes: 1 addition & 1 deletion fuzzers/binary_only/frida_windows_gdiplus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ libafl = { path = "../../../libafl", features = [
"errors_backtrace",
] } #, "llmp_small_maps", "llmp_debug"]}
libafl_bolts = { path = "../../../libafl_bolts" }
frida-gum = { version = "0.16.5", features = [
frida-gum = { version = "0.16.7", features = [
"auto-download",
"event-sink",
"invocation-listener",
Expand Down
2 changes: 2 additions & 0 deletions fuzzers/binary_only/frida_windows_gdiplus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ To build this example, run `cargo build --release` in this folder.

Then compile the harness `cl.exe /LD harness.cc /link /dll gdiplus.lib ole32.lib`

Note: this fuzzer is **statically linked** with C runtime. This is achieved by specifying `rustflags = ["-C", "target-feature=+crt-static"]` in `.cargo/config.toml`. The static linking is necessary to avoid Asan function hooks to hook the calls from the fuzzer itself, as such self-hooking can eventually lead to deadlocks in internal Frida mechanisms.

## Run

To run the example `target\release\frida_windows_gdiplus.exe -H harness.dll -i corpus -o output --libs-to-instrument gdi32.dll --libs-to-instrument gdi32full.dll --libs-to-instrument gdiplus.dll --libs-to-instrument WindowsCodecs.dll --disable-excludes`
2 changes: 0 additions & 2 deletions fuzzers/binary_only/frida_windows_gdiplus/cargo/.config

This file was deleted.

Loading

0 comments on commit b3fe744

Please sign in to comment.