forked from AFLplusplus/LibAFL
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Intel PT tracing support (AFLplusplus#2471)
* WIP: IntelPT qemu systemmode * use perf-event-open-sys instead of bindgen * intelPT Add enable and disable tracing, add test * Use static_assertions crate * Fix volatiles, finish test * Add Intel PT availability check * Use LibAFL errors in Result * Improve filtering * Add KVM pt_mode check * move static_assertions use * Check for perf_event_open support * Add (empty) IntelPT module * Add IntelPTModule POC * partial ideas to implement intel pt * forgot smth * trace decoding draft * add libipt decoder * use cpuid instead of reading /proc/cpuinfo * investigating nondeterministic behaviour * intel_pt module add thread creation hook * Fully identify deps versions Cargo docs: Although it looks like a specific version of the crate, it actually specifies a range of versions and allows SemVer compatible updates * Move mem image to module, output to file for debug * fixup! Use static_assertions crate * Exclude host kernel from traces * Bump libipt-rs * Callback to get memory as an alterantive to image * WIP Add bootloader fuzzer example * Split availability check: add availability_with_qemu * Move IntelPT to observer * Improve test docs * Clippy happy now * Taplo happy now * Add IntelPTObserver boilerplate * Hook instead of Observer * Clippy & Taplo * Add psb_freq setting * Extremely bad and dirty babyfuzzer stealing * Use thread local cell instead of mutex * Try a trace diff based naive feedback * fix perf aux buffer wrap handling * Use f64 for feedback score * Fix clippy for cargo test * Add config format tests * WIP intelpt babyfuzzer with fork * Fix not wrapped tail offset in split buffer * Baby PT with raw traces diff working * Cache nr_filters * Use Lazy_lock for perf_type * Add baby_fuzzer_intel_pt * restore baby fuzzer * baby_fuzzer with block decoder * instruction decoder instead of block * Fix after upstream merge * OwnedRefMut instead of Cow * Read mem directly instead of going through files * Fix cache lifetime and tail update * clippy * Taplo * Compile caps only on linux * clippy * Fail compilation on unsupported OSes * Add baby_fuzzer_intel_pt to CI * Cleanup * Move intel pt + linux check * fix baby pt * rollback forkexecutor * Remove unused dep * Cleanup * Lints * Compute an edge id instead of using only block ip * Binary only intelPT POC * put linux specific code behind target_os=linux * Clippy & Taplo * fix CI * Disable relocation * No unwrap in decode * No expect in decode * Better logging, smaller aux buffer * add IntelPTBuilder * some lints * Add exclude_hv config * Per CPU tracing and inheritance * Parametrize buffer size * Try not to break commandExecutor API pt.1 * Try not to break commandExecutor API pt.2 * Try not to break commandExecutor API pt.3 * fix baby PT * Support on_crash & on_timeout callbacks for libafl_qemu modules (AFLplusplus#2620) * support (unsafe) on_crash / on_timeout callbacks for modules * use libc types in bindgen * Move common code to bolts * Cleanup * Revert changes to backtrace_baby_fuzzers/command_executor * Move intel_pt in one file * Use workspace deps * add nr_addr_filter fallback * Cleaning * Improve decode * Clippy * Improve errors and docs * Impl from<PtError> for libafl::Error * Merge hooks * Docs * Clean command executor * fix baby PT * fix baby PT warnings * decoder fills the map with no vec alloc * WIP command executor intel PT * filter_map() instead of filter().map() * fix docs * fix windows? * Baby lints * Small cleanings * Use personality to disable ASLR at runtime * Fix nix dep * Use prc-maps in babyfuzzer * working ET_DYN elf * Cleanup Cargo.toml * Clean command executor * introduce PtraceCommandConfigurator * Fix clippy & taplo * input via stdin * libipt as workspace dep * Check kernel version * support Arg input location * Reorder stuff * File input * timeout support for PtraceExec * Lints * Move out method not needing self form IntelPT * unimplemented * Lints * Move intel_pt_baby_fuzzer * Move intel_pt_command_executor * Document the need for smp_rmb * Better comment * Readme and Makefile.toml instead of build.rs * Move out from libafl_bolts to libafl_intelpt * Fix hooks * (Almost) fix intel_pt command exec * fix intel_pt command exec debug * Fix baby_fuzzer * &raw over addr_of! * cfg(target_os = "linux") * bolts Cargo.toml leftover * minimum wage README.md * extract join_split_trace from decode * extract decode_block from decode * add 1 to `previous_block_ip` to avoid that all the recursive basic blocks map to 0 * More generic hook * fix windows * Update CI, fmt * No bitbybit * Fix docker? * Fix Apple silicon? * Use old libipt from crates.io --------- Co-authored-by: Romain Malmain <[email protected]> Co-authored-by: Dominik Maier <[email protected]>
- Loading branch information
1 parent
5eff9c0
commit f7f8dff
Showing
24 changed files
with
1,981 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "intel_pt_baby_fuzzer" | ||
version = "0.13.2" | ||
authors = [ | ||
"Andrea Fioraldi <[email protected]>", | ||
"Dominik Maier <[email protected]>", | ||
"Marco Cavenati <[email protected]>", | ||
] | ||
edition = "2021" | ||
|
||
[features] | ||
tui = [] | ||
|
||
[dependencies] | ||
libafl = { path = "../../../libafl/", default-features = false, features = [ | ||
"intel_pt", | ||
] } | ||
libafl_bolts = { path = "../../../libafl_bolts" } | ||
proc-maps = "0.4.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Baby fuzzer with Intel PT tracing | ||
|
||
This is a minimalistic example about how to create a libafl based fuzzer with Intel PT tracing. | ||
|
||
It runs on a single core until a crash occurs and then exits. | ||
|
||
The tested program is a simple Rust function without any instrumentation. | ||
|
||
After building this example with `cargo build`, you need to give to the executable the necessary capabilities with | ||
`sudo setcap cap_ipc_lock,cap_sys_ptrace,cap_sys_admin,cap_syslog=ep ./target/debug/intel_pt_baby_fuzzer`. | ||
|
||
You can run this example using `cargo run`, and you can enable the TUI feature by building and running with | ||
`--features tui`. | ||
|
||
This fuzzer is compatible with Linux hosts only having an Intel PT compatible CPU. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
use std::{hint::black_box, num::NonZero, path::PathBuf, process, time::Duration}; | ||
|
||
#[cfg(feature = "tui")] | ||
use libafl::monitors::tui::TuiMonitor; | ||
#[cfg(not(feature = "tui"))] | ||
use libafl::monitors::SimpleMonitor; | ||
use libafl::{ | ||
corpus::{InMemoryCorpus, OnDiskCorpus}, | ||
events::SimpleEventManager, | ||
executors::{ | ||
hooks::intel_pt::{IntelPTHook, Section}, | ||
inprocess::GenericInProcessExecutor, | ||
ExitKind, | ||
}, | ||
feedbacks::{CrashFeedback, MaxMapFeedback}, | ||
fuzzer::{Fuzzer, StdFuzzer}, | ||
generators::RandPrintablesGenerator, | ||
inputs::{BytesInput, HasTargetBytes}, | ||
mutators::{havoc_mutations::havoc_mutations, scheduled::StdScheduledMutator}, | ||
observers::StdMapObserver, | ||
schedulers::QueueScheduler, | ||
stages::mutational::StdMutationalStage, | ||
state::StdState, | ||
}; | ||
use libafl_bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice}; | ||
use proc_maps::get_process_maps; | ||
|
||
// Coverage map | ||
const MAP_SIZE: usize = 4096; | ||
static mut MAP: [u8; MAP_SIZE] = [0; MAP_SIZE]; | ||
#[allow(static_mut_refs)] | ||
static mut MAP_PTR: *mut u8 = unsafe { MAP.as_mut_ptr() }; | ||
|
||
pub fn main() { | ||
// The closure that we want to fuzz | ||
let mut harness = |input: &BytesInput| { | ||
let target = input.target_bytes(); | ||
let buf = target.as_slice(); | ||
if !buf.is_empty() && buf[0] == b'a' { | ||
let _do_something = black_box(0); | ||
if buf.len() > 1 && buf[1] == b'b' { | ||
let _do_something = black_box(0); | ||
if buf.len() > 2 && buf[2] == b'c' { | ||
panic!("Artificial bug triggered =)"); | ||
} | ||
} | ||
} | ||
ExitKind::Ok | ||
}; | ||
|
||
// Create an observation channel using the map | ||
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", MAP_PTR, MAP_SIZE) }; | ||
|
||
// Feedback to rate the interestingness of an input | ||
let mut feedback = MaxMapFeedback::new(&observer); | ||
|
||
// A feedback to choose if an input is a solution or not | ||
let mut objective = CrashFeedback::new(); | ||
|
||
// create a State from scratch | ||
let mut state = StdState::new( | ||
// RNG | ||
StdRand::with_seed(current_nanos()), | ||
// Corpus that will be evolved, we keep it in memory for performance | ||
InMemoryCorpus::new(), | ||
// Corpus in which we store solutions (crashes in this example), | ||
// on disk so the user can get them after stopping the fuzzer | ||
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), | ||
// States of the feedbacks. | ||
// The feedbacks can report the data that should persist in the State. | ||
&mut feedback, | ||
// Same for objective feedbacks | ||
&mut objective, | ||
) | ||
.unwrap(); | ||
|
||
// The Monitor trait define how the fuzzer stats are displayed to the user | ||
#[cfg(not(feature = "tui"))] | ||
let mon = SimpleMonitor::new(|s| println!("{s}")); | ||
#[cfg(feature = "tui")] | ||
let mon = TuiMonitor::builder() | ||
.title("Baby Fuzzer Intel PT") | ||
.enhanced_graphics(false) | ||
.build(); | ||
|
||
// The event manager handle the various events generated during the fuzzing loop | ||
// such as the notification of the addition of a new item to the corpus | ||
let mut mgr = SimpleEventManager::new(mon); | ||
|
||
// A queue policy to get testcases from the corpus | ||
let scheduler = QueueScheduler::new(); | ||
|
||
// A fuzzer with feedbacks and a corpus scheduler | ||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); | ||
|
||
// Get the memory map of the current process | ||
let my_pid = i32::try_from(process::id()).unwrap(); | ||
let process_maps = get_process_maps(my_pid).unwrap(); | ||
let sections = process_maps | ||
.iter() | ||
.filter_map(|pm| { | ||
if pm.is_exec() && pm.filename().is_some() { | ||
Some(Section { | ||
file_path: pm.filename().unwrap().to_string_lossy().to_string(), | ||
file_offset: pm.offset as u64, | ||
size: pm.size() as u64, | ||
virtual_address: pm.start() as u64, | ||
}) | ||
} else { | ||
None | ||
} | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
// Intel PT hook that will handle the setup of Intel PT for each execution and fill the map | ||
let pt_hook = unsafe { | ||
IntelPTHook::builder() | ||
.map_ptr(MAP_PTR) | ||
.map_len(MAP_SIZE) | ||
.image(§ions) | ||
} | ||
.build(); | ||
|
||
type PTInProcessExecutor<'a, H, OT, S, T> = | ||
GenericInProcessExecutor<H, &'a mut H, (IntelPTHook<T>, ()), OT, S>; | ||
// Create the executor for an in-process function with just one observer | ||
let mut executor = PTInProcessExecutor::with_timeout_generic( | ||
tuple_list!(pt_hook), | ||
&mut harness, | ||
tuple_list!(observer), | ||
&mut fuzzer, | ||
&mut state, | ||
&mut mgr, | ||
Duration::from_millis(5000), | ||
) | ||
.expect("Failed to create the Executor"); | ||
|
||
// Generator of printable bytearrays of max size 32 | ||
let mut generator = RandPrintablesGenerator::new(NonZero::new(32).unwrap()); | ||
|
||
// Generate 8 initial inputs | ||
state | ||
.generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 8) | ||
.expect("Failed to generate the initial corpus"); | ||
|
||
// Set up a mutational stage with a basic bytes mutator | ||
let mutator = StdScheduledMutator::new(havoc_mutations()); | ||
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); | ||
|
||
fuzzer | ||
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) | ||
.expect("Error in the fuzzing loop"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "intel_pt_command_executor" | ||
version = "0.1.0" | ||
authors = ["Marco Cavenati <[email protected]>"] | ||
edition = "2021" | ||
|
||
[dependencies] | ||
env_logger = "0.11.5" | ||
libafl = { path = "../../../libafl", default-features = false, features = [ | ||
"intel_pt", | ||
] } | ||
libafl_bolts = { path = "../../../libafl_bolts" } | ||
libafl_intelpt = { path = "../../../libafl_intelpt" } | ||
log = { version = "0.4.22", features = ["release_max_level_info"] } |
33 changes: 33 additions & 0 deletions
33
fuzzers/binary_only/intel_pt_command_executor/Makefile.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[env.development] | ||
PROFILE_DIR = "debug" | ||
|
||
[env.release] | ||
PROFILE_DIR = "release" | ||
|
||
[tasks.build_target] | ||
command = "rustc" | ||
args = [ | ||
"src/target_program.rs", | ||
"--out-dir", | ||
"${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/${PROFILE_DIR}", | ||
"-O", | ||
] | ||
|
||
[tasks.build_fuzzer] | ||
command = "cargo" | ||
args = ["build", "--profile", "${CARGO_MAKE_CARGO_PROFILE}"] | ||
|
||
[tasks.build] | ||
dependencies = ["build_fuzzer", "build_target"] | ||
|
||
[tasks.setcap] | ||
script = "sudo setcap cap_ipc_lock,cap_sys_ptrace,cap_sys_admin,cap_syslog=ep ${CARGO_MAKE_CRATE_TARGET_DIRECTORY}/${PROFILE_DIR}/${CARGO_MAKE_CRATE_NAME}" | ||
dependencies = ["build_fuzzer"] | ||
|
||
[tasks.run] | ||
command = "cargo" | ||
args = ["run", "--profile", "${CARGO_MAKE_CARGO_PROFILE}"] | ||
dependencies = ["build", "setcap"] | ||
|
||
[tasks.default] | ||
alias = "run" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Linux Binary-Only Fuzzer with Intel PT Tracing | ||
|
||
This fuzzer is designed to target a Linux binary (without requiring source code instrumentation) and leverages Intel | ||
Processor Trace (PT) to compute code coverage. | ||
|
||
## Prerequisites | ||
|
||
- A Linux host with an Intel Processor Trace (PT) compatible CPU | ||
- `cargo-make` installed | ||
- Sudo access to grant necessary capabilities to the fuzzer | ||
|
||
## How to Run the Fuzzer | ||
|
||
To compile and run the fuzzer (and the target program) execute the following command: | ||
```sh | ||
cargo make | ||
``` | ||
|
||
> **Note**: This command may prompt you for your password to assign capabilities required for Intel PT. If you'd prefer | ||
> not to run it with elevated permissions, you can review and execute the commands from `Makefile.toml` | ||
> individually. |
Oops, something went wrong.