
* 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 (#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 <romain.malmain@pm.me> Co-authored-by: Dominik Maier <domenukk@gmail.com>
96 lines
3.1 KiB
Rust
96 lines
3.1 KiB
Rust
#![cfg(feature = "std")]
|
|
#![cfg(feature = "libipt")]
|
|
#![cfg(target_os = "linux")]
|
|
|
|
use std::{arch::asm, process};
|
|
|
|
use libafl_intelpt::{availability, IntelPT};
|
|
use libipt::Image;
|
|
use nix::{
|
|
sys::{
|
|
signal::{kill, raise, Signal},
|
|
wait::{waitpid, WaitPidFlag},
|
|
},
|
|
unistd::{fork, ForkResult},
|
|
};
|
|
use proc_maps::get_process_maps;
|
|
|
|
/// To run this test ensure that the executable has the required capabilities.
|
|
/// This can be achieved with the script `./run_integration_tests_linux_with_caps.sh`
|
|
#[test]
|
|
fn intel_pt_trace_fork() {
|
|
if let Err(reason) = availability() {
|
|
// Mark as `skipped` once this will be possible https://github.com/rust-lang/rust/issues/68007
|
|
println!("Intel PT is not available, skipping test. Reasons:");
|
|
println!("{reason}");
|
|
return;
|
|
}
|
|
|
|
let pid = match unsafe { fork() } {
|
|
Ok(ForkResult::Parent { child }) => child,
|
|
Ok(ForkResult::Child) => {
|
|
raise(Signal::SIGSTOP).expect("Failed to stop the process");
|
|
// This will generate a sequence of tnt packets containing 255 taken branches
|
|
unsafe {
|
|
let mut count = 0;
|
|
asm!(
|
|
"2:",
|
|
"add {0:r}, 1",
|
|
"cmp {0:r}, 255",
|
|
"jle 2b",
|
|
inout(reg) count,
|
|
options(nostack)
|
|
);
|
|
let _ = count;
|
|
}
|
|
process::exit(0);
|
|
}
|
|
Err(e) => panic!("Fork failed {e}"),
|
|
};
|
|
|
|
let pt_builder = IntelPT::builder().pid(Some(pid.as_raw()));
|
|
let mut pt = pt_builder.build().expect("Failed to create IntelPT");
|
|
pt.enable_tracing().expect("Failed to enable tracing");
|
|
|
|
waitpid(pid, Some(WaitPidFlag::WUNTRACED)).expect("Failed to wait for the child process");
|
|
let maps = get_process_maps(pid.into()).unwrap();
|
|
kill(pid, Signal::SIGCONT).expect("Failed to continue the process");
|
|
|
|
waitpid(pid, None).expect("Failed to wait for the child process");
|
|
pt.disable_tracing().expect("Failed to disable tracing");
|
|
|
|
let mut image = Image::new(Some("test_trace_pid")).unwrap();
|
|
for map in maps {
|
|
if map.is_exec() && map.filename().is_some() {
|
|
match image.add_file(
|
|
map.filename().unwrap().to_str().unwrap(),
|
|
map.offset as u64,
|
|
map.size() as u64,
|
|
None,
|
|
map.start() as u64,
|
|
) {
|
|
Err(e) => println!(
|
|
"Error adding mapping for {:?}: {:?}, skipping",
|
|
map.filename().unwrap(),
|
|
e
|
|
),
|
|
Ok(()) => println!(
|
|
"mapping for {:?} added successfully {:#x} - {:#x}",
|
|
map.filename().unwrap(),
|
|
map.start(),
|
|
map.start() + map.size()
|
|
),
|
|
}
|
|
}
|
|
}
|
|
|
|
let mut map = vec![0u16; 0x10_00];
|
|
pt.decode_traces_into_map(&mut image, &mut map).unwrap();
|
|
|
|
let assembly_jump_id = map.iter().position(|count| *count >= 254);
|
|
assert!(
|
|
assembly_jump_id.is_some(),
|
|
"Assembly jumps not found in traces"
|
|
);
|
|
}
|