Skip to content

Commit 8398f8f

Browse files
rmalmaintokatoka
andauthored
Qemu signal refactoring (#2920)
* qemu signal refactoring * udpate qemu * clippy, moving things around * update bindings * nostd * cfg * fmt * nostd * clippy * fmt * aaa * windowsssssss * systemmode * reimport fix * remove llmp from replay mode * lol * fixer --------- Co-authored-by: Dongjia "toka" Zhang <tokazerkje@outlook.com>
1 parent defb475 commit 8398f8f

File tree

18 files changed

+395
-171
lines changed

18 files changed

+395
-171
lines changed

fuzzers/binary_only/fuzzbench_qemu/Makefile.toml

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,21 @@ mac_alias = "run_unix"
4848
windows_alias = "unsupported"
4949

5050
[tasks.run_unix]
51-
command = "cargo"
52-
args = [
53-
"run",
54-
"--profile",
55-
"${PROFILE}",
56-
"./${FUZZER_NAME}",
57-
"--",
58-
"--libafl-in",
59-
"../../inprocess/libfuzzer_libpng/corpus",
60-
"--libafl-out",
61-
"./out",
62-
"./${FUZZER_NAME}",
63-
]
51+
script_runner = "@shell"
52+
script = '''
53+
cargo build \
54+
--profile \
55+
${PROFILE}
56+
57+
${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_qemu \
58+
--libafl-in \
59+
../../inprocess/libfuzzer_libpng/corpus \
60+
--libafl-out \
61+
./out \
62+
./${FUZZER_NAME} \
63+
-- \
64+
./${FUZZER_NAME}
65+
'''
6466
dependencies = ["harness"]
6567

6668
# Run the fuzzer

fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use libafl_qemu::{
5151
// asan::{init_with_asan, QemuAsanHelper},
5252
modules::cmplog::{CmpLogModule, CmpLogObserver},
5353
modules::edges::StdEdgeCoverageModule,
54+
modules::AsanModule,
5455
Emulator,
5556
GuestReg,
5657
//snapshot::QemuSnapshotHelper,

fuzzers/binary_only/qemu_launcher/Makefile.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,9 @@ echo "Profile: ${PROFILE}"
375375
export QEMU_LAUNCHER=${TARGET_DIR}/${PROFILE_DIR}/qemu_launcher
376376
377377
./tests/injection/test.sh || exit 1
378+
379+
# complie again with simple mgr
380+
cargo build --profile=${PROFILE} --features="simplemgr" --target-dir=${TARGET_DIR}
378381
./tests/qasan/test.sh || exit 1
379382
'''
380383
dependencies = ["build_unix"]

fuzzers/binary_only/qemu_launcher/src/fuzzer.rs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ impl Fuzzer {
8686
// The shared memory allocator
8787
#[cfg(not(feature = "simplemgr"))]
8888
let mut shmem_provider = StdShMemProvider::new()?;
89-
9089
/* If we are running in verbose, don't provide a replacement stdout, otherwise, use /dev/null */
9190
#[cfg(not(feature = "simplemgr"))]
9291
let stdout = if self.options.verbose {
@@ -97,34 +96,15 @@ impl Fuzzer {
9796

9897
let client = Client::new(&self.options);
9998

100-
#[cfg(not(feature = "simplemgr"))]
99+
#[cfg(feature = "simplemgr")]
101100
if self.options.rerun_input.is_some() {
102-
// If we want to rerun a single input but we use a restarting mgr, we'll have to create a fake restarting mgr that doesn't actually restart.
103-
// It's not pretty but better than recompiling with simplemgr.
104-
105-
// Just a random number, let's hope it's free :)
106-
let broker_port = 13120;
107-
let _fake_broker = LlmpBroker::create_attach_to_tcp(
108-
shmem_provider.clone(),
109-
tuple_list!(),
110-
broker_port,
111-
)
112-
.unwrap();
101+
// only for simplemgr
102+
// DON'T USE LLMP HERE!!
103+
// it doesn't work like that
113104

114-
// To rerun an input, instead of using a launcher, we create dummy parameters and run the client directly.
115105
return client.run(
116106
None,
117-
MonitorTypedEventManager::<_, M>::new(
118-
LlmpEventManagerBuilder::builder().build_on_port(
119-
shmem_provider.clone(),
120-
broker_port,
121-
EventConfig::AlwaysUnique,
122-
None,
123-
Some(StateRestorer::new(
124-
shmem_provider.new_shmem(0x1000).unwrap(),
125-
)),
126-
)?,
127-
),
107+
SimpleEventManager::new(monitor),
128108
ClientDescription::new(0, 0, CoreId(0)),
129109
);
130110
}

fuzzers/binary_only/qemu_launcher/tests/qasan/test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ tests_expected=(
2525
"is 0 bytes to the right of the 10-byte chunk"
2626
"is 1 bytes to the left of the 10-byte chunk"
2727
"is 0 bytes inside the 10-byte chunk"
28-
"is 0 bytes to the right of the 10-byte chunk"
28+
"Invalid 11 bytes write at"
2929
"is 0 bytes inside the 10-byte chunk"
3030
"Test-Limits - No Error"
3131
)

libafl/src/executors/hooks/inprocess.rs

Lines changed: 75 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use core::{
1212

1313
#[cfg(all(target_os = "linux", feature = "std"))]
1414
use libafl_bolts::current_time;
15+
#[cfg(all(unix, feature = "std"))]
16+
use libafl_bolts::minibsod::{generate_minibsod_to_vec, BsodInfo};
1517
#[cfg(all(unix, feature = "std", not(miri)))]
1618
use libafl_bolts::os::unix_signals::setup_signal_handler;
1719
#[cfg(all(windows, feature = "std"))]
@@ -21,15 +23,20 @@ use windows::Win32::System::Threading::{CRITICAL_SECTION, PTP_TIMER};
2123

2224
#[cfg(feature = "std")]
2325
use crate::executors::hooks::timer::TimerStruct;
24-
#[cfg(all(unix, feature = "std"))]
25-
use crate::executors::hooks::unix::unix_signal_handler;
2626
use crate::{
2727
events::{EventFirer, EventRestarter},
2828
executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers},
2929
feedbacks::Feedback,
3030
state::{HasExecutions, HasSolutions},
3131
Error, HasObjective,
3232
};
33+
#[cfg(all(unix, feature = "std"))]
34+
use crate::{
35+
executors::{
36+
hooks::unix::unix_signal_handler, inprocess::run_observers_and_save_state, ExitKind,
37+
},
38+
state::HasCorpus,
39+
};
3340
#[cfg(any(unix, windows))]
3441
use crate::{inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
3542

@@ -386,52 +393,111 @@ unsafe impl Sync for InProcessExecutorHandlerData {}
386393
impl InProcessExecutorHandlerData {
387394
/// # Safety
388395
/// Only safe if not called twice and if the executor is not used from another borrow after this.
389-
#[cfg(any(unix, feature = "std"))]
396+
#[cfg(all(feature = "std", any(unix, windows)))]
390397
pub(crate) unsafe fn executor_mut<'a, E>(&self) -> &'a mut E {
391398
unsafe { (self.executor_ptr as *mut E).as_mut().unwrap() }
392399
}
393400

394401
/// # Safety
395402
/// Only safe if not called twice and if the state is not used from another borrow after this.
396-
#[cfg(any(unix, feature = "std"))]
403+
#[cfg(all(feature = "std", any(unix, windows)))]
397404
pub(crate) unsafe fn state_mut<'a, S>(&self) -> &'a mut S {
398405
unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
399406
}
400407

401408
/// # Safety
402409
/// Only safe if not called twice and if the event manager is not used from another borrow after this.
403-
#[cfg(any(unix, feature = "std"))]
410+
#[cfg(all(feature = "std", any(unix, windows)))]
404411
pub(crate) unsafe fn event_mgr_mut<'a, EM>(&self) -> &'a mut EM {
405412
unsafe { (self.event_mgr_ptr as *mut EM).as_mut().unwrap() }
406413
}
407414

408415
/// # Safety
409416
/// Only safe if not called twice and if the fuzzer is not used from another borrow after this.
410-
#[cfg(any(unix, feature = "std"))]
417+
#[cfg(all(feature = "std", any(unix, windows)))]
411418
pub(crate) unsafe fn fuzzer_mut<'a, Z>(&self) -> &'a mut Z {
412419
unsafe { (self.fuzzer_ptr as *mut Z).as_mut().unwrap() }
413420
}
414421

415422
/// # Safety
416423
/// Only safe if not called concurrently.
417-
#[cfg(any(unix, feature = "std"))]
424+
#[cfg(all(feature = "std", any(unix, windows)))]
418425
pub(crate) unsafe fn take_current_input<'a, I>(&mut self) -> &'a I {
419426
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
420427
self.current_input_ptr = ptr::null();
421428
r
422429
}
423430

424-
#[cfg(any(unix, feature = "std"))]
431+
#[cfg(all(feature = "std", any(unix, windows)))]
425432
pub(crate) fn is_valid(&self) -> bool {
426433
!self.current_input_ptr.is_null()
427434
}
428435

429-
#[cfg(any(unix, feature = "std"))]
436+
#[cfg(all(feature = "std", any(unix, windows)))]
430437
pub(crate) fn set_in_handler(&mut self, v: bool) -> bool {
431438
let old = self.in_handler;
432439
self.in_handler = v;
433440
old
434441
}
442+
443+
/// if data is valid, safely report a crash and return true.
444+
/// return false otherwise.
445+
///
446+
/// # Safety
447+
///
448+
/// Should only be called to signal a crash in the target
449+
#[cfg(all(unix, feature = "std"))]
450+
pub unsafe fn maybe_report_crash<E, EM, I, OF, S, Z>(
451+
&mut self,
452+
bsod_info: Option<BsodInfo>,
453+
) -> bool
454+
where
455+
E: Executor<EM, I, S, Z> + HasObservers,
456+
E::Observers: ObserversTuple<I, S>,
457+
EM: EventFirer<I, S> + EventRestarter<S>,
458+
OF: Feedback<EM, I, E::Observers, S>,
459+
S: HasExecutions + HasSolutions<I> + HasCorpus<I> + HasCurrentTestcase<I>,
460+
Z: HasObjective<Objective = OF>,
461+
I: Input + Clone,
462+
{
463+
if self.is_valid() {
464+
let executor = self.executor_mut::<E>();
465+
// disarms timeout in case of timeout
466+
let state = self.state_mut::<S>();
467+
let event_mgr = self.event_mgr_mut::<EM>();
468+
let fuzzer = self.fuzzer_mut::<Z>();
469+
let input = self.take_current_input::<I>();
470+
471+
log::error!("Target crashed!");
472+
473+
if let Some(bsod_info) = bsod_info {
474+
let bsod = generate_minibsod_to_vec(
475+
bsod_info.signal,
476+
&bsod_info.siginfo,
477+
bsod_info.ucontext.as_ref(),
478+
);
479+
480+
if let Ok(bsod) = bsod {
481+
if let Ok(r) = std::str::from_utf8(&bsod) {
482+
log::error!("{}", r);
483+
}
484+
}
485+
}
486+
487+
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
488+
executor,
489+
state,
490+
input,
491+
fuzzer,
492+
event_mgr,
493+
ExitKind::Crash,
494+
);
495+
496+
return true;
497+
}
498+
499+
false
500+
}
435501
}
436502

437503
/// Exception handling needs some nasty unsafe.

libafl/src/executors/inprocess/mod.rs

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@ use core::{
1414

1515
use libafl_bolts::tuples::{tuple_list, RefIndexable};
1616

17-
#[cfg(any(unix, feature = "std"))]
18-
use crate::executors::hooks::inprocess::GLOBAL_STATE;
19-
#[cfg(any(unix, feature = "std"))]
20-
use crate::ExecutionProcessor;
2117
use crate::{
2218
corpus::{Corpus, Testcase},
2319
events::{Event, EventFirer, EventRestarter},
@@ -436,45 +432,6 @@ pub fn run_observers_and_save_state<E, EM, I, OF, S, Z>(
436432
log::info!("Bye!");
437433
}
438434

439-
// TODO remove this after executor refactor and libafl qemu new executor
440-
/// Expose a version of the crash handler that can be called from e.g. an emulator
441-
///
442-
/// # Safety
443-
/// This will directly access `GLOBAL_STATE` and related data pointers
444-
#[cfg(any(unix, feature = "std"))]
445-
pub unsafe fn generic_inproc_crash_handler<E, EM, I, OF, S, Z>()
446-
where
447-
E: Executor<EM, I, S, Z> + HasObservers,
448-
E::Observers: ObserversTuple<I, S>,
449-
EM: EventFirer<I, S> + EventRestarter<S>,
450-
OF: Feedback<EM, I, E::Observers, S>,
451-
S: HasExecutions + HasSolutions<I> + HasCurrentTestcase<I>,
452-
I: Input + Clone,
453-
Z: HasObjective<Objective = OF> + ExecutionProcessor<EM, I, E::Observers, S>,
454-
{
455-
let data = &raw mut GLOBAL_STATE;
456-
let in_handler = (*data).set_in_handler(true);
457-
458-
if (*data).is_valid() {
459-
let executor = (*data).executor_mut::<E>();
460-
let state = (*data).state_mut::<S>();
461-
let event_mgr = (*data).event_mgr_mut::<EM>();
462-
let fuzzer = (*data).fuzzer_mut::<Z>();
463-
let input = (*data).take_current_input::<I>();
464-
465-
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
466-
executor,
467-
state,
468-
input,
469-
fuzzer,
470-
event_mgr,
471-
ExitKind::Crash,
472-
);
473-
}
474-
475-
(*data).set_in_handler(in_handler);
476-
}
477-
478435
#[cfg(test)]
479436
mod tests {
480437
use libafl_bolts::{rands::XkcdRand, tuples::tuple_list};

libafl_bolts/src/minibsod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use core::mem::size_of;
66
use std::io::{BufWriter, Write};
77
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
88
use std::process::Command;
9+
#[cfg(unix)]
10+
use std::vec::Vec;
911

1012
#[cfg(unix)]
1113
use libc::siginfo_t;
@@ -24,6 +26,18 @@ use windows::Win32::System::Diagnostics::Debug::{CONTEXT, EXCEPTION_POINTERS};
2426
#[cfg(unix)]
2527
use crate::os::unix_signals::{ucontext_t, Signal};
2628

29+
/// Necessary info to print a mini-BSOD.
30+
#[derive(Debug)]
31+
#[cfg(unix)]
32+
pub struct BsodInfo {
33+
/// the signal
34+
pub signal: Signal,
35+
/// siginfo
36+
pub siginfo: siginfo_t,
37+
/// ucontext
38+
pub ucontext: Option<ucontext_t>,
39+
}
40+
2741
/// Write the content of all important registers
2842
#[cfg(all(
2943
any(target_os = "linux", target_os = "android"),
@@ -1110,6 +1124,24 @@ pub fn generate_minibsod<W: Write>(
11101124
write_minibsod(writer)
11111125
}
11121126

1127+
/// Generates a mini-BSOD given a signal and context and dump it to a [`Vec`]
1128+
#[cfg(unix)]
1129+
pub fn generate_minibsod_to_vec(
1130+
signal: Signal,
1131+
siginfo: &siginfo_t,
1132+
ucontext: Option<&ucontext_t>,
1133+
) -> Result<Vec<u8>, std::io::Error> {
1134+
let mut bsod = Vec::new();
1135+
{
1136+
let mut writer = BufWriter::new(&mut bsod);
1137+
1138+
generate_minibsod(&mut writer, signal, siginfo, ucontext)?;
1139+
1140+
writer.flush()?;
1141+
}
1142+
Ok(bsod)
1143+
}
1144+
11131145
/// Generates a mini-BSOD given an `EXCEPTION_POINTERS` structure.
11141146
#[cfg(windows)]
11151147
#[expect(clippy::non_ascii_literal, clippy::not_unsafe_ptr_arg_deref)]

libafl_qemu/libafl_qemu_build/src/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::cargo_add_rpath;
1111

1212
pub const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
1313
pub const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
14-
pub const QEMU_REVISION: &str = "7e0dc68430c509ad50c6b0c9887f7e642a4bba2d";
14+
pub const QEMU_REVISION: &str = "695657e4f3f408c34b146d5191b102d5eb99b74b";
1515

1616
pub struct BuildResult {
1717
pub qemu_path: PathBuf,

0 commit comments

Comments
 (0)