add AFL++ support and other improvements

This commit is contained in:
Sergej Schumilo 2021-12-18 15:10:39 +01:00
parent 1927a0ab83
commit a199ed31e7
8 changed files with 243 additions and 130 deletions

View File

@ -18,6 +18,12 @@ fn into_absolute_path(path_to_sharedir: &str, path_to_file: String) -> String {
}
}
#[derive(Clone, Copy, Serialize, Deserialize)]
pub struct IptFilter {
pub a: u64,
pub b: u64,
}
#[derive(Clone)]
pub struct QemuKernelConfig {
pub qemu_binary: String,
@ -132,6 +138,7 @@ pub struct FuzzerConfig {
pub exit_after_first_crash: bool,
pub write_protected_input_buffer: bool,
pub cow_primary_size: Option<u64>,
pub ipt_filters: [IptFilter;4],
}
impl FuzzerConfig{
pub fn new_from_loader(sharedir: &str, default: FuzzerConfigLoader, config: FuzzerConfigLoader) -> Self {
@ -161,6 +168,12 @@ impl FuzzerConfig{
exit_after_first_crash: config.exit_after_first_crash.unwrap_or(default.exit_after_first_crash.unwrap_or(false)),
write_protected_input_buffer: config.write_protected_input_buffer,
cow_primary_size: if config.cow_primary_size != 0 { Some( config.cow_primary_size as u64) } else { None },
ipt_filters: [
config.ip0,
config.ip1,
config.ip2,
config.ip3,
],
}
}
}
@ -179,18 +192,38 @@ impl Config{
}
}
pub fn new_from_sharedir(sharedir: &str) -> Self {
pub fn new_from_sharedir(sharedir: &str) -> Result<Self, String> {
let path_to_config = format!("{}/config.ron", sharedir);
let cfg_file = File::open(&path_to_config).expect("could not open config file");
let mut cfg: ConfigLoader = ron::de::from_reader(cfg_file).unwrap();
let default_path = into_absolute_path(sharedir, cfg.include_default_config_path.unwrap());
let cfg_file = match File::open(&path_to_config){
Ok(x) => {x},
Err(_) => return Err(format!("file or folder not found ({})!", path_to_config)),
};
let mut cfg: ConfigLoader = match ron::de::from_reader(cfg_file){
Ok(x) => {x},
Err(x) => return Err(format!("invalid configuration ({})!", x)),
};
let include_default_config_path = match cfg.include_default_config_path{
Some(x) => {x},
None => return Err(format!("no path to default configuration given!")),
};
let default_path = into_absolute_path(sharedir, include_default_config_path);
let default_config_folder = Path::new(&default_path).parent().unwrap().to_str().unwrap();
cfg.include_default_config_path = Some(default_path.clone());
let default_file = File::open(cfg.include_default_config_path.as_ref().expect("no default config given")).expect("could not open config file");
let default: ConfigLoader = ron::de::from_reader(default_file).unwrap();
let default_file = match File::open(default_path.clone()){
Ok(x) => x,
Err(_) => return Err(format!("default config not found ({})!", default_path)),
};
let default: ConfigLoader = match ron::de::from_reader(default_file){
Ok(x) => {x},
Err(x) => return Err(format!("invalid default configuration ({})!", x)),
};
Self::new_from_loader(&sharedir, &default_config_folder, default, cfg)
Ok(Self::new_from_loader(&sharedir, &default_config_folder, default, cfg))
}
}

View File

@ -42,6 +42,15 @@ pub struct FuzzerConfigLoader {
#[serde(default = "default_cow_primary_size")]
pub cow_primary_size: u64,
#[serde(default = "default_ipt_filter")]
pub ip0: IptFilter,
#[serde(default = "default_ipt_filter")]
pub ip1: IptFilter,
#[serde(default = "default_ipt_filter")]
pub ip2: IptFilter,
#[serde(default = "default_ipt_filter")]
pub ip3: IptFilter,
pub workdir_path: Option<String>,
pub bitmap_size: Option<usize>,
pub mem_limit: Option<usize>,
@ -65,6 +74,13 @@ fn default_cow_primary_size() -> u64 {
0
}
fn default_ipt_filter() -> IptFilter {
IptFilter{
a: 0,
b: 0,
}
}
#[derive(Clone, Serialize, Deserialize)]
pub struct ConfigLoader {
pub include_default_config_path: Option<String>,

View File

@ -146,8 +146,11 @@ impl FuzzRunner for ForkServer {
*/
impl FuzzRunner for QemuProcess {
fn run_test(&mut self) -> Result<TestInfo, Box<dyn Error>> {
self.send_payload();
self.send_payload().unwrap();
let ops_used = self.feedback_data.shared.interpreter.executed_opcode_num;
if self.aux.result.abort != 0 {
panic!("Abort called!\n");
}
if self.aux.result.crash_found != 0 {
return Ok(TestInfo {ops_used, exitreason: ExitReason::Crash(self.aux.misc.as_slice().to_vec())});
}
@ -169,7 +172,7 @@ impl FuzzRunner for QemuProcess {
fn run_create_snapshot(&mut self) -> bool{
assert_eq!(self.aux.result.tmp_snapshot_created,0);
self.send_payload();
self.send_payload().unwrap();
return self.aux.result.tmp_snapshot_created == 1;
}
@ -177,7 +180,7 @@ impl FuzzRunner for QemuProcess {
if self.aux.result.tmp_snapshot_created != 0 {
self.aux.config.changed = 1;
self.aux.config.discard_tmp_snapshot = 1;
self.send_payload();
self.send_payload().unwrap();
if self.aux.result.tmp_snapshot_created != 0 {
println!("AUX BUFFER {:#?}",self.aux);
}
@ -190,7 +193,7 @@ impl FuzzRunner for QemuProcess {
fn run_redqueen(&mut self) -> Result<RedqueenInfo, Box<dyn Error>> {
self.aux.config.changed = 1;
self.aux.config.redqueen_mode=1;
self.send_payload();
self.send_payload().unwrap();
self.aux.config.changed = 1;
self.aux.config.redqueen_mode=0;
let rq_file = format!("{}/redqueen_workdir_{}/redqueen_results.txt",self.params.workdir,self.params.qemu_id);
@ -201,7 +204,7 @@ impl FuzzRunner for QemuProcess {
//println!("TRACE!!!!");
self.aux.config.trace_mode=1;
self.aux.config.changed = 1;
self.send_payload();
self.send_payload().unwrap();
self.aux.config.changed = 1;
self.aux.config.trace_mode=0;
return Ok(CFGInfo {});

View File

@ -17,7 +17,8 @@ use derivative::Derivative;
const AUX_BUFFER_SIZE: usize = 4096;
const AUX_MAGIC: u64 = 0x54502d554d4551_u64;
const QEMU_PT_VERSION: u16 = 1; /* let's start at 1 for the initial version using the aux buffer */
const QEMU_PT_VERSION: u16 = 2; /* let's start at 1 for the initial version using the aux buffer */
const QEMU_PT_HASH: u16 = 82;
const HEADER_SIZE: usize = 128;
const CAP_SIZE: usize = 256;
@ -82,14 +83,21 @@ impl AuxBuffer {
return AuxBuffer::new_readonly(file, false);
}
pub fn validate_header(&self) {
pub fn validate_header(&self) -> Result<(), String> {
mem_barrier();
let mgc = self.header.magic;
assert_eq!(mgc, AUX_MAGIC);
if mgc != AUX_MAGIC {
return Err(format!("aux buffer magic mismatch {} != {}...\n[!] Probably the AUX buffer is corrupted?!", AUX_MAGIC, mgc));
}
let version = self.header.version;
assert_eq!(version, QEMU_PT_VERSION);
if version != QEMU_PT_VERSION {
return Err(format!("aux buffer version mismatch {} != {}...\n[!] You are probably using either an outdated version of libnyx or QEMU-Nyx...", QEMU_PT_VERSION, version));
}
let hash = self.header.hash;
assert_eq!(hash, 81);
if hash != QEMU_PT_HASH {
return Err(format!("aux buffer hash mismatch {} != {}...\n[!] You are probably using either an outdated version of libnyx or QEMU-Nyx...", QEMU_PT_HASH, hash));
}
Ok(())
}
}
#[derive(Debug, Copy, Clone)]
@ -176,7 +184,7 @@ pub struct auxilary_buffer_result_s {
pub dirty_pages: u32,
pub pt_trace_size: u32,
pub payload_write_attempt_found: u8,
pub abort: u8,
}
#[repr(C, packed(1))]

View File

@ -24,7 +24,7 @@ fn into_absolute_path(sharedir: &str) -> String{
}
}
pub fn qemu_process_new_from_kernel(sharedir: String, cfg: &QemuKernelConfig, fuzz_cfg: &FuzzerConfig) -> qemu_process::QemuProcess {
pub fn qemu_process_new_from_kernel(sharedir: String, cfg: &QemuKernelConfig, fuzz_cfg: &FuzzerConfig) -> Result<QemuProcess, String> {
let params = params::KernelVmParams {
qemu_binary: cfg.qemu_binary.to_string(),
kernel: cfg.kernel.to_string(),
@ -39,6 +39,7 @@ pub fn qemu_process_new_from_kernel(sharedir: String, cfg: &QemuKernelConfig, fu
},
write_protected_input_buffer: fuzz_cfg.write_protected_input_buffer,
cow_primary_size: fuzz_cfg.cow_primary_size,
ipt_filters: fuzz_cfg.ipt_filters,
};
let qemu_id = fuzz_cfg.thread_id;
let qemu_params = params::QemuParams::new_from_kernel(&fuzz_cfg.workdir_path, qemu_id, &params, fuzz_cfg.threads > 1);
@ -51,7 +52,7 @@ pub fn qemu_process_new_from_kernel(sharedir: String, cfg: &QemuKernelConfig, fu
return qemu_process::QemuProcess::new(qemu_params);
}
pub fn qemu_process_new_from_snapshot(sharedir: String, cfg: &QemuSnapshotConfig, fuzz_cfg: &FuzzerConfig) -> qemu_process::QemuProcess {
pub fn qemu_process_new_from_snapshot(sharedir: String, cfg: &QemuSnapshotConfig, fuzz_cfg: &FuzzerConfig) -> Result<QemuProcess, String> {
let snapshot_path = match &cfg.snapshot_path{
SnapshotPath::Create(_x) => panic!(),
@ -80,6 +81,7 @@ pub fn qemu_process_new_from_snapshot(sharedir: String, cfg: &QemuSnapshotConfig
},
write_protected_input_buffer: fuzz_cfg.write_protected_input_buffer,
cow_primary_size: fuzz_cfg.cow_primary_size,
ipt_filters: fuzz_cfg.ipt_filters,
};
let qemu_id = fuzz_cfg.thread_id;
let qemu_params = params::QemuParams::new_from_snapshot(&fuzz_cfg.workdir_path, qemu_id, fuzz_cfg.cpu_pin_start_at, &params, fuzz_cfg.threads > 1);

View File

@ -1,5 +1,6 @@
use std::path::Path;
use crate::config::SnapshotPath;
use crate::config::IptFilter;
pub struct KernelVmParams {
pub qemu_binary: String,
@ -13,6 +14,7 @@ pub struct KernelVmParams {
pub dump_python_code_for_inputs: bool,
pub write_protected_input_buffer: bool,
pub cow_primary_size: Option<u64>,
pub ipt_filters: [IptFilter; 4],
}
pub struct SnapshotVmParams{
@ -28,6 +30,8 @@ pub struct SnapshotVmParams{
pub dump_python_code_for_inputs: bool,
pub write_protected_input_buffer: bool,
pub cow_primary_size: Option<u64>,
pub ipt_filters: [IptFilter; 4],
}
pub struct QemuParams {
@ -50,7 +54,6 @@ pub struct QemuParams {
impl QemuParams {
pub fn new_from_snapshot(workdir: &str, qemu_id: usize, cpu: usize, params: &SnapshotVmParams, create_snapshot_file: bool) -> QemuParams{
assert!(!(!create_snapshot_file && qemu_id == 1));
let project_name = Path::new(workdir)
.file_name()
.expect("Couldn't get project name from workdir!")
@ -112,13 +115,19 @@ impl QemuParams {
nyx_ops += &format!(",workdir={}", workdir);
nyx_ops += &format!(",sharedir={}", params.sharedir);
let mut i = 0;
for filter in params.ipt_filters{
if filter.a != 0 && filter.b != 0 {
nyx_ops += &format!(",ip{}_a={},ip{}_b={}", i, filter.a, i, filter.b);
i += 1;
}
}
if params.cow_primary_size.is_some(){
nyx_ops += &format!(",cow_primary_size={}", params.cow_primary_size.unwrap());
}
//nyx_ops += &format!(",ip0_a=0x1000,ip0_b=0x7ffffffff000");
//nyx_ops += &format!(",ip0_a=ffff800000000000,ip0_b=ffffffffffffffff");
cmd.push(nyx_ops);
cmd.push("-machine".to_string());
@ -171,7 +180,6 @@ impl QemuParams {
pub fn new_from_kernel(workdir: &str, qemu_id: usize, params: &KernelVmParams, create_snapshot_file: bool) -> QemuParams {
//prepare_working_dir(workdir)
assert!(!(!create_snapshot_file && qemu_id == 1));
let project_name = Path::new(workdir)
.file_name()
.expect("Couldn't get project name from workdir!")
@ -236,13 +244,18 @@ impl QemuParams {
nyx_ops += &format!(",workdir={}", workdir);
nyx_ops += &format!(",sharedir={}", params.sharedir);
let mut i = 0;
for filter in params.ipt_filters{
if filter.a != 0 && filter.b != 0 {
nyx_ops += &format!(",ip{}_a={:x},ip{}_b={:x}", i, filter.a, i, filter.b);
i += 1;
}
}
if params.cow_primary_size.is_some(){
nyx_ops += &format!(",cow_primary_size={}", params.cow_primary_size.unwrap());
}
//nyx_ops += &format!(",ip0_a=0x1000,ip0_b=0x7ffffffff000");
//nyx_ops += &format!(",ip0_a=ffff800000000000,ip0_b=ffffffffffffffff");
cmd.push(nyx_ops);
cmd.push("-machine".to_string());

View File

@ -1,6 +1,7 @@
use core::ffi::c_void;
use nix::sys::mman::*;
use std::fs;
use std::io;
use std::fs::{File, OpenOptions};
use std::io::prelude::*;
use std::os::unix::fs::symlink;
@ -31,21 +32,23 @@ pub struct QemuProcess {
pub bitmap: &'static mut [u8],
pub payload: &'static mut [u8],
pub params: QemuParams,
hprintf_log: File,
}
fn execute_qemu(ctrl: &mut UnixStream) {
ctrl.write_all(&[120_u8]).unwrap();
fn execute_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
ctrl.write_all(&[120_u8])?;
Ok(())
}
fn wait_qemu(ctrl: &mut UnixStream) {
fn wait_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
let mut buf = [0];
ctrl.read_exact(&mut buf).unwrap();
ctrl.read_exact(&mut buf)?;
Ok(())
}
fn run_qemu(ctrl: &mut UnixStream) {
execute_qemu(ctrl);
wait_qemu(ctrl);
fn run_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
execute_qemu(ctrl)?;
wait_qemu(ctrl)?;
Ok(())
}
fn make_shared_data(file: File, size: usize) -> &'static mut [u8] {
@ -69,7 +72,7 @@ fn make_shared_ijon_data(file: File, size: usize) -> FeedbackBuffer {
}
impl QemuProcess {
pub fn new(params: QemuParams) -> QemuProcess {
pub fn new(params: QemuParams) -> Result<QemuProcess, String> {
Self::prepare_redqueen_workdir(&params.workdir, params.qemu_id);
if params.qemu_id == 0{
@ -89,11 +92,20 @@ impl QemuProcess {
.open(&params.payload_filename)
.expect("couldn't open payload file");
if Path::new(&format!("{}/bitmap_{}", params.workdir, params.qemu_id)).exists(){
fs::remove_file(format!("{}/bitmap_{}", params.workdir, params.qemu_id)).unwrap();
}
symlink(
&params.bitmap_filename,
format!("{}/bitmap_{}", params.workdir, params.qemu_id),
)
.unwrap();
if Path::new(&format!("{}/payload_{}", params.workdir, params.qemu_id)).exists(){
fs::remove_file(format!("{}/payload_{}", params.workdir, params.qemu_id)).unwrap();
}
symlink(
&params.payload_filename,
format!("{}/payload_{}", params.workdir, params.qemu_id),
@ -123,7 +135,7 @@ impl QemuProcess {
thread::sleep(time::Duration::from_millis(200*params.qemu_id as u64));
let child = if params.dump_python_code_for_inputs{
let mut child = if params.dump_python_code_for_inputs{
Command::new(&params.cmd[0])
.args(&params.cmd[1..])
.env("DUMP_PAYLOAD_MODE", "TRUE")
@ -159,7 +171,9 @@ impl QemuProcess {
// dry_run
//println!("TRHEAD {} run QEMU initial",params.qemu_id);
run_qemu(&mut control);
if run_qemu(&mut control).is_err() {
return Err(format!("cannot launch QEMU-Nyx..."));
}
let aux_shm_f = OpenOptions::new()
.read(true)
@ -175,7 +189,14 @@ impl QemuProcess {
.expect("couldn't open aux buffer file");
let mut aux_buffer = AuxBuffer::new(aux_shm_f);
aux_buffer.validate_header();
match aux_buffer.validate_header(){
Err(x) => {
child.kill().unwrap();
child.wait().unwrap();
return Err(x);
},
Ok(_) => {},
}
if params.write_protected_input_buffer{
if params.qemu_id == 0 {
println!("[!] libnyx: input buffer is write protected");
@ -185,22 +206,30 @@ impl QemuProcess {
}
loop {
if aux_buffer.result.abort == 1 {
let len = aux_buffer.misc.len;
let msg = format!("agent abort() -> \n\t{}", String::from_utf8_lossy(&aux_buffer.misc.data[0..len as usize]).red());
/* get rid of this process */
child.kill().unwrap();
child.wait().unwrap();
return Err(msg);
}
if aux_buffer.result.hprintf == 1 {
let len = aux_buffer.misc.len;
print!("{}", String::from_utf8_lossy(&aux_buffer.misc.data[0..len as usize]).yellow());
}
else{
//println!("QEMU NOT READY");
}
}
if aux_buffer.result.state == 3 {
break;
}
//println!("QEMU NOT READY");
//println!("TRHEAD {} run QEMU NOT READY",params.qemu_id);
run_qemu(&mut control);
if run_qemu(&mut control).is_err(){
return Err(format!("failed to establish fuzzing loop..."));
}
//run_qemu(&mut control).unwrap();
}
//println!("QEMU READY");
println!("[!] libnyx: qemu #{} is ready:", params.qemu_id);
aux_buffer.config.reload_mode = 1;
@ -208,16 +237,7 @@ impl QemuProcess {
aux_buffer.config.timeout_usec = 500_000;
aux_buffer.config.changed = 1;
//run_qemu(&mut control);
//run_qemu(&mut control);
let mut option = OpenOptions::new();
option.read(true);
option.write(true);
option.create(true);
let hprintf_log = option.open(format!("{}/hprintf_log_{}", params.workdir, params.qemu_id)).unwrap();
return QemuProcess {
return Ok(QemuProcess {
process: child,
aux: aux_buffer,
feedback_data: ijon_shared,
@ -225,49 +245,32 @@ impl QemuProcess {
bitmap: bitmap_shared,
payload: payload_shared,
params,
hprintf_log,
};
});
}
pub fn send_payload(&mut self) {
pub fn send_payload(&mut self) -> io::Result<()>{
let mut old_address: u64 = 0;
//use rand::Rng;
//println!("RUN INPUT");
//std::thread::sleep(std::time::Duration::from_secs(1));
//let time = std::time::SystemTime::now().duration_since(std::time::SystemTime::UNIX_EPOCH).unwrap().as_nanos();
//self.hprintf_log.write_all(&format!("===({})===\n", time).as_bytes()).unwrap();
loop {
mem_barrier();
run_qemu(&mut self.ctrl);
match run_qemu(&mut self.ctrl) {
Err(x) => return Err(x),
Ok(_) => {},
}
mem_barrier();
if self.aux.result.hprintf != 0 {
self.hprintf_log.write_all(&format!("{}\n", self.aux.misc.as_string()).as_bytes()).unwrap();
//println!("HPRINTF {}", self.aux.misc.as_string());
if self.aux.result.hprintf == 1 {
let len = self.aux.misc.len;
print!("{}", String::from_utf8_lossy(&self.aux.misc.data[0..len as usize]).yellow());
//print!("{}", "".clear());
println!("TEST\n");
continue;
}
//println!("pt trace size {:x} bytes",self.aux.result.pt_trace_size);
//println!("{:} dirty pages",self.aux.result.dirty_pages);
//println!("interpreter ran {} ops",self.feedback_data.shared.interpreter.executed_opcode_num);
//let max_v = 0;
//let max_i = 0;
//for (i,v) in self.feedback_data.shared.ijon.max_data.iter().enumerate(){
// if *v > max_v{
// max_v=*v;
// max_i=i;
//
// }
//}
//println!("found IJON MAX: {}\t{:x}",max_i,max_v);
if self.aux.result.abort == 1 {
let len = self.aux.misc.len;
println!("[!] libnyx: agent abort() -> \"{}\"", String::from_utf8_lossy(&self.aux.misc.data[0..len as usize]).red());
break;
}
if self.aux.result.success != 0 || self.aux.result.crash_found != 0 || self.aux.result.asan_found != 0 || self.aux.result.payload_write_attempt_found != 0 {
break;
@ -284,15 +287,8 @@ impl QemuProcess {
self.aux.config.page_dump_mode = 1;
self.aux.config.changed = 1;
}
//else {
// break;
//}
}
//std::thread::sleep(std::time::Duration::from_secs(1));
//if self.aux.result.tmp_snapshot_created != 0 {
// //println!("created snapshot!!!!!!\n");
//}
Ok(())
}
pub fn set_timeout(&mut self, timeout: std::time::Duration){
@ -306,11 +302,26 @@ impl QemuProcess {
}
pub fn shutdown(&mut self) {
println!("Let's kill QEMU!");
println!("[!] libnyx: sending SIGKILL to QEMU-Nyx process...");
self.process.kill().unwrap();
self.wait();
}
pub fn wait_for_workdir(workdir: &str){
println!("[!] libnyx: waiting for workdir to be created by parent process...");
let files = vec![
"page_cache.lock",
"page_cache.addr",
"page_cache.addr",
];
for file in files.iter() {
while !Path::new(&format!("{}/{}", workdir, file)).exists(){
thread::sleep(time::Duration::from_secs(1));
}
}
}
pub fn prepare_workdir(workdir: &str, seed_path: Option<String>) {
Self::clear_workdir(workdir);
let folders = vec![

View File

@ -16,11 +16,13 @@ pub enum NyxReturnValue {
Asan,
Timout,
InvalidWriteToPayload,
Error
Error,
IoError, // QEMU process has died for some reason
Abort, // Abort hypercall called
}
#[no_mangle]
pub extern "C" fn nyx_new(sharedir: *const c_char, workdir: *const c_char, worker_id: u32, create_snapshot: bool) -> * mut QemuProcess {
pub extern "C" fn nyx_new(sharedir: *const c_char, workdir: *const c_char, worker_id: u32, cpu_id: u32, create_snapshot: bool) -> * mut QemuProcess {
let sharedir_c_str = unsafe {
assert!(!sharedir.is_null());
CStr::from_ptr(sharedir)
@ -35,18 +37,20 @@ pub extern "C" fn nyx_new(sharedir: *const c_char, workdir: *const c_char, worke
let sharedir_r_str = sharedir_c_str.to_str().unwrap();
let workdir_r_str = workdir_c_str.to_str().unwrap();
println!("r_str: {}", sharedir_r_str);
let cfg: Config = Config::new_from_sharedir(&sharedir_r_str);
println!("config {}", cfg.fuzz.bitmap_size);
let cfg: Config = match Config::new_from_sharedir(&sharedir_r_str){
Ok(x) => x,
Err(msg) => {
println!("[!] libnyx config reader error: {}", msg);
return std::ptr::null_mut() as *mut QemuProcess;
}
};
let mut config = cfg.fuzz;
let runner_cfg = cfg.runner;
/* todo: add sanity check */
config.cpu_pin_start_at = worker_id as usize;
config.cpu_pin_start_at = cpu_id as usize;
config.thread_id = worker_id as usize;
config.threads = if create_snapshot { 2 as usize } else { 1 as usize };
@ -59,16 +63,25 @@ pub extern "C" fn nyx_new(sharedir: *const c_char, workdir: *const c_char, worke
if worker_id == 0 {
QemuProcess::prepare_workdir(&config.workdir_path, config.seed_path.clone());
}
else{
QemuProcess::wait_for_workdir(&config.workdir_path);
}
match runner_cfg.clone() {
let runner = match runner_cfg.clone() {
FuzzRunnerConfig::QemuSnapshot(cfg) => {
let runner = qemu_process_new_from_snapshot(sdir.to_string(), &cfg, &config);
return Box::into_raw(Box::new(runner));
}
qemu_process_new_from_snapshot(sdir.to_string(), &cfg, &config)
},
FuzzRunnerConfig::QemuKernel(cfg) => {
let runner = qemu_process_new_from_kernel(sdir.to_string(), &cfg, &config);
return Box::into_raw(Box::new(runner));
qemu_process_new_from_kernel(sdir.to_string(), &cfg, &config)
}
};
match runner {
Ok(x) => Box::into_raw(Box::new(x)),
Err(msg) => {
println!("[!] libnyx failed to initialize QEMU-Nyx: {}", msg);
std::ptr::null_mut() as *mut QemuProcess
},
}
}
@ -104,6 +117,15 @@ pub extern "C" fn nyx_get_bitmap_buffer(qemu_process: * mut QemuProcess) -> *mut
}
}
#[no_mangle]
pub extern "C" fn nyx_get_bitmap_buffer_size(qemu_process: * mut QemuProcess) -> usize {
unsafe{
assert!(!qemu_process.is_null());
assert!((qemu_process as usize) % std::mem::align_of::<QemuProcess>() == 0);
return (*qemu_process).bitmap.len();
}
}
#[no_mangle]
pub extern "C" fn nyx_shutdown(qemu_process: * mut QemuProcess) {
unsafe{
@ -152,25 +174,30 @@ pub extern "C" fn nyx_exec(qemu_process: * mut QemuProcess) -> NyxReturnValue {
assert!(!qemu_process.is_null());
assert!((qemu_process as usize) % std::mem::align_of::<QemuProcess>() == 0);
(*qemu_process).send_payload();
if (*qemu_process).aux.result.crash_found != 0 {
return NyxReturnValue::Crash;
match (*qemu_process).send_payload(){
Err(_) => return NyxReturnValue::IoError,
Ok(_) => {
if (*qemu_process).aux.result.abort != 0 {
return NyxReturnValue::Abort;
}
if (*qemu_process).aux.result.crash_found != 0 {
return NyxReturnValue::Crash;
}
if (*qemu_process).aux.result.asan_found != 0 {
return NyxReturnValue::Asan;
}
if (*qemu_process).aux.result.timeout_found != 0 {
return NyxReturnValue::Timout;
}
if (*qemu_process).aux.result.payload_write_attempt_found != 0 {
return NyxReturnValue::InvalidWriteToPayload;
}
if (*qemu_process).aux.result.success != 0 {
return NyxReturnValue::Normal;
}
return NyxReturnValue::Error;
}
}
if (*qemu_process).aux.result.asan_found != 0 {
return NyxReturnValue::Asan;
}
if (*qemu_process).aux.result.timeout_found != 0 {
return NyxReturnValue::Timout;
}
if (*qemu_process).aux.result.payload_write_attempt_found != 0 {
return NyxReturnValue::InvalidWriteToPayload;
}
if (*qemu_process).aux.result.success != 0 {
return NyxReturnValue::Normal;
}
println!("unknown exeuction result!!");
return NyxReturnValue::Error;
}
}