Skip to content

Commit d15c33e

Browse files
committed
adapt to usermode
1 parent 5fab625 commit d15c33e

File tree

9 files changed

+180
-81
lines changed

9 files changed

+180
-81
lines changed

crates/libafl_qemu/src/command/lqemu/mod.rs

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,21 @@ use paste::paste;
1515
pub mod parser;
1616
use parser::{
1717
EndCommandParser, LoadCommandParser, LqprintfCommandParser, SaveCommandParser,
18-
SetMapCommandParser, StartPhysCommandParser, StartVirtCommandParser, TestCommandParser,
19-
VaddrFilterAllowRangeCommandParser, VersionCommandParser,
18+
StartVirtCommandParser, TestCommandParser, VaddrFilterAllowRangeCommandParser,
19+
VersionCommandParser,
2020
};
21+
#[cfg(feature = "systemmode")]
22+
use parser::{SetMapCommandParser, StartPhysCommandParser};
2123

2224
use super::{CommandError, IsCommand, IsStdCommandManager};
2325
use crate::{
2426
Emulator, EmulatorDriverError, EmulatorDriverResult, EmulatorExitResult, GuestReg,
25-
InputLocation, InputSetter, IsSnapshotManager, MapKind, QemuMemoryChunk, Regs,
26-
StdEmulatorDriver, define_std_command_manager_bound, define_std_command_manager_inner,
27+
InputLocation, InputSetter, IsSnapshotManager, Regs, StdEmulatorDriver,
28+
define_std_command_manager_bound, define_std_command_manager_inner,
2729
modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
2830
};
31+
#[cfg(feature = "systemmode")]
32+
use crate::{MapKind, QemuMemoryChunk};
2933

3034
mod bindings {
3135
#![expect(non_upper_case_globals)]
@@ -43,6 +47,33 @@ mod bindings {
4347
pub const VERSION_MAJOR: u64 = bindings::LQEMU_VERSION_MAJOR as u64;
4448
pub const VERSION_MINOR: u64 = bindings::LQEMU_VERSION_MINOR as u64;
4549

50+
#[cfg(feature = "usermode")]
51+
define_std_command_manager_bound!(
52+
StdCommandManager,
53+
HasTargetBytes,
54+
[
55+
StartCommand,
56+
SaveCommand,
57+
LoadCommand,
58+
EndCommand,
59+
VersionCommand,
60+
AddressAllowCommand,
61+
LqprintfCommand,
62+
TestCommand
63+
],
64+
[
65+
StartVirtCommandParser,
66+
SaveCommandParser,
67+
LoadCommandParser,
68+
EndCommandParser,
69+
VersionCommandParser,
70+
VaddrFilterAllowRangeCommandParser,
71+
LqprintfCommandParser,
72+
TestCommandParser
73+
]
74+
);
75+
76+
#[cfg(feature = "systemmode")]
4677
define_std_command_manager_bound!(
4778
StdCommandManager,
4879
HasTargetBytes,
@@ -142,7 +173,7 @@ where
142173

143174
#[derive(Debug, Clone)]
144175
pub struct StartCommand {
145-
input_location: QemuMemoryChunk,
176+
input_location: InputLocation,
146177
}
147178

148179
impl<C, CM, ET, I, IS, S, SM> IsCommand<C, CM, StdEmulatorDriver<IS>, ET, I, S, SM> for StartCommand
@@ -161,7 +192,7 @@ where
161192
fn run(
162193
&self,
163194
emu: &mut Emulator<C, CM, StdEmulatorDriver<IS>, ET, I, S, SM>,
164-
ret_reg: Option<Regs>,
195+
_ret_reg: Option<Regs>,
165196
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
166197
let qemu = emu.qemu();
167198

@@ -177,7 +208,7 @@ where
177208
// Save input location for next runs
178209
emu.driver_mut()
179210
.input_setter_mut()
180-
.set_input_location(InputLocation::new(qemu, &self.input_location, ret_reg))?;
211+
.set_input_location(self.input_location.clone())?;
181212

182213
// Auto page filtering if option is enabled
183214
#[cfg(feature = "systemmode")]
@@ -383,11 +414,14 @@ where
383414
}
384415
}
385416

417+
#[cfg(feature = "systemmode")]
386418
#[derive(Debug, Clone)]
387419
pub struct SetMapCommand {
388420
kind: MapKind,
389421
map: QemuMemoryChunk,
390422
}
423+
424+
#[cfg(feature = "systemmode")]
391425
impl<C, CM, ET, I, IS, S, SM> IsCommand<C, CM, StdEmulatorDriver<IS>, ET, I, S, SM>
392426
for SetMapCommand
393427
where
@@ -421,6 +455,7 @@ where
421455
}
422456
}
423457

458+
#[cfg(feature = "systemmode")]
424459
impl SetMapCommand {
425460
pub fn new(kind: MapKind, map: QemuMemoryChunk) -> Self {
426461
Self { kind, map }
@@ -472,11 +507,7 @@ impl Display for LoadCommand {
472507

473508
impl Display for StartCommand {
474509
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
475-
write!(
476-
f,
477-
"Start fuzzing with input @{}",
478-
self.input_location.addr()
479-
)
510+
write!(f, "Start fuzzing with input @{:?}", self.input_location)
480511
}
481512
}
482513

@@ -507,7 +538,7 @@ impl Display for PageAllowCommand {
507538

508539
impl StartCommand {
509540
#[must_use]
510-
pub fn new(input_location: QemuMemoryChunk) -> Self {
541+
pub fn new(input_location: InputLocation) -> Self {
511542
Self { input_location }
512543
}
513544
}

crates/libafl_qemu/src/command/lqemu/parser.rs

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
1+
#[cfg(feature = "usermode")]
2+
use std::slice;
13
use std::{ffi::CStr, sync::OnceLock};
24

35
use enum_map::{EnumMap, enum_map};
46
use libafl::{executors::ExitKind, inputs::HasTargetBytes};
5-
use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr};
7+
#[cfg(feature = "systemmode")]
8+
use libafl_qemu_sys::GuestPhysAddr;
9+
use libafl_qemu_sys::{GuestAddr, GuestVirtAddr};
610
use libc::c_uint;
711

812
use super::{
913
AddressAllowCommand, EndCommand, LoadCommand, LqprintfCommand, NativeExitKind, SaveCommand,
1014
StartCommand, TestCommand, VersionCommand, bindings,
1115
};
1216
use crate::{
13-
GuestReg, InputSetter, IsSnapshotManager, MapKind, Qemu, QemuMemoryChunk, Regs,
17+
GuestReg, InputLocation, InputSetter, IsSnapshotManager, Qemu, QemuMemoryChunk, Regs,
1418
StdEmulatorDriver,
15-
command::{
16-
CommandError, CommandManager, NativeCommandParser, StdCommandManager, lqemu::SetMapCommand,
17-
},
19+
command::{CommandError, CommandManager, NativeCommandParser, StdCommandManager},
1820
modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
1921
sync_exit::ExitArgs,
2022
};
23+
#[cfg(feature = "systemmode")]
24+
use crate::{MapKind, command::lqemu::SetMapCommand};
2125

2226
pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new();
2327

28+
#[cfg(feature = "systemmode")]
2429
pub struct StartPhysCommandParser;
2530

31+
#[cfg(feature = "systemmode")]
2632
impl<C, ET, I, IS, S, SM>
2733
NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver<IS>, ET, I, S, SM>
2834
for StartPhysCommandParser
@@ -44,10 +50,12 @@ where
4450
let input_phys_addr: GuestPhysAddr = qemu.read_reg(arch_regs_map[ExitArgs::Arg1])?.into();
4551
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
4652

47-
Ok(StartCommand::new(QemuMemoryChunk::phys(
48-
input_phys_addr,
49-
max_input_size,
50-
Some(qemu.current_cpu().unwrap()),
53+
let memory_chunk =
54+
QemuMemoryChunk::phys(input_phys_addr, max_input_size, qemu.current_cpu());
55+
56+
Ok(StartCommand::new(InputLocation::new(
57+
memory_chunk,
58+
Some(arch_regs_map[ExitArgs::Ret]),
5159
)))
5260
}
5361
}
@@ -76,11 +84,28 @@ where
7684
qemu.read_reg(arch_regs_map[ExitArgs::Arg1])? as GuestVirtAddr;
7785
let max_input_size: GuestReg = qemu.read_reg(arch_regs_map[ExitArgs::Arg2])?;
7886

79-
Ok(StartCommand::new(QemuMemoryChunk::virt(
80-
input_virt_addr,
81-
max_input_size,
82-
qemu.current_cpu().unwrap(),
83-
)))
87+
#[cfg(feature = "usermode")]
88+
{
89+
let memory_chunk = unsafe {
90+
slice::from_raw_parts(input_virt_addr as *const u8, max_input_size as usize)
91+
};
92+
93+
Ok(StartCommand::new(InputLocation::new(
94+
Box::from(memory_chunk),
95+
Some(arch_regs_map[ExitArgs::Ret]),
96+
)))
97+
}
98+
99+
#[cfg(feature = "systemmode")]
100+
{
101+
let memory_chunk =
102+
QemuMemoryChunk::virt(input_virt_addr, max_input_size, qemu.current_cpu().unwrap());
103+
104+
Ok(StartCommand::new(InputLocation::new(
105+
memory_chunk,
106+
Some(arch_regs_map[ExitArgs::Ret]),
107+
)))
108+
}
84109
}
85110
}
86111

@@ -259,7 +284,9 @@ where
259284
}
260285
}
261286

287+
#[cfg(feature = "systemmode")]
262288
pub struct SetMapCommandParser;
289+
#[cfg(feature = "systemmode")]
263290
impl<C, CM, ET, I, IS, S, SM> NativeCommandParser<C, CM, StdEmulatorDriver<IS>, ET, I, S, SM>
264291
for SetMapCommandParser
265292
where

crates/libafl_qemu/src/emu/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<C, I, S>
5959
}
6060

6161
#[cfg(feature = "usermode")]
62-
impl<C, I, IS, S>
62+
impl<C, I, S>
6363
EmulatorBuilder<
6464
C,
6565
StdCommandManager<S>,

crates/libafl_qemu/src/emu/drivers/mod.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! Emulator Drivers, as the name suggests, drive QEMU execution
22
//! They are used to perform specific actions on the emulator before and / or after QEMU runs.
33
4-
use std::{cell::OnceCell, collections::HashMap, fmt::Debug};
4+
#[cfg(feature = "systemmode")]
5+
use std::collections::HashMap;
6+
use std::{cell::OnceCell, fmt::Debug};
57

68
use libafl::{executors::ExitKind, inputs::HasTargetBytes, observers::ObserversTuple};
79
use libafl_bolts::{
@@ -111,16 +113,12 @@ where
111113
input: &I,
112114
) -> Result<(), EmulatorDriverError> {
113115
if let Some(input_location) = self.input_location.get_mut() {
114-
let ret_value = unsafe {
115-
input_location
116-
.segments
117-
.write(input.target_bytes().as_slice())
118-
};
116+
let ret_value = input_location.write(input.target_bytes().as_slice());
119117

120-
if let Some(reg) = input_location.ret_register {
118+
if let Some(reg) = input_location.ret_register() {
121119
qemu.current_cpu()
122120
.unwrap() // if we end up there, qemu must be running the cpu asking for the input
123-
.write_reg(reg, ret_value as GuestReg)
121+
.write_reg(*reg, ret_value as GuestReg)
124122
.unwrap();
125123
}
126124
}
@@ -350,6 +348,7 @@ impl<IS> StdEmulatorDriverBuilder<IS> {
350348
#[cfg(feature = "x86_64")]
351349
process_only: self.process_only,
352350
print_commands: self.print_commands,
351+
#[cfg(feature = "systemmode")]
353352
maps: HashMap::new(),
354353
}
355354
}

crates/libafl_qemu/src/emu/mod.rs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestUsize, GuestVirtAddr};
1414
#[cfg(doc)]
1515
use crate::modules::EmulatorModule;
1616
use crate::{
17-
HostMemorySegments, Qemu, QemuExitError, QemuExitReason, QemuHooks, QemuInitError,
18-
QemuMemoryChunk, QemuParams, QemuShutdownCause, Regs,
17+
Qemu, QemuExitError, QemuExitReason, QemuHooks, QemuInitError, QemuParams, QemuShutdownCause,
1918
breakpoint::{Breakpoint, BreakpointId},
2019
command::{CommandError, CommandManager, NopCommandManager, StdCommandManager},
2120
modules::EmulatorModuleTuple,
@@ -98,16 +97,6 @@ pub enum EmulatorExitError {
9897
BreakpointNotFound(GuestAddr),
9998
}
10099

101-
/// The fuzzing input location.
102-
///
103-
/// We store the memory segments to which the input should be written,
104-
/// and the return register containing the number bytes effectively written.
105-
#[derive(Debug, Clone)]
106-
pub struct InputLocation {
107-
segments: HostMemorySegments,
108-
ret_register: Option<Regs>,
109-
}
110-
111100
/// The high-level interface to [`Qemu`].
112101
///
113102
/// It embeds multiple structures aiming at making QEMU usage easier:
@@ -188,28 +177,6 @@ impl From<SnapshotManagerCheckError> for EmulatorDriverError {
188177
}
189178
}
190179

191-
impl InputLocation {
192-
#[must_use]
193-
pub fn new(qemu: Qemu, mem_chunk: &QemuMemoryChunk, ret_register: Option<Regs>) -> Self {
194-
let segments = mem_chunk.to_host_segments(qemu);
195-
196-
Self {
197-
segments,
198-
ret_register,
199-
}
200-
}
201-
202-
#[must_use]
203-
pub fn segments(&self) -> &HostMemorySegments {
204-
&self.segments
205-
}
206-
207-
#[must_use]
208-
pub fn ret_register(&self) -> &Option<Regs> {
209-
&self.ret_register
210-
}
211-
}
212-
213180
impl From<EmulatorExitError> for EmulatorDriverError {
214181
fn from(error: EmulatorExitError) -> Self {
215182
EmulatorDriverError::QemuExitReasonError(error)

crates/libafl_qemu/src/emu/systemmode.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,42 @@ pub enum SnapshotManager {
1616

1717
pub type StdSnapshotManager = FastSnapshotManager;
1818

19+
/// The fuzzing input location.
20+
///
21+
/// We store the memory location to which the input should be written,
22+
/// and the return register containing the number bytes effectively written.
23+
#[derive(Debug, Clone)]
24+
pub struct InputLocation {
25+
location: HostMemorySegments,
26+
ret_register: Option<Regs>,
27+
}
28+
29+
impl InputLocation {
30+
#[must_use]
31+
pub fn new(qemu: Qemu, mem_chunk: &QemuMemoryChunk, ret_register: Option<Regs>) -> Self {
32+
let location = mem_chunk.to_host_segments(qemu);
33+
34+
Self {
35+
location,
36+
ret_register,
37+
}
38+
}
39+
40+
#[must_use]
41+
pub fn location(&self) -> &HostMemorySegments {
42+
&self.location
43+
}
44+
45+
#[must_use]
46+
pub fn ret_register(&self) -> &Option<Regs> {
47+
&self.ret_register
48+
}
49+
50+
pub fn write(&mut self, input: &[u8]) -> usize {
51+
self.location.segments.write(input)
52+
}
53+
}
54+
1955
impl IsSnapshotManager for SnapshotManager {
2056
fn save(&mut self, qemu: Qemu) -> SnapshotId {
2157
match self {

0 commit comments

Comments
 (0)