LibAFL_qemu: Return errors from Emulator::new
instead of asserting (#1197)
* qemu: Return errors from Emulator::new instead of asserting Libraries should not `assert!` except in cases of unrecoverable (library) programmer error. These errors are all potentially recoverable, and aren't internal errors in `libafl_qemu` itself. * Respond to review comments
This commit is contained in:
parent
21ee8d2cae
commit
aa3f126100
@ -147,7 +147,7 @@ fn fuzz(
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
let emu = Emulator::new(&args, &env);
|
||||
let emu = Emulator::new(&args, &env)?;
|
||||
|
||||
let mut elf_buffer = Vec::new();
|
||||
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer)?;
|
||||
|
@ -171,7 +171,7 @@ fn fuzz(
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
let emu = Emulator::new(&args, &env);
|
||||
let emu = Emulator::new(&args, &env).unwrap();
|
||||
//let emu = init_with_asan(&mut args, &mut env);
|
||||
|
||||
let mut elf_buffer = Vec::new();
|
||||
|
@ -54,7 +54,7 @@ pub fn fuzz() {
|
||||
env::remove_var("LD_LIBRARY_PATH");
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
let emu = Emulator::new(&args, &env);
|
||||
let emu = Emulator::new(&args, &env).unwrap();
|
||||
|
||||
let mut elf_buffer = Vec::new();
|
||||
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer).unwrap();
|
||||
|
@ -54,7 +54,7 @@ pub fn fuzz() {
|
||||
env::remove_var("LD_LIBRARY_PATH");
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
let emu = Emulator::new(&args, &env);
|
||||
let emu = Emulator::new(&args, &env).unwrap();
|
||||
|
||||
let mut elf_buffer = Vec::new();
|
||||
let elf = EasyElf::from_file(emu.binary_path(), &mut elf_buffer).unwrap();
|
||||
|
@ -80,7 +80,7 @@ pub fn fuzz() {
|
||||
// Initialize QEMU
|
||||
let args: Vec<String> = env::args().collect();
|
||||
let env: Vec<(String, String)> = env::vars().collect();
|
||||
let emu = Emulator::new(&args, &env);
|
||||
let emu = Emulator::new(&args, &env).unwrap();
|
||||
|
||||
emu.set_breakpoint(main_addr);
|
||||
unsafe {
|
||||
|
@ -41,7 +41,7 @@
|
||||
//!
|
||||
//! let env: Vec<(String, String)> = env::vars().collect();
|
||||
//!
|
||||
//! let emu = Emulator::new(&mut options.qemu_args.to_vec(), &mut env);
|
||||
//! let emu = Emulator::new(&mut options.qemu_args.to_vec(), &mut env).unwrap();
|
||||
//! // do other stuff...
|
||||
//! }
|
||||
//!
|
||||
|
@ -16,7 +16,7 @@ use meminterval::{Interval, IntervalTree};
|
||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||
|
||||
use crate::{
|
||||
emu::{Emulator, MemAccessInfo, SyscallHookResult},
|
||||
emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult},
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
GuestAddr,
|
||||
@ -454,8 +454,10 @@ impl AsanGiovese {
|
||||
|
||||
static mut ASAN_INITED: bool = false;
|
||||
|
||||
pub fn init_with_asan(args: &mut Vec<String>, env: &mut [(String, String)]) -> Emulator {
|
||||
assert!(!args.is_empty());
|
||||
pub fn init_with_asan(
|
||||
args: &mut Vec<String>,
|
||||
env: &mut [(String, String)],
|
||||
) -> Result<Emulator, EmuError> {
|
||||
let current = env::current_exe().unwrap();
|
||||
let asan_lib = fs::canonicalize(current)
|
||||
.unwrap()
|
||||
|
@ -3,6 +3,7 @@
|
||||
use core::{
|
||||
convert::Into,
|
||||
ffi::c_void,
|
||||
fmt,
|
||||
mem::MaybeUninit,
|
||||
ptr::{addr_of, copy_nonoverlapping, null},
|
||||
};
|
||||
@ -673,28 +674,68 @@ pub struct Emulator {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum EmuError {
|
||||
MultipleInstances,
|
||||
EmptyArgs,
|
||||
TooManyArgs(usize),
|
||||
}
|
||||
|
||||
impl std::error::Error for EmuError {}
|
||||
|
||||
impl fmt::Display for EmuError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
EmuError::MultipleInstances => {
|
||||
write!(f, "Only one instance of the QEMU Emulator is permitted")
|
||||
}
|
||||
EmuError::EmptyArgs => {
|
||||
write!(f, "QEMU emulator args cannot be empty")
|
||||
}
|
||||
EmuError::TooManyArgs(n) => {
|
||||
write!(
|
||||
f,
|
||||
"Too many arguments passed to QEMU emulator ({n} > i32::MAX)"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EmuError> for libafl::Error {
|
||||
fn from(err: EmuError) -> Self {
|
||||
libafl::Error::unknown(format!("{err}"))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
impl Emulator {
|
||||
#[allow(clippy::must_use_candidate, clippy::similar_names)]
|
||||
pub fn new(args: &[String], env: &[(String, String)]) -> Emulator {
|
||||
pub fn new(args: &[String], env: &[(String, String)]) -> Result<Emulator, EmuError> {
|
||||
unsafe {
|
||||
assert!(
|
||||
!EMULATOR_IS_INITIALIZED,
|
||||
"Only an instance of Emulator is permitted"
|
||||
);
|
||||
if EMULATOR_IS_INITIALIZED {
|
||||
return Err(EmuError::MultipleInstances);
|
||||
}
|
||||
assert!(!args.is_empty());
|
||||
}
|
||||
if args.is_empty() {
|
||||
return Err(EmuError::EmptyArgs);
|
||||
}
|
||||
|
||||
let argc = args.len();
|
||||
if i32::try_from(argc).is_err() {
|
||||
return Err(EmuError::TooManyArgs(argc));
|
||||
}
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let argc = argc as i32;
|
||||
|
||||
let args: Vec<String> = args.iter().map(|x| x.clone() + "\0").collect();
|
||||
let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect();
|
||||
assert!(argv.len() < i32::MAX as usize);
|
||||
let env_strs: Vec<String> = env
|
||||
.iter()
|
||||
.map(|(k, v)| format!("{}={}\0", &k, &v))
|
||||
.collect();
|
||||
let mut envp: Vec<*const u8> = env_strs.iter().map(|x| x.as_bytes().as_ptr()).collect();
|
||||
envp.push(null());
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let argc = argv.len() as i32;
|
||||
unsafe {
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
qemu_user_init(
|
||||
@ -714,7 +755,7 @@ impl Emulator {
|
||||
}
|
||||
EMULATOR_IS_INITIALIZED = true;
|
||||
}
|
||||
Emulator { _private: () }
|
||||
Ok(Emulator { _private: () })
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
@ -1174,10 +1215,10 @@ pub mod pybind {
|
||||
impl Emulator {
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
#[new]
|
||||
fn new(args: Vec<String>, env: Vec<(String, String)>) -> Emulator {
|
||||
Emulator {
|
||||
emu: super::Emulator::new(&args, &env),
|
||||
}
|
||||
fn new(args: Vec<String>, env: Vec<(String, String)>) -> PyResult<Emulator> {
|
||||
let emu = super::Emulator::new(&args, &env)
|
||||
.map_err(|e| PyValueError::new_err(format!("{e}")))?;
|
||||
Ok(Emulator { emu })
|
||||
}
|
||||
|
||||
fn write_mem(&self, addr: GuestAddr, buf: &[u8]) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user