syheliel 758e49ac70
NYX Executor (GSoC '22) (#693)
* Add ccache

* Update codecov.yml

* Add libnyx

* Fix

* Add nyx build script

* Fix build.sh && init executor.rs

* Fix commit

* Fix code

* initialize `exector.rs`

* refine API in `nyx_bridge.rs`

* initialze `run_target`

* add `test_nyxhelper`

* initize `test_executor`

* remove `nyx_beidge.rs`

* make `test_executor` compile

* Improve test

* refine code

* update version

* fix docker

* fix docker

* Fix clippy

* Fix build

* fix build && add `set_timeout`

* Fix and refine CI

* fix CI

* Fix CI

* Add platform restrict

* cargo fmt

* add parallel mode

* add example `nyx_libxml2_parallel`

* fix fuzzer example

* fix CI

* add README

* fix CI

* fix CI

* fix CI

* remove unwrap and NyxResult

* code format fix

* add libnyx's rev

* fix format

* change Duration format && Fix CI

* caego fmt

* fix CI

* fix CI

* Add doc

* test CI

* Update test_all_fuzzers.sh

* Update test_all_fuzzers.sh

* Update test_all_fuzzers.sh

* add cache for apt and cargo-install

* Update build_and_test.yml

* Update build_and_test.yml

* tmp test CI

* fix CI

* remove debug cmd

* remove test

* code refine

* code refine

* code refine

* code refine

* add Makefile

* fix example doc for nyx

* add `NyxHelper::new_with_initial_timeout`

* fix `NyxHelper::new`

* fix curl parameter

* code refine

* add check for setup script

* use afl-clang-fast in nyx

* fix logic

* fix makefile

* fix CI

* Update build_and_test.yml

* Update build_and_test.yml

* remove debug cmd

Co-authored-by: syheliel <syheliel@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
2022-08-25 10:55:35 +02:00

158 lines
5.2 KiB
Rust

/// [`NyxHelper`] is used to wrap `NyxProcess`
use std::{
fmt::{self, Debug},
path::Path,
time::Duration,
};
use libafl::Error;
use libnyx::{NyxProcess, NyxReturnValue};
const INIT_TIMEOUT: Duration = Duration::new(2, 0);
pub struct NyxHelper {
pub nyx_process: NyxProcess,
/// real size of trace_bits
pub real_map_size: usize,
// real size of the trace_bits
pub map_size: usize,
/// shared memory with instruction bitmaps
pub trace_bits: *mut u8,
}
const MAX_FILE: u32 = 1024 * 1024;
#[derive(Clone, Copy, Debug)]
pub enum NyxProcessType {
/// stand alone mode
ALONE,
/// parallel mode's parent, used to create snapshot
PARENT,
/// parallel mode's child, consume snapshot and execute
CHILD,
}
impl NyxHelper {
/// create `NyxProcess` and do basic settings
/// It will convert instance to parent or child using `parent_cpu_id` when set`parallel_mode`
/// will fail if initial connection takes more than 2 seconds
pub fn new(
target_dir: &Path,
cpu_id: u32,
snap_mode: bool,
parallel_mode: bool,
parent_cpu_id: Option<u32>,
) -> Result<Self, Error> {
NyxHelper::new_with_initial_timeout(
target_dir,
cpu_id,
snap_mode,
parallel_mode,
parent_cpu_id,
INIT_TIMEOUT,
)
}
/// create `NyxProcess` and do basic settings
/// It will convert instance to parent or child using `parent_cpu_id` when set`parallel_mode`
/// will fail if initial connection takes more than `initial_timeout` seconds
pub fn new_with_initial_timeout(
target_dir: &Path,
cpu_id: u32,
snap_mode: bool,
parallel_mode: bool,
parent_cpu_id: Option<u32>,
initial_timeout: Duration,
) -> Result<Self, Error> {
let sharedir = match target_dir.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 = work_dir.to_str().expect("unable to convert workdir to str");
let nyx_type = if parallel_mode {
let parent_cpu_id = match parent_cpu_id {
None => {
return Err(Error::illegal_argument(
"please set parent_cpu_id in nyx parallel mode",
))
}
Some(x) => x,
};
if cpu_id == parent_cpu_id {
NyxProcessType::PARENT
} else {
NyxProcessType::CHILD
}
} else {
NyxProcessType::ALONE
};
let nyx_process = match nyx_type {
NyxProcessType::ALONE => NyxProcess::new(sharedir, work_dir, cpu_id, MAX_FILE, true),
NyxProcessType::PARENT => {
NyxProcess::new_parent(sharedir, work_dir, cpu_id, MAX_FILE, true)
}
NyxProcessType::CHILD => NyxProcess::new_child(sharedir, work_dir, cpu_id, cpu_id),
};
let mut nyx_process =
nyx_process.map_err(|msg: String| -> Error { Error::illegal_argument(msg) })?;
let real_map_size = nyx_process.bitmap_buffer_size();
let map_size = ((real_map_size + 63) >> 6) << 6;
let trace_bits = nyx_process.bitmap_buffer_mut().as_mut_ptr();
nyx_process.option_set_reload_mode(snap_mode);
nyx_process.option_apply();
// default timeout for initial dry-run
let sec = initial_timeout
.as_secs()
.try_into()
.map_err(|_| -> Error { Error::illegal_argument("can't cast time's sec to u8") })?;
let micro_sec: u32 = initial_timeout.subsec_micros();
nyx_process.option_set_timeout(sec, micro_sec);
nyx_process.option_apply();
// dry run to check if qemu is spawned
nyx_process.set_input(b"INIT", 4);
match nyx_process.exec() {
NyxReturnValue::Error => {
nyx_process.shutdown();
let msg = "Error: Nyx runtime error has occured...";
return Err(Error::illegal_state(msg));
}
NyxReturnValue::IoError => {
let msg = "Error: QEMU-nyx died...";
return Err(Error::illegal_state(msg));
}
NyxReturnValue::Abort => {
nyx_process.shutdown();
let msg = "Error: Nyx abort occured...";
return Err(Error::illegal_state(msg));
}
_ => {}
}
Ok(Self {
nyx_process,
real_map_size,
map_size,
trace_bits,
})
}
/// set timeout
pub fn set_timeout(mut self, time: Duration) {
let sec: u8 = time
.as_secs()
.try_into()
.expect("can't cast time's sec to u8");
let micro_sec: u32 = time.subsec_micros();
self.nyx_process.option_set_timeout(sec, micro_sec);
self.nyx_process.option_apply();
}
}
impl Debug for NyxHelper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NyxInprocessHelper").finish()
}
}