Skip to content

Commit 3547c13

Browse files
rmalmainmzfr
authored andcommitted
Refactor of Qemu configuration (AFLplusplus#2707)
* Qemu config refactoring. * QEMU error refactoring. * Single QEMU init function. * Light refactor of EmulatorModules. * Qemu is now a parameter to EmulatorModule callbacks and most function hooks. * EmulatorModules is initialized before QEMU is initialized. * refactor asan and asanguest modules to avoid custom init of QEMU and use the module interface instead. * asan fixed size accesses working with generics. * use pre_syscall_* and post_syscall_* everywhere for consistency. * adapt qemu_launcher example to fully work with Emulator, since Qemu must now be initialized by Emulator. * start writing Emulator / EmulatorBuilder / QemuConfig doc. * fix broken intel pt doc.
1 parent 21b0779 commit 3547c13

File tree

40 files changed

+1428
-1307
lines changed

40 files changed

+1428
-1307
lines changed

fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ fn fuzz(
176176
);
177177

178178
let emulator = Emulator::empty()
179-
.qemu_cli(args)
179+
.qemu_parameters(args)
180180
.modules(emulator_modules)
181181
.build()?;
182182

fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ use libafl_qemu::{
5555
GuestReg,
5656
//snapshot::QemuSnapshotHelper,
5757
MmapPerms,
58-
Qemu,
5958
QemuExecutor,
6059
QemuExitError,
6160
QemuExitReason,
@@ -175,8 +174,33 @@ fn fuzz(
175174
env::remove_var("LD_LIBRARY_PATH");
176175

177176
let args: Vec<String> = env::args().collect();
178-
let qemu = Qemu::init(&args).expect("QEMU init failed");
179-
// let (emu, asan) = init_with_asan(&mut args, &mut env).unwrap();
177+
178+
// Create an observation channel using the coverage map
179+
let mut edges_observer = unsafe {
180+
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
181+
"edges",
182+
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
183+
&raw mut MAX_EDGES_FOUND,
184+
))
185+
.track_indices()
186+
};
187+
188+
let modules = tuple_list!(
189+
StdEdgeCoverageModule::builder()
190+
.map_observer(edges_observer.as_mut())
191+
.build()
192+
.unwrap(),
193+
CmpLogModule::default(),
194+
// QemuAsanHelper::default(asan),
195+
//QemuSnapshotHelper::new()
196+
);
197+
198+
let emulator = Emulator::empty()
199+
.qemu_parameters(args)
200+
.modules(modules)
201+
.build()?;
202+
203+
let qemu = emulator.qemu();
180204

181205
let mut elf_buffer = Vec::new();
182206
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
@@ -255,16 +279,6 @@ fn fuzz(
255279
},
256280
};
257281

258-
// Create an observation channel using the coverage map
259-
let mut edges_observer = unsafe {
260-
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
261-
"edges",
262-
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
263-
&raw mut MAX_EDGES_FOUND,
264-
))
265-
.track_indices()
266-
};
267-
268282
// Create an observation channel to keep track of the execution time
269283
let time_observer = TimeObserver::new("time");
270284

@@ -364,18 +378,6 @@ fn fuzz(
364378
ExitKind::Ok
365379
};
366380

367-
let modules = tuple_list!(
368-
StdEdgeCoverageModule::builder()
369-
.map_observer(edges_observer.as_mut())
370-
.build()
371-
.unwrap(),
372-
CmpLogModule::default(),
373-
// QemuAsanHelper::default(asan),
374-
//QemuSnapshotHelper::new()
375-
);
376-
377-
let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?;
378-
379381
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
380382
let executor = QemuExecutor::new(
381383
emulator,

fuzzers/binary_only/qemu_cmin/src/fuzzer.rs

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use libafl_bolts::{
2828
};
2929
use libafl_qemu::{
3030
elf::EasyElf, modules::edges::StdEdgeCoverageChildModule, ArchExtras, CallingConvention,
31-
Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuExitReason,
32-
QemuForkExecutor, QemuShutdownCause, Regs,
31+
Emulator, GuestAddr, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor,
32+
QemuShutdownCause, Regs,
3333
};
3434
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
3535

@@ -113,7 +113,31 @@ pub fn fuzz() -> Result<(), Error> {
113113
log::debug!("ARGS: {:#?}", options.args);
114114

115115
env::remove_var("LD_LIBRARY_PATH");
116-
let qemu = Qemu::init(&options.args).unwrap();
116+
117+
let mut shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
118+
119+
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
120+
let edges = edges_shmem.as_slice_mut();
121+
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
122+
123+
let mut edges_observer = unsafe {
124+
HitcountsMapObserver::new(ConstMapObserver::from_mut_ptr(
125+
"edges",
126+
NonNull::new(edges.as_mut_ptr())
127+
.expect("The edge map pointer is null.")
128+
.cast::<[u8; EDGES_MAP_DEFAULT_SIZE]>(),
129+
))
130+
};
131+
132+
let modules = tuple_list!(StdEdgeCoverageChildModule::builder()
133+
.const_map_observer(edges_observer.as_mut())
134+
.build()?);
135+
136+
let emulator = Emulator::empty()
137+
.qemu_parameters(options.args)
138+
.modules(modules)
139+
.build()?;
140+
let qemu = emulator.qemu();
117141

118142
let mut elf_buffer = Vec::new();
119143
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap();
@@ -139,8 +163,6 @@ pub fn fuzz() -> Result<(), Error> {
139163

140164
let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap();
141165

142-
let mut shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
143-
144166
let monitor = SimpleMonitor::with_user_monitor(|s| {
145167
println!("{s}");
146168
});
@@ -157,19 +179,6 @@ pub fn fuzz() -> Result<(), Error> {
157179
},
158180
};
159181

160-
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
161-
let edges = edges_shmem.as_slice_mut();
162-
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
163-
164-
let mut edges_observer = unsafe {
165-
HitcountsMapObserver::new(ConstMapObserver::from_mut_ptr(
166-
"edges",
167-
NonNull::new(edges.as_mut_ptr())
168-
.expect("The edge map pointer is null.")
169-
.cast::<[u8; EDGES_MAP_DEFAULT_SIZE]>(),
170-
))
171-
};
172-
173182
let mut feedback = MaxMapFeedback::new(&edges_observer);
174183

175184
let mut objective = ();
@@ -222,12 +231,6 @@ pub fn fuzz() -> Result<(), Error> {
222231
ExitKind::Ok
223232
};
224233

225-
let modules = tuple_list!(StdEdgeCoverageChildModule::builder()
226-
.const_map_observer(edges_observer.as_mut())
227-
.build()?);
228-
229-
let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?;
230-
231234
let mut executor = QemuForkExecutor::new(
232235
emulator,
233236
&mut harness,

fuzzers/binary_only/qemu_coverage/src/fuzzer.rs

Lines changed: 74 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use libafl_bolts::{
3131
use libafl_qemu::{
3232
elf::EasyElf,
3333
modules::{drcov::DrCovModule, StdAddressFilter},
34-
ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExecutor,
34+
ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, QemuExecutor,
3535
QemuExitReason, QemuRWError, QemuShutdownCause, Regs,
3636
};
3737

@@ -123,80 +123,93 @@ pub fn fuzz() {
123123

124124
env::remove_var("LD_LIBRARY_PATH");
125125

126-
let qemu = Qemu::init(&options.args).unwrap();
127-
128-
let mut elf_buffer = Vec::new();
129-
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap();
130-
131-
let test_one_input_ptr = elf
132-
.resolve_symbol("LLVMFuzzerTestOneInput", qemu.load_addr())
133-
.expect("Symbol LLVMFuzzerTestOneInput not found");
134-
log::debug!("LLVMFuzzerTestOneInput @ {test_one_input_ptr:#x}");
126+
let mut run_client = |state: Option<_>,
127+
mut mgr: LlmpRestartingEventManager<_, _, _>,
128+
client_description: ClientDescription| {
129+
let mut cov_path = options.coverage_path.clone();
135130

136-
qemu.entry_break(test_one_input_ptr);
131+
let emulator_modules = tuple_list!(DrCovModule::builder()
132+
.filter(StdAddressFilter::default())
133+
.filename(cov_path.clone())
134+
.full_trace(false)
135+
.build());
137136

138-
for m in qemu.mappings() {
139-
log::debug!(
140-
"Mapping: 0x{:016x}-0x{:016x}, {}",
141-
m.start(),
142-
m.end(),
143-
m.path().unwrap_or(&"<EMPTY>".to_string())
144-
);
145-
}
137+
let emulator = Emulator::empty()
138+
.qemu_parameters(options.args.clone())
139+
.modules(emulator_modules)
140+
.build()
141+
.expect("QEMU initialization failed");
142+
let qemu = emulator.qemu();
143+
144+
let mut elf_buffer = Vec::new();
145+
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer).unwrap();
146+
147+
let test_one_input_ptr = elf
148+
.resolve_symbol("LLVMFuzzerTestOneInput", qemu.load_addr())
149+
.expect("Symbol LLVMFuzzerTestOneInput not found");
150+
log::debug!("LLVMFuzzerTestOneInput @ {test_one_input_ptr:#x}");
151+
152+
qemu.entry_break(test_one_input_ptr);
153+
154+
for m in qemu.mappings() {
155+
log::debug!(
156+
"Mapping: 0x{:016x}-0x{:016x}, {}",
157+
m.start(),
158+
m.end(),
159+
m.path().unwrap_or(&"<EMPTY>".to_string())
160+
);
161+
}
146162

147-
let pc: GuestReg = qemu.read_reg(Regs::Pc).unwrap();
148-
log::debug!("Break at {pc:#x}");
163+
let pc: GuestReg = qemu.read_reg(Regs::Pc).unwrap();
164+
log::debug!("Break at {pc:#x}");
149165

150-
let ret_addr: GuestAddr = qemu.read_return_address().unwrap();
151-
log::debug!("Return address = {ret_addr:#x}");
166+
let ret_addr: GuestAddr = qemu.read_return_address().unwrap();
167+
log::debug!("Return address = {ret_addr:#x}");
152168

153-
qemu.set_breakpoint(ret_addr);
169+
qemu.set_breakpoint(ret_addr);
154170

155-
let input_addr = qemu
156-
.map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite)
157-
.unwrap();
158-
log::debug!("Placing input at {input_addr:#x}");
171+
let input_addr = qemu
172+
.map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite)
173+
.unwrap();
174+
log::debug!("Placing input at {input_addr:#x}");
159175

160-
let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap();
176+
let stack_ptr: GuestAddr = qemu.read_reg(Regs::Sp).unwrap();
161177

162-
let reset = |buf: &[u8], len: GuestReg| -> Result<(), QemuRWError> {
163-
unsafe {
164-
let _ = qemu.write_mem(input_addr, buf);
165-
qemu.write_reg(Regs::Pc, test_one_input_ptr)?;
166-
qemu.write_reg(Regs::Sp, stack_ptr)?;
167-
qemu.write_return_address(ret_addr)?;
168-
qemu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
169-
qemu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
178+
let reset = |buf: &[u8], len: GuestReg| -> Result<(), QemuRWError> {
179+
unsafe {
180+
let _ = qemu.write_mem(input_addr, buf);
181+
qemu.write_reg(Regs::Pc, test_one_input_ptr)?;
182+
qemu.write_reg(Regs::Sp, stack_ptr)?;
183+
qemu.write_return_address(ret_addr)?;
184+
qemu.write_function_argument(CallingConvention::Cdecl, 0, input_addr)?;
185+
qemu.write_function_argument(CallingConvention::Cdecl, 1, len)?;
170186

171-
match qemu.run() {
172-
Ok(QemuExitReason::Breakpoint(_)) => {}
173-
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => {
174-
process::exit(0)
187+
match qemu.run() {
188+
Ok(QemuExitReason::Breakpoint(_)) => {}
189+
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(
190+
Signal::SigInterrupt,
191+
))) => process::exit(0),
192+
_ => panic!("Unexpected QEMU exit."),
175193
}
176-
_ => panic!("Unexpected QEMU exit."),
177-
}
178-
179-
Ok(())
180-
}
181-
};
182194

183-
let mut harness =
184-
|_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| {
185-
let target = input.target_bytes();
186-
let mut buf = target.as_slice();
187-
let mut len = buf.len();
188-
if len > MAX_INPUT_SIZE {
189-
buf = &buf[0..MAX_INPUT_SIZE];
190-
len = MAX_INPUT_SIZE;
195+
Ok(())
191196
}
192-
let len = len as GuestReg;
193-
reset(buf, len).unwrap();
194-
ExitKind::Ok
195197
};
196198

197-
let mut run_client = |state: Option<_>,
198-
mut mgr: LlmpRestartingEventManager<_, _, _>,
199-
client_description: ClientDescription| {
199+
let mut harness =
200+
|_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| {
201+
let target = input.target_bytes();
202+
let mut buf = target.as_slice();
203+
let mut len = buf.len();
204+
if len > MAX_INPUT_SIZE {
205+
buf = &buf[0..MAX_INPUT_SIZE];
206+
len = MAX_INPUT_SIZE;
207+
}
208+
let len = len as GuestReg;
209+
reset(buf, len).unwrap();
210+
ExitKind::Ok
211+
};
212+
200213
let core_id = client_description.core_id();
201214
let core_idx = options
202215
.cores
@@ -232,23 +245,11 @@ pub fn fuzz() {
232245
let scheduler = QueueScheduler::new();
233246
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
234247

235-
let mut cov_path = options.coverage_path.clone();
236248
let coverage_name = cov_path.file_stem().unwrap().to_str().unwrap();
237249
let coverage_extension = cov_path.extension().unwrap_or_default().to_str().unwrap();
238250
let core = core_id.0;
239251
cov_path.set_file_name(format!("{coverage_name}-{core:03}.{coverage_extension}"));
240252

241-
let emulator_modules = tuple_list!(DrCovModule::builder()
242-
.filter(StdAddressFilter::default())
243-
.filename(cov_path)
244-
.full_trace(false)
245-
.build());
246-
247-
let emulator = Emulator::empty()
248-
.qemu(qemu)
249-
.modules(emulator_modules)
250-
.build()?;
251-
252253
let mut executor = QemuExecutor::new(
253254
emulator,
254255
&mut harness,

0 commit comments

Comments
 (0)