diff --git a/libnyx/src/ffi.rs b/libnyx/src/ffi.rs
index 6fb97b9..0a608a9 100644
--- a/libnyx/src/ffi.rs
+++ b/libnyx/src/ffi.rs
@@ -1,3 +1,20 @@
+/*
+ libnyx FFI API
+
+ Copyright (C) 2021 Sergej Schumilo
+ This file is part of libnyx.
+
+ libnyx is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+ libnyx is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with libnyx. If not, see .
+ */
use libc::c_char;
use std::ffi::CStr;
use std::ffi::c_void;
@@ -5,16 +22,34 @@ use std::ffi::c_void;
use fuzz_runner::nyx::aux_buffer::{NYX_CRASH, NYX_HPRINTF, NYX_ABORT};
use super::*;
-#[no_mangle]
-pub extern "C" fn nyx_load_config(sharedir: *const c_char) -> *mut c_void {
- let sharedir_c_str = unsafe {
- assert!(!sharedir.is_null());
- CStr::from_ptr(sharedir)
+/* Helper function to load a C string pointer and return a Rust string. */
+fn __load_c_string_ptr(pointer: *const c_char) -> String {
+ let c_str = unsafe {
+ assert!(!pointer.is_null());
+ CStr::from_ptr(pointer)
};
- let sharedir_r_str = sharedir_c_str.to_str().unwrap();
+ c_str.to_str().unwrap().to_string()
+}
- let cfg: NyxConfig = match NyxConfig::load(sharedir_r_str){
+/* Helper function to check if the config pointer is valid.
+ * Turns the pointer into a reference to a config object.
+ */
+fn __nyx_config_check_ptr(config: * mut c_void) -> *mut NyxConfig {
+ assert!(!config.is_null());
+ assert!((config as usize) % std::mem::align_of::() == 0);
+
+ config as *mut NyxConfig
+}
+
+/* Loads a given Nyx share-dir and returns a raw pointer to the Nyx config object.
+ * The pointer is later used to access the config object in other FFI config functions.
+ */
+#[no_mangle]
+pub extern "C" fn nyx_config_load(sharedir: *const c_char) -> *mut c_void {
+ let sharedir_r_str = __load_c_string_ptr(sharedir);
+
+ let cfg: NyxConfig = match NyxConfig::load(&sharedir_r_str){
Ok(x) => x,
Err(msg) => {
println!("[!] libnyx config reader error: {}", msg);
@@ -25,32 +60,93 @@ pub extern "C" fn nyx_load_config(sharedir: *const c_char) -> *mut c_void {
Box::into_raw(Box::new(cfg)) as *mut c_void
}
+/* Simple debug function to print the entire config object to stdout. */
#[no_mangle]
-pub extern "C" fn nyx_print_config(config: * mut c_void) {
- unsafe{
- assert!(!config.is_null());
- assert!((config as usize) % std::mem::align_of::() == 0);
+pub extern "C" fn nyx_config_debug(config: * mut c_void) {
+ let cfg = __nyx_config_check_ptr(config);
- let cfg = config as *mut NyxConfig;
+ unsafe{
println!("{}", *cfg);
}
}
-fn nyx_process_start(sharedir: *const c_char, workdir: *const c_char, worker_id: u32, cpu_id: u32, create_snapshot: bool, input_buffer_size: Option, input_buffer_write_protection: bool) -> * mut NyxProcess {
- let sharedir_c_str = unsafe {
- assert!(!sharedir.is_null());
- CStr::from_ptr(sharedir)
- };
-
- let workdir_c_str = unsafe {
- assert!(!workdir.is_null());
- CStr::from_ptr(workdir)
- };
+/* Simple debug function to print a subset of configurable options to stdout. */
+#[no_mangle]
+pub extern "C" fn nyx_config_print(config: * mut c_void) {
+ unsafe{
+ NyxConfig::print(&*__nyx_config_check_ptr(config));
+ }
+}
- let sharedir_r_str = sharedir_c_str.to_str().unwrap();
- let workdir_r_str = workdir_c_str.to_str().unwrap();
+/* FFI function to set the workdir path in the config object. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_workdir_path(config: * mut c_void, workdir: *const c_char) {
+ let workidr_r_str = __load_c_string_ptr(workdir);
+ let cfg = __nyx_config_check_ptr(config);
+
+ unsafe{
+ NyxConfig::set_workdir_path(&mut *cfg, workidr_r_str.to_string());
+ }
+}
+
+/* FFI function to set the input buffer size in the config object. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_input_buffer_size(config: * mut c_void, input_buffer_size: u32) {
+ let cfg = __nyx_config_check_ptr(config);
+
+ assert_eq!(input_buffer_size > 0, true);
+ unsafe{
+ NyxConfig::set_input_buffer_size(&mut *cfg, input_buffer_size as usize);
+ }
+}
+
+/* FFI function to set the input buffer write protection in the config object. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_input_buffer_write_protection(config: * mut c_void, input_buffer_write_protection: bool) {
+ let cfg = __nyx_config_check_ptr(config);
+
+ unsafe{
+ NyxConfig::set_input_buffer_write_protection(&mut *cfg, input_buffer_write_protection);
+ }
+}
+
+/* FFI function to set the hprintf file descriptor in the config object. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_hprintf_fd(config: * mut c_void, hprintf_fd: i32) {
+ let cfg = __nyx_config_check_ptr(config);
+
+ unsafe{
+ NyxConfig::set_hprintf_fd(&mut *cfg, hprintf_fd);
+ }
+}
+
+/* FFI function to set the fuzz runner role in the config object. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_process_role(config: * mut c_void, role: NyxProcessRole) {
+ let cfg = __nyx_config_check_ptr(config);
+
+ unsafe{
+ NyxConfig::set_process_role(&mut *cfg, role);
+ }
+}
+
+/* Enable snapshot reuse by setting the path to the snapshot folder. */
+#[no_mangle]
+pub extern "C" fn nyx_config_set_reuse_snapshot_path(config: * mut c_void, reuse_snapshot_path: *const c_char) {
+ let reuse_snapshot_path_r_str = __load_c_string_ptr(reuse_snapshot_path);
+ let cfg = __nyx_config_check_ptr(config);
+
+ unsafe{
+ NyxConfig::set_reuse_snapshot_path(&mut *cfg, reuse_snapshot_path_r_str.to_string());
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nyx_new(config: * mut c_void, worker_id: u32) -> * mut NyxProcess {
- match NyxProcess::process_start(sharedir_r_str, workdir_r_str, worker_id, cpu_id, create_snapshot, input_buffer_size, input_buffer_write_protection) {
+ let cfg = __nyx_config_check_ptr(config);
+
+ match NyxProcess::new(unsafe {&mut *(cfg)}, worker_id as usize) {
Ok(x) => Box::into_raw(Box::new(x)),
Err(msg) => {
println!("[!] libnyx failed to initialize QEMU-Nyx: {}", msg);
@@ -59,106 +155,68 @@ fn nyx_process_start(sharedir: *const c_char, workdir: *const c_char, worker_id:
}
}
-#[no_mangle]
-pub extern "C" fn nyx_new(sharedir: *const c_char, workdir: *const c_char, cpu_id: u32, input_buffer_size: u32, input_buffer_write_protection: bool) -> * mut NyxProcess {
- nyx_process_start(sharedir, workdir, 0, cpu_id, false, Some(input_buffer_size), input_buffer_write_protection)
-}
-
-
-#[no_mangle]
-pub extern "C" fn nyx_new_parent(sharedir: *const c_char, workdir: *const c_char, cpu_id: u32, input_buffer_size: u32, input_buffer_write_protection: bool) -> * mut NyxProcess {
- nyx_process_start(sharedir, workdir, 0, cpu_id, true, Some(input_buffer_size), input_buffer_write_protection)
-}
-
-#[no_mangle]
-pub extern "C" fn nyx_new_child(sharedir: *const c_char, workdir: *const c_char, cpu_id: u32, worker_id: u32) -> * mut NyxProcess {
- if worker_id == 0 {
- println!("[!] libnyx failed -> worker_id=0 cannot be used for child processes");
- std::ptr::null_mut() as *mut NyxProcess
- }
- else{
- nyx_process_start(sharedir, workdir, worker_id, cpu_id, true, None, false)
- }
-}
-
+/* Helper function to check if the NyxProcess pointer is valid.
+ * Turns the pointer into a reference to the NyxProcess object.
+ */
+fn __nyx_process_check_ptr(nyx_process: * mut NyxProcess) -> *mut NyxProcess {
+ assert!(!nyx_process.is_null());
+ assert!((nyx_process as usize) % std::mem::align_of::() == 0);
+ nyx_process as *mut NyxProcess
+}
#[no_mangle]
pub extern "C" fn nyx_get_aux_buffer(nyx_process: * mut NyxProcess) -> *mut u8 {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- return (*nyx_process).aux_buffer_as_mut_ptr();
+ return (*__nyx_process_check_ptr(nyx_process)).aux_buffer_as_mut_ptr();
}
}
#[no_mangle]
pub extern "C" fn nyx_get_input_buffer(nyx_process: * mut NyxProcess) -> *mut u8 {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- return (*nyx_process).input_buffer_mut().as_mut_ptr();
+ return (*__nyx_process_check_ptr(nyx_process)).input_buffer_mut().as_mut_ptr();
}
}
#[no_mangle]
pub extern "C" fn nyx_get_bitmap_buffer(nyx_process: * mut NyxProcess) -> *mut u8 {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- return (*nyx_process).bitmap_buffer_mut().as_mut_ptr();
+ return (*__nyx_process_check_ptr(nyx_process)).bitmap_buffer_mut().as_mut_ptr();
}
}
#[no_mangle]
pub extern "C" fn nyx_get_bitmap_buffer_size(nyx_process: * mut NyxProcess) -> usize {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
- //return (*nyx_process).process.bitmap.len();
- return (*nyx_process).bitmap_buffer_size();
+ return (*__nyx_process_check_ptr(nyx_process)).bitmap_buffer_size();
}
}
#[no_mangle]
pub extern "C" fn nyx_shutdown(nyx_process: * mut NyxProcess) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).shutdown();
+ (*__nyx_process_check_ptr(nyx_process)).shutdown();
}
}
#[no_mangle]
pub extern "C" fn nyx_option_set_reload_mode(nyx_process: * mut NyxProcess, enable: bool) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).option_set_reload_mode(enable);
+ (*__nyx_process_check_ptr(nyx_process)).option_set_reload_mode(enable);
}
}
#[no_mangle]
pub extern "C" fn nyx_option_set_timeout(nyx_process: * mut NyxProcess, timeout_sec: u8, timeout_usec: u32) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).option_set_timeout(timeout_sec, timeout_usec);
+ (*__nyx_process_check_ptr(nyx_process)).option_set_timeout(timeout_sec, timeout_usec);
}
}
#[no_mangle]
pub extern "C" fn nyx_option_apply(nyx_process: * mut NyxProcess) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).option_apply();
+ (*__nyx_process_check_ptr(nyx_process)).option_apply();
}
}
@@ -166,10 +224,7 @@ pub extern "C" fn nyx_option_apply(nyx_process: * mut NyxProcess) {
pub extern "C" fn nyx_exec(nyx_process: * mut NyxProcess) -> NyxReturnValue {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).exec()
+ (*__nyx_process_check_ptr(nyx_process)).exec()
}
}
@@ -177,11 +232,8 @@ pub extern "C" fn nyx_exec(nyx_process: * mut NyxProcess) -> NyxReturnValue {
pub extern "C" fn nyx_set_afl_input(nyx_process: * mut NyxProcess, buffer: *mut u8, size: u32) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
assert!((buffer as usize) % std::mem::align_of::() == 0);
-
- (*nyx_process).set_input_ptr(buffer, size);
+ (*__nyx_process_check_ptr(nyx_process)).set_input_ptr(buffer, size);
}
}
@@ -189,14 +241,14 @@ pub extern "C" fn nyx_set_afl_input(nyx_process: * mut NyxProcess, buffer: *mut
#[no_mangle]
pub extern "C" fn nyx_print_aux_buffer(nyx_process: * mut NyxProcess) {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
- print!("{}", format!("{:#?}", (*nyx_process).process.aux.result));
+ let nyx_process = __nyx_process_check_ptr(nyx_process);
- match (*nyx_process).process.aux.result.exec_result_code {
+ print!("{}", format!("{:#?}", (*nyx_process).process.aux_buffer().result));
+
+ match (*nyx_process).process.aux_buffer().result.exec_result_code {
NYX_CRASH | NYX_ABORT | NYX_HPRINTF => {
- println!("{}", std::str::from_utf8(&(*nyx_process).process.aux.misc.data).unwrap());
+ println!("{}", std::str::from_utf8(&(*nyx_process).process.aux_buffer().misc.data).unwrap());
},
_ => {},
}
@@ -207,12 +259,19 @@ pub extern "C" fn nyx_print_aux_buffer(nyx_process: * mut NyxProcess) {
pub extern "C" fn nyx_get_aux_string(nyx_process: * mut NyxProcess, buffer: *mut u8, size: u32) -> u32 {
unsafe{
- assert!(!nyx_process.is_null());
- assert!((nyx_process as usize) % std::mem::align_of::() == 0);
+ let nyx_process = __nyx_process_check_ptr(nyx_process);
assert!((buffer as usize) % std::mem::align_of::() == 0);
- let len = std::cmp::min( (*nyx_process).process.aux.misc.len as usize, size as usize);
- std::ptr::copy((*nyx_process).process.aux.misc.data.as_mut_ptr(), buffer, len);
+ let len = std::cmp::min( (*nyx_process).process.aux_buffer().misc.len as usize, size as usize);
+ std::ptr::copy((*nyx_process).process.aux_buffer_mut().misc.data.as_mut_ptr(), buffer, len);
len as u32
}
}
+
+
+#[no_mangle]
+pub extern "C" fn nyx_set_hprintf_fd(nyx_process: * mut NyxProcess, fd: i32) {
+ unsafe{
+ (*__nyx_process_check_ptr(nyx_process)).process.set_hprintf_fd(fd);
+ }
+}
diff --git a/libnyx/src/lib.rs b/libnyx/src/lib.rs
index 50ae874..2d53729 100644
--- a/libnyx/src/lib.rs
+++ b/libnyx/src/lib.rs
@@ -1,11 +1,27 @@
+/*
+ libnyx Rust API
+
+ Copyright (C) 2021 Sergej Schumilo
+ This file is part of libnyx.
+
+ libnyx is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+ libnyx is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with libnyx. If not, see .
+ */
extern crate libc;
-use config::{Config, FuzzRunnerConfig};
+use config::{Config, FuzzRunnerConfig, QemuNyxRole};
-use fuzz_runner::nyx::qemu_process_new_from_kernel;
-use fuzz_runner::nyx::qemu_process_new_from_snapshot;
use fuzz_runner::nyx::qemu_process::QemuProcess;
use fuzz_runner::nyx::aux_buffer::{NYX_SUCCESS, NYX_CRASH, NYX_TIMEOUT, NYX_INPUT_WRITE, NYX_ABORT};
+use libc::fcntl;
use std::fmt;
@@ -24,6 +40,14 @@ pub enum NyxReturnValue {
Abort, // Abort hypercall called
}
+#[repr(C)]
+#[derive(Debug)]
+pub enum NyxProcessRole {
+ StandAlone,
+ Parent,
+ Child,
+}
+
impl fmt::Display for NyxReturnValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -48,18 +72,42 @@ pub struct NyxProcess {
#[derive(Clone, Debug)]
pub struct NyxConfig {
config: Config,
+ sharedir_path: String,
}
impl NyxConfig {
+
+ /* Loads a given Nyx share-dir and returns a result object containing the config object.
+ * The config object is later used to access the config object via specific config functions.
+ */
pub fn load(sharedir: &str) -> Result {
+ /* TODO: perform some additional sanity checks on the sharedir (such as checking if the bootstrap scripts exist) */
match Config::new_from_sharedir(&sharedir){
Ok(x) => Ok(NyxConfig{
- config: x
+ config: x,
+ sharedir_path: sharedir.to_string()
}),
Err(x) => Err(x),
}
}
+ /* Simple debug function to print the entire config object to stdout. */
+ pub fn print(&self){
+ println!("[*] Nyx config (share-dir: {}):", self.sharedir_path());
+ println!(" - workdir_path -> {}", self.workdir_path());
+ println!(" - input_buffer_size -> {}", self.input_buffer_size());
+ println!(" - input_buffer_write_protection -> {}", self.input_buffer_write_protection());
+ println!(" - hprintf_fd -> {}", self.hprintf_fd());
+ println!(" - process_role: -> {:?}", self.process_role());
+
+ }
+
+ /* Returns the path to the actual sharedir. */
+ pub fn sharedir_path(&self) -> String {
+ self.sharedir_path.clone()
+ }
+
+ /* Returns the path to the configured qemu binary. */
pub fn qemu_binary_path(&self) -> Option{
let process_cfg= match self.config.runner.clone() {
FuzzRunnerConfig::QemuKernel(cfg) => cfg,
@@ -68,6 +116,7 @@ impl NyxConfig {
return Some(process_cfg.qemu_binary);
}
+ /* Returns the path to the configured kernel image (if Nyx is configured to run in kernel mode). */
pub fn kernel_image_path(&self) -> Option{
let process_cfg= match self.config.runner.clone() {
FuzzRunnerConfig::QemuKernel(cfg) => cfg,
@@ -76,6 +125,7 @@ impl NyxConfig {
return Some(process_cfg.kernel);
}
+ /* Returns the path to the configured initrd image (if Nyx is configured to run in kernel mode). */
pub fn ramfs_image_path(&self) -> Option{
let process_cfg= match self.config.runner.clone() {
FuzzRunnerConfig::QemuKernel(cfg) => cfg,
@@ -84,26 +134,100 @@ impl NyxConfig {
return Some(process_cfg.ramfs);
}
+ /* Returns the configured timeout threshold as a std::time::Duration object. */
pub fn timeout(&self) -> std::time::Duration {
self.config.fuzz.time_limit
}
+ /* Returns the configured spec path (deprecated). */
pub fn spec_path(&self) -> String{
self.config.fuzz.spec_path.clone()
}
+ /* Returns the configured trace bitmap size (might be reconfigured later by the agent). */
pub fn bitmap_size(&self) -> usize{
self.config.fuzz.bitmap_size
}
+ /* Returns the configured workdir path. */
pub fn workdir_path(&self) -> &str {
&self.config.fuzz.workdir_path
}
+ /* Returns the actual size of the input buffer. */
+ pub fn input_buffer_size(&self) -> usize {
+ self.config.fuzz.input_buffer_size
+ }
+
+ /* Returns the config value of the input buffer write protection of the agent (guest). */
+ pub fn input_buffer_write_protection(&self) -> bool {
+ self.config.fuzz.write_protected_input_buffer
+ }
+
+ /* Sets the path to the workdir. */
pub fn set_workdir_path(&mut self, path: String) {
self.config.fuzz.workdir_path = path;
}
+ /* Set the size of the input buffer (must be a multiple of x86_64_PAGE_SIZE -> 4096). */
+ pub fn set_input_buffer_size(&mut self, size: usize) {
+ if size % 0x1000 != 0 {
+ /* TODO: return error */
+ panic!("[ ] Input buffer size must be a multiple of x86_64_PAGE_SIZE (4096)!");
+ }
+ self.config.fuzz.input_buffer_size = size;
+ }
+
+ /* Set the input buffer write protection of the agent (guest). */
+ pub fn set_input_buffer_write_protection(&mut self, write_protected: bool) {
+ self.config.fuzz.write_protected_input_buffer = write_protected;
+ }
+
+ /* Returns the current configured FD to redirect hprintf() calls to (returns -1 if None is set). */
+ pub fn hprintf_fd(&self) -> i32 {
+ /* TODO: fix me */
+ match self.config.runtime.hprintf_fd() {
+ Some(fd) => fd,
+ None => -1,
+ }
+ }
+
+ /* Sets the FD to redirect hprintf() calls to (must be a valid FD and must not be closed after this call). */
+ pub fn set_hprintf_fd(&mut self, fd: i32) {
+ self.config.runtime.set_hpintf_fd(fd);
+ }
+
+ /* Sets the process role of the fuzz runner */
+ pub fn set_process_role(&mut self, role: NyxProcessRole) {
+ let _role = match role {
+ NyxProcessRole::Parent => QemuNyxRole::Parent,
+ NyxProcessRole::Child => QemuNyxRole::Child,
+ NyxProcessRole::StandAlone => QemuNyxRole::StandAlone,
+ };
+
+ self.config.runtime.set_process_role(_role);
+ }
+
+ /* Configures the path to the snapshot file to be reused (optional). */
+ pub fn set_reuse_snapshot_path(&mut self, path: String) {
+ self.config.runtime.set_reuse_snapshot_path(path);
+ }
+
+ /* Returns the currently configured process role of the fuzz runner. */
+ pub fn process_role(&self) -> &QemuNyxRole {
+ self.config.runtime.process_role()
+ }
+
+ /* Returns the current QEMU-Nyx worker ID. */
+ pub fn worker_id(&self) -> usize {
+ self.config.runtime.worker_id()
+ }
+
+ /* Sets the QEMU-Nyx worker ID. */
+ pub fn set_worker_id(&mut self, worker_id: usize) {
+ self.config.runtime.set_worker_id(worker_id);
+ }
+
pub fn dict(&self) -> Vec> {
self.config.fuzz.dict.clone()
}
@@ -117,56 +241,12 @@ impl fmt::Display for NyxConfig {
impl NyxProcess {
- fn start_process(sharedir: &str, workdir: &str, fuzzer_config: Config, worker_id: u32) -> Result {
+ pub fn new(config: &mut NyxConfig, worker_id: usize) -> Result {
- let mut config = fuzzer_config.fuzz;
- let runner_cfg = fuzzer_config.runner;
-
- config.workdir_path = format!("{}", workdir);
-
- let sdir = sharedir.clone();
-
- 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() {
- FuzzRunnerConfig::QemuSnapshot(cfg) => {
- qemu_process_new_from_snapshot(sdir.to_string(), &cfg, &config)
- },
- FuzzRunnerConfig::QemuKernel(cfg) => {
- qemu_process_new_from_kernel(sdir.to_string(), &cfg, &config)
- }
- }
- }
+ let sharedir = config.sharedir_path();
+ config.set_worker_id(worker_id);
- fn process_start(sharedir: &str, workdir: &str, worker_id: u32, cpu_id: u32, create_snapshot: bool, input_buffer_size: Option, input_buffer_write_protection: bool) -> Result {
- let mut cfg: Config = match Config::new_from_sharedir(&sharedir){
- Ok(x) => x,
- Err(msg) => {
- return Err(format!("[!] libnyx config reader error: {}", msg));
- }
- };
-
- cfg.fuzz.write_protected_input_buffer = input_buffer_write_protection;
-
- /* todo: add sanity check */
- cfg.fuzz.cpu_pin_start_at = cpu_id as usize;
-
- match input_buffer_size{
- Some(x) => { cfg.fuzz.input_buffer_size = x as usize; },
- None => {},
- }
-
- cfg.fuzz.thread_id = worker_id as usize;
- cfg.fuzz.threads = if create_snapshot { 2 as usize } else { 1 as usize };
-
- cfg.fuzz.workdir_path = format!("{}", workdir);
-
- match Self::start_process(sharedir, workdir, cfg, worker_id){
+ match fuzz_runner::nyx::qemu_process_new(sharedir.to_string(), &config.config){
Ok(x) => Ok(NyxProcess{
process: x,
}),
@@ -174,41 +254,9 @@ impl NyxProcess {
}
}
- pub fn from_config(sharedir: &str, config: &NyxConfig, worker_id: u32, create_snapshot: bool) -> Result{
- let workdir = config.config.fuzz.workdir_path.clone();
-
- let mut config= config.clone();
- config.config.fuzz.threads = if create_snapshot { 2 as usize } else { 1 as usize };
- config.config.fuzz.thread_id = worker_id as usize;
-
- match Self::start_process(sharedir, &workdir, config.config.clone(), worker_id) {
- Ok(x) => Ok(NyxProcess{
- process: x,
- }),
- Err(x) => Err(x),
- }
- }
-
- pub fn new(sharedir: &str, workdir: &str, cpu_id: u32, input_buffer_size: u32, input_buffer_write_protection: bool) -> Result {
- Self::process_start(sharedir, workdir, 0, cpu_id, false, Some(input_buffer_size), input_buffer_write_protection)
- }
-
- pub fn new_parent(sharedir: &str, workdir: &str, cpu_id: u32, input_buffer_size: u32, input_buffer_write_protection: bool) -> Result {
- Self::process_start(sharedir, workdir, 0, cpu_id, true, Some(input_buffer_size), input_buffer_write_protection)
- }
-
- pub fn new_child(sharedir: &str, workdir: &str, cpu_id: u32, worker_id: u32) -> Result {
- if worker_id == 0 {
- println!("[!] libnyx failed -> worker_id=0 cannot be used for child processes");
- Err("worker_id=0 cannot be used for child processes".to_string())
- }
- else{
- Self::process_start(sharedir, workdir, worker_id, cpu_id, true, None, false)
- }
- }
pub fn aux_buffer_as_mut_ptr(&self) -> *mut u8 {
- std::ptr::addr_of!(self.process.aux.header.magic) as *mut u8
+ std::ptr::addr_of!(self.process.aux_buffer().header.magic) as *mut u8
}
pub fn input_buffer(&self) -> &[u8] {
@@ -244,48 +292,48 @@ impl NyxProcess {
}
pub fn option_set_reload_mode(&mut self, enable: bool) {
- self.process.aux.config.reload_mode = if enable {1} else {0};
+ self.process.aux_buffer_mut().config.reload_mode = if enable {1} else {0};
}
pub fn option_set_redqueen_mode(&mut self, enable: bool) {
- self.process.aux.config.redqueen_mode = if enable {1} else {0};
+ self.process.aux_buffer_mut().config.redqueen_mode = if enable {1} else {0};
}
pub fn option_set_trace_mode(&mut self, enable: bool) {
- self.process.aux.config.trace_mode = if enable {1} else {0};
+ self.process.aux_buffer_mut().config.trace_mode = if enable {1} else {0};
}
pub fn option_set_delete_incremental_snapshot(&mut self, enable: bool) {
- self.process.aux.config.discard_tmp_snapshot = if enable {1} else {0};
+ self.process.aux_buffer_mut().config.discard_tmp_snapshot = if enable {1} else {0};
}
pub fn option_set_timeout(&mut self, timeout_sec: u8, timeout_usec: u32) {
- self.process.aux.config.timeout_sec = timeout_sec;
- self.process.aux.config.timeout_usec = timeout_usec;
+ self.process.aux_buffer_mut().config.timeout_sec = timeout_sec;
+ self.process.aux_buffer_mut().config.timeout_usec = timeout_usec;
}
pub fn option_apply(&mut self) {
- self.process.aux.config.changed = 1;
+ self.process.aux_buffer_mut().config.changed = 1;
}
pub fn aux_misc(&self) -> Vec{
- self.process.aux.misc.as_slice().to_vec()
+ self.process.aux_buffer().misc.as_slice().to_vec()
}
pub fn aux_tmp_snapshot_created(&self) -> bool {
- self.process.aux.result.tmp_snapshot_created != 0
+ self.process.aux_buffer().result.tmp_snapshot_created != 0
}
pub fn aux_string(&self) -> String {
- let len = self.process.aux.misc.len;
- String::from_utf8_lossy(&self.process.aux.misc.data[0..len as usize]).to_string()
+ let len = self.process.aux_buffer().misc.len;
+ String::from_utf8_lossy(&self.process.aux_buffer().misc.data[0..len as usize]).to_string()
}
pub fn exec(&mut self) -> NyxReturnValue {
match self.process.send_payload(){
Err(_) => NyxReturnValue::IoError,
Ok(_) => {
- match self.process.aux.result.exec_result_code {
+ match self.process.aux_buffer().result.exec_result_code {
NYX_SUCCESS => NyxReturnValue::Normal,
NYX_CRASH => NyxReturnValue::Crash,
NYX_TIMEOUT => NyxReturnValue::Timeout,
@@ -307,4 +355,15 @@ impl NyxProcess {
pub fn set_input(&mut self, buffer: &[u8], size: u32) {
self.set_input_ptr(buffer.as_ptr(), size);
}
+
+ pub fn set_hprintf_fd(&mut self, fd: i32) {
+
+ /* sanitiy check to prevent invalid file descriptors via F_GETFD */
+ unsafe {
+ assert!(fcntl(fd, libc::F_GETFD) != -1);
+ };
+
+ self.process.set_hprintf_fd(fd);
+ }
+
}
diff --git a/libnyx/test.c b/libnyx/test.c
index ab3b048..a00d19a 100644
--- a/libnyx/test.c
+++ b/libnyx/test.c
@@ -1,9 +1,14 @@
+/* Simple test program to test the C-API */
#include
#include "libnyx.h"
#include
#include
+
+#include
+#include
+#include
#ifndef HEXDUMP_COLS
#define HEXDUMP_COLS 16
@@ -11,90 +16,101 @@
void hexdump(void *mem, unsigned int len)
{
- unsigned int i, j;
-
- for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
+ unsigned int i, j;
+
+ for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
+ {
+ /* print offset */
+ if(i % HEXDUMP_COLS == 0)
{
- /* print offset */
- if(i % HEXDUMP_COLS == 0)
- {
- printf("0x%06x: ", i);
- }
-
- /* print hex data */
- if(i < len)
- {
- printf("%02x ", 0xFF & ((char*)mem)[i]);
- }
- else /* end of block, just aligning for ASCII dump */
- {
- printf(" ");
- }
-
- /* print ASCII dump */
- if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
- {
- for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
- {
- if(j >= len) /* end of block, not really printing */
- {
- putchar(' ');
- }
- else if(isprint(((char*)mem)[j])) /* printable char */
- {
- putchar(0xFF & ((char*)mem)[j]);
- }
- else /* other char */
- {
- putchar('.');
- }
- }
- putchar('\n');
- }
+ printf("0x%06x: ", i);
}
+
+ /* print hex data */
+ if(i < len)
+ {
+ printf("%02x ", 0xFF & ((char*)mem)[i]);
+ }
+ else /* end of block, just aligning for ASCII dump */
+ {
+ printf(" ");
+ }
+
+ /* print ASCII dump */
+ if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
+ {
+ for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
+ {
+ if(j >= len) /* end of block, not really printing */
+ {
+ putchar(' ');
+ }
+ else if(isprint(((char*)mem)[j])) /* printable char */
+ {
+ putchar(0xFF & ((char*)mem)[j]);
+ }
+ else /* other char */
+ {
+ putchar('.');
+ }
+ }
+ putchar('\n');
+ }
+ }
}
int main(int argc, char** argv){
- printf("YO\n");
+
+ void* aux_buffer;
- void* aux_buffer;
+ void* nyx_config = nyx_config_load("/tmp/nyx_libxml2/");
- void* ptr = nyx_new("/tmp/nyx_bash/");
+ //nyx_config_debug(nyx_config);
- printf("QEMU Rust Object Pointer: %p\n", ptr);
+ nyx_config_set_workdir_path(nyx_config, "/tmp/wdir");
+ nyx_config_set_input_buffer_size(nyx_config, 0x2000);
- void* aux = nyx_get_aux_buffer(ptr);
+ int fd = open("/tmp/nyx_test_output.log", O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ printf("Log output FD: %d\n", fd);
+ nyx_config_set_hprintf_fd(nyx_config, fd);
- printf("QEMU Rust Aux Pointer: %p\n", aux);
+ nyx_config_set_process_role(nyx_config, StandAlone);
+
+ //nyx_config_set_reuse_snapshot_path(nyx_config, "/tmp/wdir/snapshot/");
- hexdump(aux, 16);
+ nyx_config_print(nyx_config);
+ nyx_config_debug(nyx_config);
- void* payload = nyx_get_payload_buffer(ptr);
+ void* nyx_runner = nyx_new(nyx_config, 0);
- nyx_set_afl_input(ptr, "HALLO", 5);
+ printf("Nyx runner object pointer: %p\n", nyx_runner);
+ void* aux = nyx_get_aux_buffer(nyx_runner);
- printf("QEMU Rust Payload Pointer: %p\n", payload);
+ printf("QEMU rust aux pointer: %p\n", aux);
+ hexdump(aux, 16);
- nyx_option_set_reload_mode(ptr, true);
- nyx_option_apply(ptr);
+ void* nyx_input = nyx_get_input_buffer(nyx_runner);
- hexdump(payload, 16);
+ nyx_set_afl_input(nyx_runner, "INPUT", 5);
+ printf("QEMU Rust Payload Pointer: %p\n", nyx_input);
- printf("About to run init\n");
- printf("INIT -> %d\n", nyx_exec(ptr));
- printf("Init done\n");
+ nyx_option_set_reload_mode(nyx_runner, true);
+ nyx_option_apply(nyx_runner);
+ hexdump(nyx_input, 16);
- for(int i = 0; i < 32; i++){
- nyx_set_afl_input(ptr, "HALLO", 5);
- printf("nyx_exec -> %d\n", nyx_exec(ptr));
- //nyx_print_aux_buffer(ptr);
- }
-
- nyx_shutdown(ptr);
+ printf("About to run init\n");
+ printf("INIT -> %d\n", nyx_exec(nyx_runner));
+ printf("Init done\n");
+ for(int i = 0; i < 4; i++){
+ nyx_set_afl_input(nyx_runner, "INPUT", 5);
+ printf("nyx_exec -> %d\n", nyx_exec(nyx_runner));
+ nyx_print_aux_buffer(nyx_runner);
+ }
+ nyx_shutdown(nyx_runner);
}