diff --git a/config/Cargo.toml b/config/Cargo.toml index 1ab9280..d0225d4 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -9,4 +9,5 @@ edition = "2018" [dependencies] serde ="1.0.104" serde_derive ="1.0.104" -ron="0.6.2" \ No newline at end of file +ron="0.6.2" +libc = "0.2" \ No newline at end of file diff --git a/config/src/config.rs b/config/src/config.rs index ec6f4bc..e2d1767 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -5,6 +5,8 @@ use std::fs::File; use std::path::{Path}; use crate::loader::*; +use libc::fcntl; + fn into_absolute_path(path_to_sharedir: &str, path_to_file: String) -> String { let path_to_default_config = Path::new(&path_to_file); @@ -128,9 +130,6 @@ pub struct FuzzerConfig { pub input_buffer_size: usize, pub mem_limit: usize, pub time_limit: Duration, - pub threads: usize, - pub thread_id: usize, - pub cpu_pin_start_at: usize, pub seed_path: Option, pub dict: Vec>, pub snapshot_placement: SnapshotPlacement, @@ -158,9 +157,6 @@ impl FuzzerConfig{ input_buffer_size: config.input_buffer_size, mem_limit: config.mem_limit.or(default.mem_limit).expect("no mem_limit specified"), time_limit: config.time_limit.or(default.time_limit).expect("no time_limit specified"), - threads: config.threads.or(default.threads).expect("no threads specified"), - thread_id: config.thread_id.or(default.thread_id).expect("no thread_id specified"), - cpu_pin_start_at: config.cpu_pin_start_at.or(default.cpu_pin_start_at).expect("no cpu_pin_start_at specified"), seed_path: seed_path_value, dict: config.dict.or(default.dict).expect("no dict specified"), snapshot_placement: config.snapshot_placement.or(default.snapshot_placement).expect("no snapshot_placement specified"), @@ -178,10 +174,113 @@ impl FuzzerConfig{ } } +#[derive(Clone, Debug)] +pub enum QemuNyxRole { + /* Standalone mode, snapshot is kept in memory and not serialized. */ + StandAlone, + + /* Serialize the VM snapshot after the root snapshot has been created. + * The serialized snapshot will be stored in the workdir and the snapshot + * will later be used by the child processes. */ + Parent, + + /* Wait for the snapshot to be created by the parent process and + * deserialize it from the workdir. This way all child processes can + * mmap() the snapshot files and access the snapshot directly via shared memory. + * Consequently, this will result in a much lower memory usage compared to spawning + * multiple StandAlone-type instances. */ + Child, +} + +#[derive(Clone, Debug)] +/* runtime specific configuration */ +pub struct RuntimeConfig { + /* Configurable option to redirect hprintf to a file descriptor. + * If None, hprintf will be redirected to stdout via println!(). + */ + hprintf_fd: Option, + + /* Configurable option to specify the role of the process. + * If StandAlone, the process will not serialize the snapshot and keep everything in memory. + * If Parent, the process will create a snapshot and serialize it. + * If Child, the process will wait for the parent to create a snapshot and deserialize it. */ + process_role: QemuNyxRole, + + /* Configurable option to reuse a snapshot from a previous run (useful to avoid VM bootstrapping). */ + reuse_snapshot_path: Option, + + /* enable advanced VM debug mode (such as spawning a VNC server per VM) */ + debug_mode: bool, + + /* worker_id of the current QEMU Nyx instance */ + worker_id: usize, +} + +impl RuntimeConfig{ + pub fn new() -> Self { + Self{ + hprintf_fd: None, + process_role: QemuNyxRole::StandAlone, + reuse_snapshot_path: None, + debug_mode: false, + worker_id: 0, + } + } + + pub fn hprintf_fd(&self) -> Option { + self.hprintf_fd + } + + pub fn process_role(&self) -> &QemuNyxRole { + &self.process_role + } + + pub fn set_hpintf_fd(&mut self, fd: i32){ + /* sanitiy check to prevent invalid file descriptors via F_GETFD */ + unsafe { + /* TODO: return error instead of panicking */ + assert!(fcntl(fd, libc::F_GETFD) != -1); + }; + + self.hprintf_fd = Some(fd); + } + + pub fn set_process_role(&mut self, role: QemuNyxRole){ + self.process_role = role; + } + + pub fn reuse_root_snapshot_path(&self) -> Option { + self.reuse_snapshot_path.clone() + } + + pub fn set_reuse_snapshot_path(&mut self, path: String){ + let path = Path::new(&path).canonicalize().unwrap().to_str().unwrap().to_string(); + self.reuse_snapshot_path = Some(path); + } + + pub fn debug_mode(&self) -> bool { + self.debug_mode + } + + pub fn set_debug_mode(&mut self, debug_mode: bool){ + self.debug_mode = debug_mode; + } + + pub fn worker_id(&self) -> usize { + self.worker_id + } + + pub fn set_worker_id(&mut self, thread_id: usize){ + self.worker_id = thread_id; + } + +} + #[derive(Clone, Debug)] pub struct Config { pub runner: FuzzRunnerConfig, pub fuzz: FuzzerConfig, + pub runtime: RuntimeConfig, } impl Config{ @@ -189,6 +288,7 @@ impl Config{ Self{ runner: FuzzRunnerConfig::new_from_loader(&default_config_folder, default.runner, config.runner), fuzz: FuzzerConfig::new_from_loader(&sharedir, default.fuzz, config.fuzz), + runtime: RuntimeConfig::new(), } } diff --git a/config/src/lib.rs b/config/src/lib.rs index 225983a..7c8f15b 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -1,6 +1,7 @@ extern crate serde; extern crate serde_derive; extern crate ron; +extern crate libc; mod loader; mod config; diff --git a/config/src/loader.rs b/config/src/loader.rs index 98b91cb..51f7c3a 100644 --- a/config/src/loader.rs +++ b/config/src/loader.rs @@ -59,9 +59,6 @@ pub struct FuzzerConfigLoader { pub mem_limit: Option, pub time_limit: Option, pub target_binary: Option, - pub threads: Option, - pub thread_id: Option, - pub cpu_pin_start_at: Option, pub seed_path: Option, pub dict: Option>>, pub snapshot_placement: Option,