emu::current_cpu() is now the CPU that hitted the breakpoint in fullsystem (#910)

* emu::current_cpu() is now kept after vm stop and it is the CPU that hitted the breakpoint

* clippy

* uninit

* clippy

* clippy

* clippy

* clippy

* nightly override in CI

* nightly override in CI

* components

* components

* targets

* targets

* clippy

* clippy

* clippy

* clippy

* clippy (again)

* MaybeUninit

Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
Andrea Fioraldi 2022-11-25 11:57:08 +01:00 committed by GitHub
parent bc85129cd9
commit c2776e117a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 64 additions and 109 deletions

View File

@ -20,6 +20,7 @@ jobs:
with: with:
profile: minimal profile: minimal
toolchain: nightly toolchain: nightly
override: true
- name: install mdbook - name: install mdbook
uses: baptiste0928/cargo-install@v1.3.0 uses: baptiste0928/cargo-install@v1.3.0
with: with:
@ -193,10 +194,12 @@ jobs:
with: with:
profile: minimal profile: minimal
toolchain: nightly toolchain: nightly
- name: Add nightly rustfmt and clippy override: true
run: rustup toolchain install nightly && rustup target add --toolchain nightly aarch64-unknown-none && rustup component add --toolchain nightly rust-src && rustup target add thumbv6m-none-eabi components: rustfmt, clippy, rust-src
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: Add targets
run: rustup target add arm-linux-androideabi && rustup target add thumbv6m-none-eabi
- name: Build aarch64-unknown-none - name: Build aarch64-unknown-none
run: cd ./fuzzers/baby_no_std && cargo +nightly build -Zbuild-std=core,alloc --target aarch64-unknown-none -v --release && cd ../.. run: cd ./fuzzers/baby_no_std && cargo +nightly build -Zbuild-std=core,alloc --target aarch64-unknown-none -v --release && cd ../..
- name: run x86_64 until panic! - name: run x86_64 until panic!

View File

@ -31,10 +31,7 @@ fn adder_loop(port: u16) -> ! {
loop { loop {
let mut msg_counter = 0; let mut msg_counter = 0;
loop { loop {
let (sender, tag, buf) = match client.recv_buf().unwrap() { let Some((sender, tag, buf)) = client.recv_buf().unwrap() else { break };
None => break,
Some(msg) => msg,
};
msg_counter += 1; msg_counter += 1;
match tag { match tag {
_TAG_SIMPLE_U32_V1 => { _TAG_SIMPLE_U32_V1 => {

View File

@ -41,7 +41,7 @@ macro_rules! impl_asany {
/// Get a `type_id` from its previously unpacked `u64`. /// Get a `type_id` from its previously unpacked `u64`.
/// Opposite of [`unpack_type_id(id)`]. /// Opposite of [`unpack_type_id(id)`].
/// ///
/// # Safety /// # Note
/// Probably not safe for future compilers, fine for now. /// Probably not safe for future compilers, fine for now.
#[must_use] #[must_use]
pub fn pack_type_id(id: u64) -> TypeId { pub fn pack_type_id(id: u64) -> TypeId {
@ -52,7 +52,7 @@ pub fn pack_type_id(id: u64) -> TypeId {
/// Unpack a `type_id` to an `u64` /// Unpack a `type_id` to an `u64`
/// Opposite of [`pack_type_id(id)`]. /// Opposite of [`pack_type_id(id)`].
/// ///
/// # Safety /// # Note
/// Probably not safe for future compilers, fine for now. /// Probably not safe for future compilers, fine for now.
#[must_use] #[must_use]
pub fn unpack_type_id(id: TypeId) -> u64 { pub fn unpack_type_id(id: TypeId) -> u64 {

View File

@ -8,7 +8,7 @@ use core::cell::RefCell;
use std::os::unix::prelude::{AsRawFd, RawFd}; use std::os::unix::prelude::{AsRawFd, RawFd};
use std::{ use std::{
fs::{self, remove_file, File, OpenOptions}, fs::{self, remove_file, File, OpenOptions},
io::{Seek, SeekFrom, Write}, io::{Seek, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -124,7 +124,7 @@ impl InputFile {
/// Rewinds the file to the beginning /// Rewinds the file to the beginning
#[inline] #[inline]
pub fn rewind(&mut self) -> Result<(), Error> { pub fn rewind(&mut self) -> Result<(), Error> {
if let Err(err) = self.file.seek(SeekFrom::Start(0)) { if let Err(err) = self.file.rewind() {
Err(err.into()) Err(err.into())
} else { } else {
Ok(()) Ok(())

View File

@ -2681,13 +2681,10 @@ where
}; };
println!("Connected to port {port}"); println!("Connected to port {port}");
let broker_shmem_description = if let TcpResponse::BrokerConnectHello { let TcpResponse::BrokerConnectHello {
broker_shmem_description, broker_shmem_description,
hostname: _, hostname: _,
} = recv_tcp_msg(&mut stream)?.try_into()? } = recv_tcp_msg(&mut stream)?.try_into()? else {
{
broker_shmem_description
} else {
return Err(Error::illegal_state( return Err(Error::illegal_state(
"Received unexpected Broker Hello".to_string(), "Received unexpected Broker Hello".to_string(),
)); ));
@ -2706,11 +2703,7 @@ where
send_tcp_msg(&mut stream, &client_hello_req)?; send_tcp_msg(&mut stream, &client_hello_req)?;
let client_id = if let TcpResponse::LocalClientAccepted { client_id } = let TcpResponse::LocalClientAccepted { client_id } = recv_tcp_msg(&mut stream)?.try_into()? else {
recv_tcp_msg(&mut stream)?.try_into()?
{
client_id
} else {
return Err(Error::illegal_state( return Err(Error::illegal_state(
"Unexpected Response from Broker".to_string(), "Unexpected Response from Broker".to_string(),
)); ));

View File

@ -348,12 +348,9 @@ impl Drop for ShMemServiceThread {
fn drop(&mut self) { fn drop(&mut self) {
if self.join_handle.is_some() { if self.join_handle.is_some() {
println!("Stopping ShMemService"); println!("Stopping ShMemService");
let mut stream = match UnixStream::connect_to_unix_addr( let Ok(mut stream) = UnixStream::connect_to_unix_addr(
&UnixSocketAddr::new(UNIX_SERVER_NAME).unwrap(), &UnixSocketAddr::new(UNIX_SERVER_NAME).unwrap(),
) { ) else { return };
Ok(stream) => stream,
Err(_) => return, // ignoring non-started server
};
let body = postcard::to_allocvec(&ServedShMemRequest::Exit).unwrap(); let body = postcard::to_allocvec(&ServedShMemRequest::Exit).unwrap();

View File

@ -234,7 +234,7 @@ where
/// Match for a name and return the value /// Match for a name and return the value
/// ///
/// # Safety /// # Note
/// This operation is unsafe with Rust stable, wait for [specialization](https://stackoverflow.com/a/60138532/7658998). /// This operation is unsafe with Rust stable, wait for [specialization](https://stackoverflow.com/a/60138532/7658998).
pub trait MatchName { pub trait MatchName {
/// Match for a name and return the borrowed value /// Match for a name and return the borrowed value

View File

@ -535,13 +535,12 @@ impl CommandExecutorBuilder {
OT: Debug + MatchName + ObserversTuple<S>, OT: Debug + MatchName + ObserversTuple<S>,
S: UsesInput, S: UsesInput,
{ {
let program = if let Some(program) = &self.program { let Some(program) = &self.program else {
program
} else {
return Err(Error::illegal_argument( return Err(Error::illegal_argument(
"ComandExecutor::builder: no program set!", "ComandExecutor::builder: no program set!",
)); ));
}; };
let mut command = Command::new(program); let mut command = Command::new(program);
match &self.input_location { match &self.input_location {
InputLocation::StdIn => { InputLocation::StdIn => {

View File

@ -328,15 +328,13 @@ impl Forkserver {
/// Read a message from the child process. /// Read a message from the child process.
pub fn read_st_timed(&mut self, timeout: &TimeSpec) -> Result<Option<i32>, Error> { pub fn read_st_timed(&mut self, timeout: &TimeSpec) -> Result<Option<i32>, Error> {
let mut buf: [u8; 4] = [0_u8; 4]; let mut buf: [u8; 4] = [0_u8; 4];
let st_read = match self.st_pipe.read_end() { let Some(st_read) = self.st_pipe.read_end() else {
Some(fd) => fd,
None => {
return Err(Error::file(io::Error::new( return Err(Error::file(io::Error::new(
ErrorKind::BrokenPipe, ErrorKind::BrokenPipe,
"Read pipe end was already closed", "Read pipe end was already closed",
))); )));
}
}; };
let mut readfds = FdSet::new(); let mut readfds = FdSet::new();
readfds.insert(st_read); readfds.insert(st_read);
// We'll pass a copied timeout to keep the original timeout intact, because select updates timeout to indicate how much time was left. See select(2) // We'll pass a copied timeout to keep the original timeout intact, because select updates timeout to indicate how much time was left. See select(2)

View File

@ -169,19 +169,13 @@ impl Tokens {
if line.is_empty() || start == Some('#') { if line.is_empty() || start == Some('#') {
continue; continue;
} }
let pos_quote = match line.find('\"') { let Some(pos_quote) = line.find('\"') else { return Err(Error::illegal_argument(format!("Illegal line: {line}"))) };
Some(x) => x,
None => return Err(Error::illegal_argument(format!("Illegal line: {line}"))),
};
if line.chars().nth(line.len() - 1) != Some('"') { if line.chars().nth(line.len() - 1) != Some('"') {
return Err(Error::illegal_argument(format!("Illegal line: {line}"))); return Err(Error::illegal_argument(format!("Illegal line: {line}")));
} }
// extract item // extract item
let item = match line.get(pos_quote + 1..line.len() - 1) { let Some(item) = line.get(pos_quote + 1..line.len() - 1) else { return Err(Error::illegal_argument(format!("Illegal line: {line}"))) };
Some(x) => x,
None => return Err(Error::illegal_argument(format!("Illegal line: {line}"))),
};
if item.is_empty() { if item.is_empty() {
continue; continue;
} }

View File

@ -548,7 +548,7 @@ where
/// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map. /// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map.
/// ///
/// # Safety /// # Note
/// Will dereference the owned slice with up to len elements. /// Will dereference the owned slice with up to len elements.
#[must_use] #[must_use]
pub fn new_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self pub fn new_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self
@ -594,7 +594,7 @@ where
/// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map in differential mode. /// Creates a new [`MapObserver`] from an [`OwnedSliceMut`] map in differential mode.
/// ///
/// # Safety /// # Note
/// Will dereference the owned slice with up to len elements. /// Will dereference the owned slice with up to len elements.
#[must_use] #[must_use]
pub fn differential_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self pub fn differential_from_ownedref<S>(name: S, map: OwnedSliceMut<'a, T>) -> Self

View File

@ -264,10 +264,7 @@ where
/// Cull the `Corpus` /// Cull the `Corpus`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn accounting_cull(&self, state: &mut CS::State) -> Result<(), Error> { pub fn accounting_cull(&self, state: &mut CS::State) -> Result<(), Error> {
let top_rated = match state.metadata().get::<TopAccountingMetadata>() { let Some(top_rated) = state.metadata().get::<TopAccountingMetadata>() else { return Ok(()) };
None => return Ok(()),
Some(val) => val,
};
for (_key, idx) in &top_rated.map { for (_key, idx) in &top_rated.map {
let mut entry = state.corpus().get(*idx)?.borrow_mut(); let mut entry = state.corpus().get(*idx)?.borrow_mut();

View File

@ -273,10 +273,7 @@ where
/// Cull the `Corpus` using the `MinimizerScheduler` /// Cull the `Corpus` using the `MinimizerScheduler`
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub fn cull(&self, state: &mut CS::State) -> Result<(), Error> { pub fn cull(&self, state: &mut CS::State) -> Result<(), Error> {
let top_rated = match state.metadata().get::<TopRatedsMetadata>() { let Some(top_rated) = state.metadata().get::<TopRatedsMetadata>() else { return Ok(()) };
None => return Ok(()),
Some(val) => val,
};
let mut acc = HashSet::new(); let mut acc = HashSet::new();

View File

@ -349,9 +349,7 @@ impl Allocator {
#[allow(clippy::missing_safety_doc)] #[allow(clippy::missing_safety_doc)]
pub unsafe fn release(&mut self, ptr: *mut c_void) { pub unsafe fn release(&mut self, ptr: *mut c_void) {
//println!("freeing address: {:?}", ptr); //println!("freeing address: {:?}", ptr);
let mut metadata = if let Some(metadata) = self.allocations.get_mut(&(ptr as usize)) { let Some(metadata) = self.allocations.get_mut(&(ptr as usize)) else {
metadata
} else {
if !ptr.is_null() { if !ptr.is_null() {
AsanErrors::get_mut() AsanErrors::get_mut()
.report_error(AsanError::UnallocatedFree((ptr as usize, Backtrace::new()))); .report_error(AsanError::UnallocatedFree((ptr as usize, Backtrace::new())));

View File

@ -60,20 +60,14 @@ impl NyxHelper {
parent_cpu_id: Option<u32>, parent_cpu_id: Option<u32>,
initial_timeout: Duration, initial_timeout: Duration,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let sharedir = match target_dir.to_str() { let Some(sharedir) = target_dir.to_str() else { return Err(Error::illegal_argument("can't convert sharedir to str")) };
Some(x) => x,
None => return Err(Error::illegal_argument("can't convert sharedir to str")),
};
let work_dir = target_dir.join("workdir"); let work_dir = target_dir.join("workdir");
let work_dir = work_dir.to_str().expect("unable to convert workdir to str"); let work_dir = work_dir.to_str().expect("unable to convert workdir to str");
let nyx_type = if parallel_mode { let nyx_type = if parallel_mode {
let parent_cpu_id = match parent_cpu_id { let Some(parent_cpu_id) = parent_cpu_id else {
None => {
return Err(Error::illegal_argument( return Err(Error::illegal_argument(
"please set parent_cpu_id in nyx parallel mode", "please set parent_cpu_id in nyx parallel mode",
)) ))
}
Some(x) => x,
}; };
if cpu_id == parent_cpu_id { if cpu_id == parent_cpu_id {
NyxProcessType::PARENT NyxProcessType::PARENT

View File

@ -4,7 +4,7 @@ use which::which;
const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge";
const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge";
const QEMU_REVISION: &str = "f26a5ca6137bb5d4d0dcfe5451fb16d4c0551c4e"; const QEMU_REVISION: &str = "6db12fe4df0eb1305261cf07d1995f21eb262392";
fn build_dep_check(tools: &[&str]) { fn build_dep_check(tools: &[&str]) {
for tool in tools { for tool in tools {

View File

@ -50,7 +50,7 @@ impl<S> QemuHelper<S> for QemuCallTracerHelper
where where
S: UsesInput, S: UsesInput,
{ {
fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, QT, S>) fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
where where
QT: QemuHelperTuple<S>, QT: QemuHelperTuple<S>,
{ {

View File

@ -1,13 +1,14 @@
//! Expose QEMU user `LibAFL` C api to Rust //! Expose QEMU user `LibAFL` C api to Rust
#[cfg(emulation_mode = "usermode")]
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
use core::{ use core::{
convert::Into, convert::Into,
ffi::c_void, ffi::c_void,
ptr::{addr_of, addr_of_mut, copy_nonoverlapping, null}, ptr::{addr_of, copy_nonoverlapping, null},
}; };
use std::{ffi::CString, slice::from_raw_parts, str::from_utf8_unchecked}; #[cfg(emulation_mode = "systemmode")]
use std::ffi::CString;
use std::{slice::from_raw_parts, str::from_utf8_unchecked};
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
use libc::c_int; use libc::c_int;
@ -539,7 +540,6 @@ impl CPU {
pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String> pub fn write_reg<R, T>(&self, reg: R, val: T) -> Result<(), String>
where where
T: Num + PartialOrd + Copy,
R: Into<i32>, R: Into<i32>,
{ {
let reg = reg.into(); let reg = reg.into();
@ -553,16 +553,17 @@ impl CPU {
pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String> pub fn read_reg<R, T>(&self, reg: R) -> Result<T, String>
where where
T: Num + PartialOrd + Copy,
R: Into<i32>, R: Into<i32>,
{ {
unsafe {
let reg = reg.into(); let reg = reg.into();
let mut val = T::zero(); let mut val = MaybeUninit::uninit();
let success = unsafe { libafl_qemu_read_reg(self.ptr, reg, addr_of_mut!(val) as *mut u8) }; let success = libafl_qemu_read_reg(self.ptr, reg, val.as_mut_ptr() as *mut u8);
if success == 0 { if success == 0 {
Err(format!("Failed to read register {reg}")) Err(format!("Failed to read register {reg}"))
} else { } else {
Ok(val) Ok(val.assume_init())
}
} }
} }
@ -794,12 +795,6 @@ impl Emulator {
pub fn load_addr(&self) -> GuestAddr { pub fn load_addr(&self) -> GuestAddr {
unsafe { libafl_load_addr() as GuestAddr } unsafe { libafl_load_addr() as GuestAddr }
} }
#[cfg(emulation_mode = "systemmode")]
#[must_use]
pub fn load_addr(&self) -> GuestAddr {
// Only work if the binary is linked to the correct address and not pie
return 0x0 as GuestAddr;
}
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
#[must_use] #[must_use]

View File

@ -37,10 +37,6 @@ pub use __afl_acc_memop_ptr as ACCOUNTING_MEMOP_MAP_PTR;
pub use __afl_area_ptr as EDGES_MAP_PTR; pub use __afl_area_ptr as EDGES_MAP_PTR;
/// Return Tokens from the compile-time token section /// Return Tokens from the compile-time token section
///
/// # Safety
///
/// This fn is safe to call, as long as the compilation did not break, previously
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn autotokens() -> Result<Tokens, Error> { pub fn autotokens() -> Result<Tokens, Error> {
unsafe { unsafe {

View File

@ -7,7 +7,7 @@ extern "C" {
/// Start the forkserver from this point. Any shared memory must be created before. /// Start the forkserver from this point. Any shared memory must be created before.
/// ///
/// # Safety /// # Note
/// ///
/// The forkserver logic is written in C and this code is a wrapper. /// The forkserver logic is written in C and this code is a wrapper.
pub fn start_forkserver() -> ! { pub fn start_forkserver() -> ! {

View File

@ -14,7 +14,7 @@ extern "C" {
/// Calls the (native) libfuzzer initialize function. /// Calls the (native) libfuzzer initialize function.
/// Returns the value returned by the init function. /// Returns the value returned by the init function.
/// # Safety /// # Note
/// Calls the libfuzzer-style init function which is native code. /// Calls the libfuzzer-style init function which is native code.
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
#[allow(clippy::must_use_candidate)] // nobody uses that return code... #[allow(clippy::must_use_candidate)] // nobody uses that return code...
@ -31,7 +31,7 @@ pub fn libfuzzer_initialize(args: &[String]) -> i32 {
} }
/// Call a single input of a libfuzzer-style cpp-harness /// Call a single input of a libfuzzer-style cpp-harness
/// # Safety /// # Note
/// Calls the libfuzzer harness. We actually think the target is unsafe and crashes eventually, that's why we do all this fuzzing. /// Calls the libfuzzer harness. We actually think the target is unsafe and crashes eventually, that's why we do all this fuzzing.
#[allow(clippy::must_use_candidate)] #[allow(clippy::must_use_candidate)]
pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 { pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 {

View File

@ -7,9 +7,6 @@ use core::slice::from_raw_parts_mut;
pub static mut COUNTERS_MAPS: Vec<&'static mut [u8]> = Vec::new(); pub static mut COUNTERS_MAPS: Vec<&'static mut [u8]> = Vec::new();
/// Initialize the sancov `8-bit-counters` - usually called by `llvm`. /// Initialize the sancov `8-bit-counters` - usually called by `llvm`.
///
/// # Safety
/// Set up our coverage maps.
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
#[allow(clippy::not_unsafe_ptr_arg_deref)] #[allow(clippy::not_unsafe_ptr_arg_deref)]