diff --git a/fuzz_runner/src/nyx/mod.rs b/fuzz_runner/src/nyx/mod.rs index 444262c..5184d7b 100644 --- a/fuzz_runner/src/nyx/mod.rs +++ b/fuzz_runner/src/nyx/mod.rs @@ -10,7 +10,6 @@ use std::fs; use std::path::PathBuf; extern crate config; -use crate::config::{QemuKernelConfig, QemuSnapshotConfig, FuzzerConfig, SnapshotPath}; fn into_absolute_path(sharedir: &str) -> String{ @@ -24,107 +23,9 @@ fn into_absolute_path(sharedir: &str) -> String{ } } -pub fn qemu_process_new_from_kernel(sharedir: String, cfg: &QemuKernelConfig, fuzz_cfg: &FuzzerConfig) -> Result { - let params = params::KernelVmParams { - qemu_binary: cfg.qemu_binary.to_string(), - kernel: cfg.kernel.to_string(), - sharedir: into_absolute_path(&sharedir), - ramfs: cfg.ramfs.to_string(), - ram_size: fuzz_cfg.mem_limit, - bitmap_size: fuzz_cfg.bitmap_size, - debug: cfg.debug, - dump_python_code_for_inputs: match fuzz_cfg.dump_python_code_for_inputs{ - None => false, - Some(x) => x, - }, - write_protected_input_buffer: fuzz_cfg.write_protected_input_buffer, - cow_primary_size: fuzz_cfg.cow_primary_size, - ipt_filters: fuzz_cfg.ipt_filters, - input_buffer_size: fuzz_cfg.input_buffer_size, - }; - let qemu_id = fuzz_cfg.thread_id; - let qemu_params = params::QemuParams::new_from_kernel(&fuzz_cfg.workdir_path, qemu_id, ¶ms, fuzz_cfg.threads > 1); - - /* - if qemu_id == 0{ - qemu_process::QemuProcess::prepare_workdir(&fuzz_cfg.workdir_path, fuzz_cfg.seed_pattern.clone()); - } - */ +pub fn qemu_process_new(sharedir: String, cfg: &config::Config) -> Result { + + + let qemu_params = params::QemuParams::new(into_absolute_path(&sharedir), cfg); return qemu_process::QemuProcess::new(qemu_params); } - -pub fn qemu_process_new_from_snapshot(sharedir: String, cfg: &QemuSnapshotConfig, fuzz_cfg: &FuzzerConfig) -> Result { - - let snapshot_path = match &cfg.snapshot_path{ - SnapshotPath::Create(_x) => panic!(), - SnapshotPath::Reuse(x) => SnapshotPath::Reuse(x.to_string()), - SnapshotPath::DefaultPath => { - if fuzz_cfg.thread_id == 0 { - SnapshotPath::Create(format!("{}/snapshot/",fuzz_cfg.workdir_path)) - } else { - SnapshotPath::Reuse(format!("{}/snapshot/",fuzz_cfg.workdir_path)) - } - } - }; - - let params = params::SnapshotVmParams { - qemu_binary: cfg.qemu_binary.to_string(), - hda: cfg.hda.to_string(), - sharedir: into_absolute_path(&sharedir), - presnapshot: cfg.presnapshot.to_string(), - ram_size: fuzz_cfg.mem_limit, - bitmap_size: fuzz_cfg.bitmap_size, - debug: cfg.debug, - snapshot_path, - dump_python_code_for_inputs: match fuzz_cfg.dump_python_code_for_inputs{ - None => false, - Some(x) => x, - }, - write_protected_input_buffer: fuzz_cfg.write_protected_input_buffer, - cow_primary_size: fuzz_cfg.cow_primary_size, - ipt_filters: fuzz_cfg.ipt_filters, - input_buffer_size: fuzz_cfg.input_buffer_size, - }; - 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, ¶ms, fuzz_cfg.threads > 1); - - return qemu_process::QemuProcess::new(qemu_params); -} - - -#[cfg(test)] -mod tests { - //use crate::aux_buffer::*; - use super::params::*; - use super::qemu_process::*; - //use std::{thread, time}; - - #[test] - fn it_works() { - let workdir = "/tmp/workdir_test"; - let params = KernelVmParams { - qemu_binary: "/home/kafl/NEW2/QEMU-PT_4.2.0/x86_64-softmmu/qemu-system-x86_64" - .to_string(), - kernel: "/home/kafl/Target-Components/linux_initramfs/bzImage-linux-4.15-rc7" - .to_string(), - ramfs: "/home/kafl/Target-Components/linux_initramfs/init.cpio.gz".to_string(), - sharedir: "foo! invalid".to_string(), - ram_size: 1000, - bitmap_size: 0x1 << 16, - debug: false, - dump_python_code_for_inputs: false, - write_protected_input_buffer: false, - }; - let qemu_id = 1; - let qemu_params = QemuParams::new_from_kernel(workdir, qemu_id, ¶ms); - - QemuProcess::prepare_workdir(&workdir, None); - - let mut qemu_process = QemuProcess::new(qemu_params); - - for _i in 0..100 { - qemu_process.send_payload(); - } - println!("test done"); - } -} diff --git a/fuzz_runner/src/nyx/params.rs b/fuzz_runner/src/nyx/params.rs index df63da5..2574b44 100644 --- a/fuzz_runner/src/nyx/params.rs +++ b/fuzz_runner/src/nyx/params.rs @@ -1,38 +1,4 @@ -use crate::config::SnapshotPath; -use crate::config::IptFilter; - -pub struct KernelVmParams { - pub qemu_binary: String, - pub kernel: String, - pub sharedir: String, - pub ramfs: String, - pub ram_size: usize, - pub bitmap_size: usize, - pub debug: bool, - - pub dump_python_code_for_inputs: bool, - pub write_protected_input_buffer: bool, - pub cow_primary_size: Option, - pub ipt_filters: [IptFilter; 4], - pub input_buffer_size: usize, -} - -pub struct SnapshotVmParams{ - pub qemu_binary: String, - pub hda: String, - pub sharedir: String, - pub presnapshot: String, - pub snapshot_path: SnapshotPath, - pub ram_size: usize, - pub bitmap_size: usize, - pub debug: bool, - - pub dump_python_code_for_inputs: bool, - pub write_protected_input_buffer: bool, - pub cow_primary_size: Option, - pub ipt_filters: [IptFilter; 4], - pub input_buffer_size: usize, -} +use crate::{config::{Config, FuzzRunnerConfig, QemuNyxRole}, QemuProcess}; pub struct QemuParams { pub cmd: Vec, @@ -46,31 +12,54 @@ pub struct QemuParams { pub dump_python_code_for_inputs: bool, pub write_protected_input_buffer: bool, pub cow_primary_size: Option, + pub hprintf_fd: Option, + } impl QemuParams { - pub fn new_from_snapshot(workdir: &str, qemu_id: usize, cpu: usize, params: &SnapshotVmParams, create_snapshot_file: bool) -> QemuParams{ - + + pub fn new(sharedir: String, fuzzer_config: &Config) -> QemuParams { + + let mut cmd = vec![]; + let qemu_id = fuzzer_config.runtime.worker_id(); + let workdir = &fuzzer_config.fuzz.workdir_path; + + let debug = fuzzer_config.runtime.debug_mode(); + let qemu_aux_buffer_filename = format!("{}/aux_buffer_{}", workdir, qemu_id); let control_filename = format!("{}/interface_{}", workdir, qemu_id); - let mut cmd = vec![]; - cmd.push(params.qemu_binary.to_string()); + match fuzzer_config.runner.clone(){ + FuzzRunnerConfig::QemuKernel(x) => { + cmd.push(x.qemu_binary.to_string()); + cmd.push("-kernel".to_string()); + cmd.push(x.kernel.to_string()); + + cmd.push("-initrd".to_string()); + cmd.push(x.ramfs.to_string()); + + cmd.push("-append".to_string()); + cmd.push("nokaslr oops=panic nopti ignore_rlimit_data".to_string()); + }, + FuzzRunnerConfig::QemuSnapshot(x) => { + cmd.push(x.qemu_binary.to_string()); + cmd.push("-drive".to_string()); + cmd.push(format!("file={},format=raw,index=0,media=disk", x.hda.to_string())); + }, + } - cmd.push("-drive".to_string()); - cmd.push(format!("file={},format=raw,index=0,media=disk", params.hda.to_string())); - - if !params.debug { + /* generic QEMU-Nyx parameters */ + if !debug{ cmd.push("-display".to_string()); cmd.push("none".to_string()); } else { cmd.push("-vnc".to_string()); - cmd.push(format!(":{}",qemu_id+cpu)); + cmd.push(format!(":{}",qemu_id)); } cmd.push("-serial".to_string()); - if params.debug { + if debug { cmd.push("mon:stdio".to_string()); } else { cmd.push("stdio".to_string()); @@ -85,7 +74,7 @@ impl QemuParams { cmd.push("de".to_string()); cmd.push("-m".to_string()); - cmd.push(params.ram_size.to_string()); + cmd.push(fuzzer_config.fuzz.mem_limit.to_string()); cmd.push("-chardev".to_string()); cmd.push(format!( @@ -95,23 +84,22 @@ impl QemuParams { cmd.push("-device".to_string()); let mut nyx_ops = format!("nyx,chardev=nyx_interface"); - nyx_ops += &format!(",bitmap_size={}", params.bitmap_size); - nyx_ops += &format!(",input_buffer_size={}", params.input_buffer_size); + nyx_ops += &format!(",bitmap_size={}", fuzzer_config.fuzz.bitmap_size); + nyx_ops += &format!(",input_buffer_size={}", fuzzer_config.fuzz.input_buffer_size); nyx_ops += &format!(",worker_id={}", qemu_id); nyx_ops += &format!(",workdir={}", workdir); - nyx_ops += &format!(",sharedir={}", params.sharedir); + nyx_ops += &format!(",sharedir={}", sharedir); - let mut i = 0; - for filter in params.ipt_filters{ + for filter in fuzzer_config.fuzz.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()); + if fuzzer_config.fuzz.cow_primary_size.is_some(){ + nyx_ops += &format!(",cow_primary_size={}", fuzzer_config.fuzz.cow_primary_size.unwrap()); } cmd.push(nyx_ops); @@ -122,132 +110,75 @@ impl QemuParams { cmd.push("-cpu".to_string()); cmd.push("kAFL64-Hypervisor-v1".to_string()); - match ¶ms.snapshot_path { - SnapshotPath::Create(path) => { - if create_snapshot_file { - cmd.push("-fast_vm_reload".to_string()); - cmd.push(format!("path={},load=off,pre_path={}", path,params.presnapshot)); - } - else{ - cmd.push("-fast_vm_reload".to_string()); - cmd.push(format!("path={},load=off,pre_path={},skip_serialization=on", path,params.presnapshot)); - } - }, - SnapshotPath::Reuse(path) => { - cmd.push("-fast_vm_reload".to_string()); - cmd.push(format!("path={},load=on", path)); - } - SnapshotPath::DefaultPath => panic!(), - } - - return QemuParams { - cmd, - qemu_aux_buffer_filename, - control_filename, - workdir: workdir.to_string(), - qemu_id, - bitmap_size: params.bitmap_size, - payload_size: params.input_buffer_size, - dump_python_code_for_inputs: params.dump_python_code_for_inputs, - write_protected_input_buffer: params.write_protected_input_buffer, - cow_primary_size: params.cow_primary_size, - }; - } - pub fn new_from_kernel(workdir: &str, qemu_id: usize, params: &KernelVmParams, create_snapshot_file: bool) -> QemuParams { - - let qemu_aux_buffer_filename = format!("{}/aux_buffer_{}", workdir, qemu_id); - let control_filename = format!("{}/interface_{}", workdir, qemu_id); - - let mut cmd = vec![]; - cmd.push(params.qemu_binary.to_string()); - cmd.push("-kernel".to_string()); - cmd.push(params.kernel.to_string()); - - cmd.push("-initrd".to_string()); - cmd.push(params.ramfs.to_string()); - - cmd.push("-append".to_string()); - cmd.push("nokaslr oops=panic nopti ignore_rlimit_data".to_string()); - - if !params.debug { - cmd.push("-display".to_string()); - cmd.push("none".to_string()); - } - - cmd.push("-serial".to_string()); - if params.debug { - cmd.push("mon:stdio".to_string()); - } else { - cmd.push("none".to_string()); - } - - cmd.push("-enable-kvm".to_string()); - - cmd.push("-net".to_string()); - cmd.push("none".to_string()); - - cmd.push("-k".to_string()); - cmd.push("de".to_string()); - - cmd.push("-m".to_string()); - cmd.push(params.ram_size.to_string()); - - - cmd.push("-chardev".to_string()); - cmd.push(format!( - "socket,server,path={},id=nyx_interface", - control_filename - )); - - cmd.push("-device".to_string()); - let mut nyx_ops = format!("nyx,chardev=nyx_interface"); - nyx_ops += &format!(",bitmap_size={}", params.bitmap_size); - nyx_ops += &format!(",input_buffer_size={}", params.input_buffer_size); - nyx_ops += &format!(",worker_id={}", qemu_id); - 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()); - } - - cmd.push(nyx_ops); - - cmd.push("-machine".to_string()); - cmd.push("kAFL64-v1".to_string()); - - cmd.push("-cpu".to_string()); - cmd.push("kAFL64-Hypervisor-v1,+vmx".to_string()); - - if create_snapshot_file { + if fuzzer_config.runtime.reuse_root_snapshot_path().is_some() { cmd.push("-fast_vm_reload".to_string()); - if qemu_id == 0{ - cmd.push(format!("path={}/snapshot/,load=off", workdir)); - } else { - cmd.push(format!("path={}/snapshot/,load=on", workdir)); + cmd.push(format!("path={},load=on", fuzzer_config.runtime.reuse_root_snapshot_path().unwrap())); + } + else{ + match fuzzer_config.runner.clone(){ + FuzzRunnerConfig::QemuKernel(_) => { + + match fuzzer_config.runtime.process_role() { + QemuNyxRole::StandAlone => {}, + QemuNyxRole::Parent => { + cmd.push("-fast_vm_reload".to_string()); + cmd.push(format!("path={}/snapshot/,load=off", workdir)); + }, + QemuNyxRole::Child => { + cmd.push("-fast_vm_reload".to_string()); + cmd.push(format!("path={}/snapshot/,load=on", workdir)); + }, + }; + }, + FuzzRunnerConfig::QemuSnapshot(x) => { + + match fuzzer_config.runtime.process_role() { + QemuNyxRole::StandAlone => { + cmd.push("-fast_vm_reload".to_string()); + cmd.push(format!("path={}/snapshot/,load=off,pre_path={},skip_serialization=on", workdir, x.presnapshot)); + + }, + QemuNyxRole::Parent => { + cmd.push("-fast_vm_reload".to_string()); + cmd.push(format!("path={}/snapshot/,load=off,pre_path={}", workdir, x.presnapshot)); + }, + QemuNyxRole::Child => { + cmd.push("-fast_vm_reload".to_string()); + cmd.push(format!("path={}/snapshot/,load=on,pre_path={}", workdir, x.presnapshot)); + }, + }; + }, } } + match fuzzer_config.runtime.process_role() { + QemuNyxRole::StandAlone | QemuNyxRole::Parent => { + assert!(qemu_id == 0); + QemuProcess::prepare_workdir(workdir, fuzzer_config.fuzz.seed_path.clone()); + }, + QemuNyxRole::Child => { + QemuProcess::wait_for_workdir(workdir); + }, + }; + + return QemuParams { cmd, qemu_aux_buffer_filename, control_filename, workdir: workdir.to_string(), qemu_id, - bitmap_size: params.bitmap_size, - payload_size: params.input_buffer_size, - dump_python_code_for_inputs: params.dump_python_code_for_inputs, - write_protected_input_buffer: params.write_protected_input_buffer, - cow_primary_size: params.cow_primary_size, - }; + bitmap_size: fuzzer_config.fuzz.bitmap_size, + payload_size: fuzzer_config.fuzz.input_buffer_size, + dump_python_code_for_inputs: match fuzzer_config.fuzz.dump_python_code_for_inputs{ + None => false, + Some(x) => x, + }, + write_protected_input_buffer: fuzzer_config.fuzz.write_protected_input_buffer, + cow_primary_size: fuzzer_config.fuzz.cow_primary_size, + hprintf_fd: fuzzer_config.runtime.hprintf_fd(), + } } + } diff --git a/fuzz_runner/src/nyx/qemu_process.rs b/fuzz_runner/src/nyx/qemu_process.rs index 12ce543..757ba05 100644 --- a/fuzz_runner/src/nyx/qemu_process.rs +++ b/fuzz_runner/src/nyx/qemu_process.rs @@ -1,4 +1,5 @@ use core::ffi::c_void; +use std::os::unix::prelude::FromRawFd; use std::path::PathBuf; use nix::sys::mman::*; use std::fs; @@ -33,8 +34,12 @@ use crate::nyx::mem_barrier::mem_barrier; use crate::nyx::params::QemuParams; pub struct QemuProcess { - pub process: Child, - pub aux: AuxBuffer, + + process: Child, + + /* ptr to the aux buffer */ + aux: AuxBuffer, + pub feedback_data: FeedbackBuffer, pub ijon_buffer: &'static mut [u8], pub ctrl: UnixStream, @@ -46,6 +51,8 @@ pub struct QemuProcess { shm_work_dir: PathBuf, #[allow(unused)] shm_file_lock: File, + + hprintf_file: Option, } fn execute_qemu(ctrl: &mut UnixStream) -> io::Result<()>{ @@ -168,12 +175,6 @@ impl QemuProcess { let ijon_shared = make_shared_data(&ijon_buffer_shm_f, 0x1000); let ijon_feedback_buffer = make_shared_ijon_data(ijon_buffer_shm_f, 0x1000); - - thread::sleep(time::Duration::from_secs(1)); - - thread::sleep(time::Duration::from_millis(200*params.qemu_id as u64)); - - let mut child = if params.dump_python_code_for_inputs{ Command::new(¶ms.cmd[0]) .args(¶ms.cmd[1..]) @@ -188,12 +189,6 @@ impl QemuProcess { .expect("failed to execute process") }; - - thread::sleep(time::Duration::from_secs(1)); - - thread::sleep(time::Duration::from_millis(200*params.qemu_id as u64)); - - let mut control = loop { match UnixStream::connect(¶ms.control_filename) { Ok(stream) => break stream, @@ -207,19 +202,15 @@ impl QemuProcess { return Err(format!("cannot launch QEMU-Nyx...")); } - let aux_shm_f = OpenOptions::new() - .read(true) - .write(true) - .open(¶ms.qemu_aux_buffer_filename) - .expect("couldn't open aux buffer file"); - aux_shm_f.set_len(0x1000).unwrap(); + let mut aux_buffer = { + let aux_shm_f = OpenOptions::new() + .read(true) + .write(true) + .open(¶ms.qemu_aux_buffer_filename) + .expect("couldn't open aux buffer file"); - let aux_shm_f = OpenOptions::new() - .write(true) - .read(true) - .open(¶ms.qemu_aux_buffer_filename) - .expect("couldn't open aux buffer file"); - let mut aux_buffer = AuxBuffer::new(aux_shm_f); + AuxBuffer::new(aux_shm_f) + }; match aux_buffer.validate_header(){ Err(x) => { @@ -237,12 +228,17 @@ impl QemuProcess { aux_buffer.config.changed = 1; } + let mut hprintf_file = match params.hprintf_fd { + Some(fd) => Some(unsafe { File::from_raw_fd(fd) }), + None => None, + }; + loop { match aux_buffer.result.exec_result_code { NYX_HPRINTF => { let len = aux_buffer.misc.len; - print!("{}", String::from_utf8_lossy(&aux_buffer.misc.data[0..len as usize]).yellow()); + QemuProcess::output_hprintf(&mut hprintf_file, &String::from_utf8_lossy(&aux_buffer.misc.data[0..len as usize]).yellow()); }, NYX_ABORT => { let len = aux_buffer.misc.len; @@ -313,9 +309,32 @@ impl QemuProcess { params, shm_work_dir, shm_file_lock: file_lock, + hprintf_file, }); } + fn output_hprintf(hprintf_file: &mut Option, msg: &str){ + match hprintf_file { + Some(ref mut f) => { + f.write_fmt(format_args!("{}", msg)).unwrap(); + }, + None => { + print!("{}", msg); + } + } + } + + pub fn aux_buffer(&self) -> &AuxBuffer{ + &self.aux + } + + pub fn aux_buffer_mut(&mut self) -> &mut AuxBuffer{ + &mut self.aux + } + + pub fn set_hprintf_fd(&mut self, fd: i32){ + self.hprintf_file = unsafe { Some(File::from_raw_fd(fd)) }; + } pub fn send_payload(&mut self) -> io::Result<()>{ let mut old_address: u64 = 0; @@ -355,7 +374,7 @@ impl QemuProcess { match self.aux.result.exec_result_code { NYX_HPRINTF => { let len = self.aux.misc.len; - print!("{}", String::from_utf8_lossy(&self.aux.misc.data[0..len as usize]).yellow()); + QemuProcess::output_hprintf(&mut self.hprintf_file, &String::from_utf8_lossy(&self.aux.misc.data[0..len as usize]).yellow()); continue; }, NYX_ABORT => {