This commit is contained in:
parent
27d379486b
commit
119077b190
@ -22,7 +22,7 @@ impl ExitReason {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn is_normal(&self) -> bool{
|
||||
pub fn is_normal(&self) -> bool {
|
||||
use ExitReason::*;
|
||||
match self {
|
||||
Normal(_) => return true,
|
||||
@ -30,7 +30,7 @@ impl ExitReason {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str{
|
||||
pub fn name(&self) -> &str {
|
||||
use ExitReason::*;
|
||||
match self {
|
||||
Normal(_) => return "normal",
|
||||
|
@ -1,11 +1,10 @@
|
||||
extern crate byteorder;
|
||||
extern crate config;
|
||||
extern crate glob;
|
||||
extern crate nix;
|
||||
extern crate serde_derive;
|
||||
extern crate snafu;
|
||||
extern crate timeout_readwrite;
|
||||
extern crate config;
|
||||
|
||||
|
||||
pub mod exitreason;
|
||||
pub use exitreason::ExitReason;
|
||||
@ -14,4 +13,3 @@ pub use exitreason::ExitReason;
|
||||
|
||||
pub mod nyx;
|
||||
pub use nyx::QemuProcess;
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
|
||||
use nix::sys::mman::*;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
use std::fmt;
|
||||
//use std::sync::atomic::compiler_fence;
|
||||
//use std::sync::atomic::Ordering;
|
||||
|
||||
use crate::nyx::mem_barrier::mem_barrier;
|
||||
|
||||
|
||||
use derivative::Derivative;
|
||||
|
||||
/* various Nyx exec codes (aux_buffer.result.exec_result_code) */
|
||||
@ -19,7 +17,6 @@ pub const NYX_TIMEOUT: u8 = 3;
|
||||
pub const NYX_INPUT_WRITE: u8 = 4;
|
||||
pub const NYX_ABORT: u8 = 5;
|
||||
|
||||
|
||||
pub const AUX_BUFFER_SIZE: usize = 4096;
|
||||
|
||||
const AUX_MAGIC: u64 = 0x54502d554d4551_u64;
|
||||
@ -50,11 +47,9 @@ pub struct AuxBuffer {
|
||||
}
|
||||
|
||||
impl AuxBuffer {
|
||||
|
||||
pub fn new_readonly(file: File, read_only: bool, size: usize) -> Self {
|
||||
|
||||
let mut prot = ProtFlags::PROT_READ;
|
||||
if !read_only{
|
||||
if !read_only {
|
||||
prot |= ProtFlags::PROT_WRITE;
|
||||
}
|
||||
|
||||
@ -62,7 +57,15 @@ impl AuxBuffer {
|
||||
let null_addr = std::num::NonZeroUsize::new(0);
|
||||
let aux_buffer_alloc_size = std::num::NonZeroUsize::new(size).unwrap();
|
||||
unsafe {
|
||||
let ptr = mmap(null_addr, aux_buffer_alloc_size, prot, flags, file.into_raw_fd(), 0).unwrap();
|
||||
let ptr = mmap(
|
||||
null_addr,
|
||||
aux_buffer_alloc_size,
|
||||
prot,
|
||||
flags,
|
||||
file.into_raw_fd(),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let header = (ptr.add(HEADER_OFFSET) as *mut auxilary_buffer_header_s)
|
||||
.as_mut()
|
||||
.unwrap();
|
||||
@ -99,19 +102,33 @@ impl AuxBuffer {
|
||||
|
||||
/* This is a somewhat hacky way of returning a slice of the total misc area */
|
||||
pub fn misc_slice(&self) -> &[u8] {
|
||||
return unsafe { std::slice::from_raw_parts(self.misc as *const auxilary_buffer_misc_s as *const u8, self.size - MISC_OFFSET) };
|
||||
return unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
self.misc as *const auxilary_buffer_misc_s as *const u8,
|
||||
self.size - MISC_OFFSET,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/* same... */
|
||||
pub fn misc_data_slice(&self) -> &[u8] {
|
||||
return unsafe { std::slice::from_raw_parts((self.misc as *const auxilary_buffer_misc_s as *const u8).offset(std::mem::size_of::<u16>() as isize), self.size - MISC_OFFSET - std::mem::size_of::<u16>()) };
|
||||
return unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(self.misc as *const auxilary_buffer_misc_s as *const u8)
|
||||
.offset(std::mem::size_of::<u16>() as isize),
|
||||
self.size - MISC_OFFSET - std::mem::size_of::<u16>(),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
pub fn validate_header(&self) -> Result<(), String> {
|
||||
mem_barrier();
|
||||
let mgc = self.header.magic;
|
||||
if mgc != AUX_MAGIC {
|
||||
return Err(format!("aux buffer magic mismatch {} != {}...\n[!] Probably the AUX buffer is corrupted?!", AUX_MAGIC, mgc));
|
||||
return Err(format!(
|
||||
"aux buffer magic mismatch {} != {}...\n[!] Probably the AUX buffer is corrupted?!",
|
||||
AUX_MAGIC, mgc
|
||||
));
|
||||
}
|
||||
let version = self.header.version;
|
||||
if version != QEMU_PT_VERSION {
|
||||
@ -141,7 +158,6 @@ pub struct auxilary_buffer_cap_s {
|
||||
|
||||
pub agent_input_buffer_size: u32, /* agent requests a custom input buffer size (if the size is 0, the minimum buffer size is used) */
|
||||
pub agent_coverage_bitmap_size: u32, /* agent requests a custom coverage bitmap size (if the size is 0, the minimum buffer size is used) */
|
||||
|
||||
}
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed(1))]
|
||||
@ -186,7 +202,7 @@ pub struct auxilary_buffer_result_s {
|
||||
pub pt_overflow: u8,
|
||||
pub page_not_found: u8,
|
||||
pub tmp_snapshot_created: u8,
|
||||
#[derivative(Debug="ignore")]
|
||||
#[derivative(Debug = "ignore")]
|
||||
pub padding_3: u8,
|
||||
|
||||
pub page_not_found_addr: u64,
|
||||
@ -195,13 +211,12 @@ pub struct auxilary_buffer_result_s {
|
||||
pub bb_coverage: u32,
|
||||
pub runtime_usec: u32,
|
||||
pub runtime_sec: u32,
|
||||
|
||||
}
|
||||
|
||||
#[repr(C, packed(1))]
|
||||
pub struct auxilary_buffer_misc_s {
|
||||
pub len: u16,
|
||||
pub data: [u8;MISC_SIZE-2],
|
||||
pub data: [u8; MISC_SIZE - 2],
|
||||
}
|
||||
|
||||
fn inspect_bytes(bs: &[u8]) -> String {
|
||||
@ -216,12 +231,12 @@ fn inspect_bytes(bs: &[u8]) -> String {
|
||||
visible
|
||||
}
|
||||
|
||||
impl auxilary_buffer_misc_s{
|
||||
pub fn as_slice(&self) -> &[u8]{
|
||||
impl auxilary_buffer_misc_s {
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
assert!(self.len as usize <= self.data.len());
|
||||
return &self.data[0..self.len as usize];
|
||||
}
|
||||
pub fn as_string(&self) -> String{
|
||||
pub fn as_string(&self) -> String {
|
||||
inspect_bytes(self.as_slice())
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed(1))]
|
||||
pub struct InterpreterData{
|
||||
pub executed_opcode_num: u32
|
||||
pub struct InterpreterData {
|
||||
pub executed_opcode_num: u32,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct IjonData {
|
||||
pub max_data: [u64;256],
|
||||
pub max_data: [u64; 256],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C, packed(1))]
|
||||
pub struct SharedFeedbackData{
|
||||
pub struct SharedFeedbackData {
|
||||
pub interpreter: InterpreterData,
|
||||
pad: [u8; 0x1000/2-std::mem::size_of::<InterpreterData>()],
|
||||
pad: [u8; 0x1000 / 2 - std::mem::size_of::<InterpreterData>()],
|
||||
pub ijon: IjonData,
|
||||
}
|
||||
|
||||
@ -22,8 +22,8 @@ pub struct FeedbackBuffer {
|
||||
pub shared: &'static mut SharedFeedbackData,
|
||||
}
|
||||
|
||||
impl FeedbackBuffer{
|
||||
pub fn new(shared: &'static mut SharedFeedbackData) -> Self{
|
||||
Self{shared}
|
||||
impl FeedbackBuffer {
|
||||
pub fn new(shared: &'static mut SharedFeedbackData) -> Self {
|
||||
Self { shared }
|
||||
}
|
||||
}
|
@ -11,21 +11,21 @@ use std::path::PathBuf;
|
||||
|
||||
extern crate config;
|
||||
|
||||
fn into_absolute_path(sharedir: &str) -> String{
|
||||
|
||||
fn into_absolute_path(sharedir: &str) -> String {
|
||||
let srcdir = PathBuf::from(&sharedir);
|
||||
|
||||
if srcdir.is_relative(){
|
||||
return fs::canonicalize(&srcdir).unwrap().to_str().unwrap().to_string();
|
||||
}
|
||||
else{
|
||||
if srcdir.is_relative() {
|
||||
return fs::canonicalize(&srcdir)
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
} else {
|
||||
return sharedir.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn qemu_process_new(sharedir: String, cfg: &config::Config) -> Result<QemuProcess, String> {
|
||||
|
||||
|
||||
let qemu_params = params::QemuParams::new(into_absolute_path(&sharedir), cfg);
|
||||
return qemu_process::QemuProcess::new(qemu_params);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
config::{Config, FuzzRunnerConfig, QemuNyxRole},
|
||||
QemuProcess,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use crate::{config::{Config, FuzzRunnerConfig, QemuNyxRole}, QemuProcess};
|
||||
|
||||
pub struct QemuParams {
|
||||
pub cmd: Vec<String>,
|
||||
@ -20,9 +23,7 @@ pub struct QemuParams {
|
||||
}
|
||||
|
||||
impl QemuParams {
|
||||
|
||||
pub fn new(sharedir: String, fuzzer_config: &Config) -> QemuParams {
|
||||
|
||||
let mut cmd = vec![];
|
||||
let qemu_id = fuzzer_config.runtime.worker_id();
|
||||
|
||||
@ -33,7 +34,7 @@ impl QemuParams {
|
||||
let qemu_aux_buffer_filename = format!("{}/aux_buffer_{}", workdir, qemu_id);
|
||||
let control_filename = format!("{}/interface_{}", workdir, qemu_id);
|
||||
|
||||
match fuzzer_config.runner.clone(){
|
||||
match fuzzer_config.runner.clone() {
|
||||
FuzzRunnerConfig::QemuKernel(x) => {
|
||||
cmd.push(x.qemu_binary.to_string());
|
||||
cmd.push("-kernel".to_string());
|
||||
@ -44,21 +45,21 @@ impl QemuParams {
|
||||
|
||||
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={},index=0,media=disk", x.hda.to_string()));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/* generic QEMU-Nyx parameters */
|
||||
if !debug{
|
||||
if !debug {
|
||||
cmd.push("-display".to_string());
|
||||
cmd.push("none".to_string());
|
||||
} else {
|
||||
cmd.push("-vnc".to_string());
|
||||
cmd.push(format!(":{}",qemu_id));
|
||||
cmd.push(format!(":{}", qemu_id));
|
||||
}
|
||||
|
||||
cmd.push("-serial".to_string());
|
||||
@ -95,23 +96,32 @@ impl QemuParams {
|
||||
cmd.push("-device".to_string());
|
||||
let mut nyx_ops = format!("nyx,chardev=nyx_interface");
|
||||
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!(
|
||||
",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={}", sharedir);
|
||||
nyx_ops += &format!(",aux_buffer_size={}", fuzzer_config.runtime.aux_buffer_size());
|
||||
nyx_ops += &format!(
|
||||
",aux_buffer_size={}",
|
||||
fuzzer_config.runtime.aux_buffer_size()
|
||||
);
|
||||
nyx_ops += &format!(",dump_pt_trace={}", true);
|
||||
|
||||
let mut i = 0;
|
||||
for filter in fuzzer_config.fuzz.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 fuzzer_config.fuzz.cow_primary_size.is_some(){
|
||||
nyx_ops += &format!(",cow_primary_size={}", fuzzer_config.fuzz.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);
|
||||
@ -131,48 +141,60 @@ impl QemuParams {
|
||||
|
||||
if fuzzer_config.runtime.reuse_root_snapshot_path().is_some() {
|
||||
cmd.push("-fast_vm_reload".to_string());
|
||||
cmd.push(format!("path={},load=on", fuzzer_config.runtime.reuse_root_snapshot_path().unwrap()));
|
||||
}
|
||||
else{
|
||||
match fuzzer_config.runner.clone(){
|
||||
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 => {
|
||||
cmd.push("-fast_vm_reload".to_string());
|
||||
cmd.push(format!("path={}/snapshot/,load=off,skip_serialization=on", workdir));
|
||||
},
|
||||
cmd.push(format!(
|
||||
"path={}/snapshot/,load=off,skip_serialization=on",
|
||||
workdir
|
||||
));
|
||||
}
|
||||
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());
|
||||
if x.presnapshot.is_empty() {
|
||||
cmd.push(format!("path={}/snapshot/,load=off,skip_serialization=on", workdir));
|
||||
cmd.push(format!(
|
||||
"path={}/snapshot/,load=off,skip_serialization=on",
|
||||
workdir
|
||||
));
|
||||
} else {
|
||||
cmd.push(format!("path={}/snapshot/,load=off,pre_path={},skip_serialization=on", workdir, x.presnapshot));
|
||||
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));
|
||||
},
|
||||
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", workdir));
|
||||
},
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,13 +202,12 @@ impl QemuParams {
|
||||
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,
|
||||
@ -195,7 +216,7 @@ impl QemuParams {
|
||||
qemu_id,
|
||||
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{
|
||||
dump_python_code_for_inputs: match fuzzer_config.fuzz.dump_python_code_for_inputs {
|
||||
None => false,
|
||||
Some(x) => x,
|
||||
},
|
||||
@ -203,8 +224,7 @@ impl QemuParams {
|
||||
cow_primary_size: fuzzer_config.fuzz.cow_primary_size,
|
||||
hprintf_fd: fuzzer_config.runtime.hprintf_fd(),
|
||||
aux_buffer_size: fuzzer_config.runtime.aux_buffer_size(),
|
||||
time_limit: fuzzer_config.fuzz.time_limit
|
||||
time_limit: fuzzer_config.fuzz.time_limit,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
use std::os::unix::prelude::FromRawFd;
|
||||
use std::path::PathBuf;
|
||||
use fs4::FileExt;
|
||||
use nix::sys::mman::*;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::os::unix::fs::symlink;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::io::IntoRawFd;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::os::unix::prelude::FromRawFd;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use std::process::Child;
|
||||
use std::process::Command;
|
||||
use std::{thread, time};
|
||||
use std::process;
|
||||
use fs4::FileExt;
|
||||
|
||||
use nix::unistd::gettid;
|
||||
|
||||
@ -24,16 +24,16 @@ extern crate colored; // not needed in Rust 2018
|
||||
|
||||
use colored::*;
|
||||
|
||||
|
||||
use crate::nyx::aux_buffer::AuxBuffer;
|
||||
use crate::nyx::aux_buffer::{NYX_SUCCESS, NYX_CRASH, NYX_HPRINTF, NYX_TIMEOUT, NYX_ABORT, NYX_INPUT_WRITE};
|
||||
use crate::nyx::aux_buffer::{
|
||||
NYX_ABORT, NYX_CRASH, NYX_HPRINTF, NYX_INPUT_WRITE, NYX_SUCCESS, NYX_TIMEOUT,
|
||||
};
|
||||
|
||||
use crate::nyx::ijon_data::{SharedFeedbackData, FeedbackBuffer};
|
||||
use crate::nyx::ijon_data::{FeedbackBuffer, SharedFeedbackData};
|
||||
use crate::nyx::mem_barrier::mem_barrier;
|
||||
use crate::nyx::params::QemuParams;
|
||||
|
||||
pub struct QemuProcess {
|
||||
|
||||
process: Child,
|
||||
|
||||
/* ptr to the aux buffer */
|
||||
@ -54,18 +54,18 @@ pub struct QemuProcess {
|
||||
hprintf_file: Option<File>,
|
||||
}
|
||||
|
||||
fn execute_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
|
||||
fn execute_qemu(ctrl: &mut UnixStream) -> io::Result<()> {
|
||||
ctrl.write_all(&[120_u8])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
|
||||
fn wait_qemu(ctrl: &mut UnixStream) -> io::Result<()> {
|
||||
let mut buf = [0];
|
||||
ctrl.read_exact(&mut buf)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_qemu(ctrl: &mut UnixStream) -> io::Result<()>{
|
||||
fn run_qemu(ctrl: &mut UnixStream) -> io::Result<()> {
|
||||
execute_qemu(ctrl)?;
|
||||
wait_qemu(ctrl)?;
|
||||
Ok(())
|
||||
@ -96,11 +96,10 @@ fn make_shared_ijon_data(file: File, size: usize) -> FeedbackBuffer {
|
||||
}
|
||||
|
||||
impl QemuProcess {
|
||||
|
||||
pub fn new(params: QemuParams) -> Result<QemuProcess, String> {
|
||||
Self::prepare_redqueen_workdir(¶ms.workdir, params.qemu_id);
|
||||
|
||||
if params.qemu_id == 0{
|
||||
if params.qemu_id == 0 {
|
||||
println!("[!] libnyx: spawning qemu with:\n {}", params.cmd.join(" "));
|
||||
}
|
||||
|
||||
@ -116,8 +115,7 @@ impl QemuProcess {
|
||||
.open(&shm_work_dir_path)
|
||||
.expect("couldn't open bitmap file");
|
||||
|
||||
|
||||
if Path::new(&format!("{}/bitmap_{}", params.workdir, params.qemu_id)).exists(){
|
||||
if Path::new(&format!("{}/bitmap_{}", params.workdir, params.qemu_id)).exists() {
|
||||
fs::remove_file(format!("{}/bitmap_{}", params.workdir, params.qemu_id)).unwrap();
|
||||
}
|
||||
|
||||
@ -137,8 +135,7 @@ impl QemuProcess {
|
||||
.open(&shm_work_dir_path)
|
||||
.expect("couldn't open bitmap file");
|
||||
|
||||
|
||||
if Path::new(&format!("{}/ijon_{}", params.workdir, params.qemu_id)).exists(){
|
||||
if Path::new(&format!("{}/ijon_{}", params.workdir, params.qemu_id)).exists() {
|
||||
fs::remove_file(format!("{}/ijon_{}", params.workdir, params.qemu_id)).unwrap();
|
||||
}
|
||||
|
||||
@ -158,7 +155,7 @@ impl QemuProcess {
|
||||
.open(&shm_work_dir_path)
|
||||
.expect("couldn't open payload file");
|
||||
|
||||
if Path::new(&format!("{}/payload_{}", params.workdir, params.qemu_id)).exists(){
|
||||
if Path::new(&format!("{}/payload_{}", params.workdir, params.qemu_id)).exists() {
|
||||
fs::remove_file(format!("{}/payload_{}", params.workdir, params.qemu_id)).unwrap();
|
||||
}
|
||||
|
||||
@ -178,14 +175,13 @@ 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);
|
||||
|
||||
let mut child = if params.dump_python_code_for_inputs{
|
||||
let mut child = if params.dump_python_code_for_inputs {
|
||||
Command::new(¶ms.cmd[0])
|
||||
.args(¶ms.cmd[1..])
|
||||
.env("DUMP_PAYLOAD_MODE", "TRUE")
|
||||
.spawn()
|
||||
.expect("failed to execute process")
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
Command::new(¶ms.cmd[0])
|
||||
.args(¶ms.cmd[1..])
|
||||
.spawn()
|
||||
@ -195,9 +191,7 @@ impl QemuProcess {
|
||||
let mut control = loop {
|
||||
match UnixStream::connect(¶ms.control_filename) {
|
||||
Ok(stream) => break stream,
|
||||
_ => {
|
||||
thread::sleep(time::Duration::from_millis(1))
|
||||
},
|
||||
_ => thread::sleep(time::Duration::from_millis(1)),
|
||||
}
|
||||
};
|
||||
|
||||
@ -215,15 +209,15 @@ impl QemuProcess {
|
||||
AuxBuffer::new(aux_shm_f, params.aux_buffer_size)
|
||||
};
|
||||
|
||||
match 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{
|
||||
Ok(_) => {}
|
||||
}
|
||||
if params.write_protected_input_buffer {
|
||||
if params.qemu_id == 0 {
|
||||
println!("[!] libnyx: input buffer is write protected");
|
||||
}
|
||||
@ -237,15 +231,20 @@ impl QemuProcess {
|
||||
};
|
||||
|
||||
loop {
|
||||
|
||||
match aux_buffer.result.exec_result_code {
|
||||
NYX_HPRINTF => {
|
||||
let len = aux_buffer.misc.len;
|
||||
QemuProcess::output_hprintf(&mut hprintf_file, &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;
|
||||
let msg = format!("agent abort() -> \n\t{}", String::from_utf8_lossy(&aux_buffer.misc.data[0..len as usize]).red());
|
||||
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();
|
||||
@ -253,7 +252,7 @@ impl QemuProcess {
|
||||
|
||||
return Err(msg);
|
||||
}
|
||||
NYX_SUCCESS => {},
|
||||
NYX_SUCCESS => {}
|
||||
x => {
|
||||
panic!(" -> unkown type ? {}", x);
|
||||
}
|
||||
@ -262,7 +261,7 @@ impl QemuProcess {
|
||||
if aux_buffer.result.state == 3 {
|
||||
break;
|
||||
}
|
||||
if run_qemu(&mut control).is_err(){
|
||||
if run_qemu(&mut control).is_err() {
|
||||
return Err(format!("failed to establish fuzzing loop..."));
|
||||
}
|
||||
}
|
||||
@ -272,17 +271,23 @@ impl QemuProcess {
|
||||
if aux_buffer.cap.agent_coverage_bitmap_size != 0 {
|
||||
//let file_len = bitmap_shm_f.metadata().unwrap().len();
|
||||
bitmap_size = aux_buffer.cap.agent_coverage_bitmap_size as usize;
|
||||
if aux_buffer.cap.agent_coverage_bitmap_size as usize > bitmap_shared.len(){
|
||||
if aux_buffer.cap.agent_coverage_bitmap_size as usize > bitmap_shared.len() {
|
||||
//println!("[!] libnyx: agent requests a differnt coverage bitmap size: {:x} (current: {:x})", aux_buffer.cap.agent_coverage_bitmap_size as u32, file_len);
|
||||
bitmap_shared = make_shared_data(&bitmap_shm_f, aux_buffer.cap.agent_coverage_bitmap_size as usize);
|
||||
bitmap_shared = make_shared_data(
|
||||
&bitmap_shm_f,
|
||||
aux_buffer.cap.agent_coverage_bitmap_size as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut input_buffer_size = params.payload_size as usize;
|
||||
if aux_buffer.cap.agent_input_buffer_size != 0 {
|
||||
input_buffer_size = aux_buffer.cap.agent_input_buffer_size as usize;
|
||||
if aux_buffer.cap.agent_input_buffer_size as usize > payload_shared.len(){
|
||||
payload_shared = make_shared_data(&payload_shm_f, aux_buffer.cap.agent_input_buffer_size as usize);
|
||||
if aux_buffer.cap.agent_input_buffer_size as usize > payload_shared.len() {
|
||||
payload_shared = make_shared_data(
|
||||
&payload_shm_f,
|
||||
aux_buffer.cap.agent_input_buffer_size as usize,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,37 +321,37 @@ impl QemuProcess {
|
||||
});
|
||||
}
|
||||
|
||||
fn output_hprintf(hprintf_file: &mut Option<File>, msg: &str){
|
||||
fn output_hprintf(hprintf_file: &mut Option<File>, 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{
|
||||
pub fn aux_buffer(&self) -> &AuxBuffer {
|
||||
&self.aux
|
||||
}
|
||||
|
||||
pub fn aux_buffer_mut(&mut self) -> &mut AuxBuffer{
|
||||
pub fn aux_buffer_mut(&mut self) -> &mut AuxBuffer {
|
||||
&mut self.aux
|
||||
}
|
||||
|
||||
pub fn set_hprintf_fd(&mut self, fd: i32){
|
||||
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<()>{
|
||||
pub fn send_payload(&mut self) -> io::Result<()> {
|
||||
let mut old_address: u64 = 0;
|
||||
|
||||
loop {
|
||||
mem_barrier();
|
||||
match run_qemu(&mut self.ctrl) {
|
||||
Err(x) => return Err(x),
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
}
|
||||
mem_barrier();
|
||||
|
||||
@ -362,13 +367,12 @@ impl QemuProcess {
|
||||
mem_barrier();
|
||||
match run_qemu(&mut self.ctrl) {
|
||||
Err(x) => return Err(x),
|
||||
Ok(_) => {},
|
||||
Ok(_) => {}
|
||||
}
|
||||
mem_barrier();
|
||||
|
||||
continue;
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
println!("libnyx: cannot dump missing page -> {:x}", v);
|
||||
}
|
||||
}
|
||||
@ -376,17 +380,24 @@ impl QemuProcess {
|
||||
match self.aux.result.exec_result_code {
|
||||
NYX_HPRINTF => {
|
||||
let len = self.aux.misc.len;
|
||||
QemuProcess::output_hprintf(&mut self.hprintf_file, &String::from_utf8_lossy(&self.aux.misc_data_slice()[0..len as usize]).yellow());
|
||||
QemuProcess::output_hprintf(
|
||||
&mut self.hprintf_file,
|
||||
&String::from_utf8_lossy(&self.aux.misc_data_slice()[0..len as usize])
|
||||
.yellow(),
|
||||
);
|
||||
continue;
|
||||
},
|
||||
}
|
||||
NYX_ABORT => {
|
||||
let len = self.aux.misc.len;
|
||||
println!("[!] libnyx: agent abort() -> \"{}\"", String::from_utf8_lossy(&self.aux.misc_data_slice()[0..len as usize]).red());
|
||||
println!(
|
||||
"[!] libnyx: agent abort() -> \"{}\"",
|
||||
String::from_utf8_lossy(&self.aux.misc_data_slice()[0..len as usize]).red()
|
||||
);
|
||||
break;
|
||||
},
|
||||
}
|
||||
NYX_SUCCESS | NYX_CRASH | NYX_INPUT_WRITE | NYX_TIMEOUT => {
|
||||
break;
|
||||
},
|
||||
}
|
||||
x => {
|
||||
panic!("[!] libnyx: ERROR -> unkown Nyx exec result code: {}", x);
|
||||
}
|
||||
@ -395,7 +406,7 @@ impl QemuProcess {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_timeout(&mut self, timeout: std::time::Duration){
|
||||
pub fn set_timeout(&mut self, timeout: std::time::Duration) {
|
||||
self.aux.config.timeout_sec = timeout.as_secs() as u8;
|
||||
self.aux.config.timeout_usec = timeout.subsec_micros();
|
||||
self.aux.config.changed = 1;
|
||||
@ -405,18 +416,41 @@ impl QemuProcess {
|
||||
self.process.wait().unwrap();
|
||||
}
|
||||
|
||||
fn remove_shm_work_dir(&mut self){
|
||||
|
||||
fn remove_shm_work_dir(&mut self) {
|
||||
/* move originals into workdir (in case we need the data to debug stuff) */
|
||||
let shm_path = self.shm_work_dir.to_str().unwrap();
|
||||
fs::remove_file(&format!("{}/bitmap_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::copy(&format!("{}/bitmap", shm_path), &format!("{}/bitmap_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::remove_file(&format!(
|
||||
"{}/bitmap_{}",
|
||||
&self.params.workdir, self.params.qemu_id
|
||||
))
|
||||
.unwrap();
|
||||
fs::copy(
|
||||
&format!("{}/bitmap", shm_path),
|
||||
&format!("{}/bitmap_{}", &self.params.workdir, self.params.qemu_id),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs::remove_file(&format!("{}/payload_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::copy(&format!("{}/input", shm_path), &format!("{}/payload_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::remove_file(&format!(
|
||||
"{}/payload_{}",
|
||||
&self.params.workdir, self.params.qemu_id
|
||||
))
|
||||
.unwrap();
|
||||
fs::copy(
|
||||
&format!("{}/input", shm_path),
|
||||
&format!("{}/payload_{}", &self.params.workdir, self.params.qemu_id),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
fs::remove_file(&format!("{}/ijon_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::copy(&format!("{}/ijon", shm_path), &format!("{}/ijon_{}", &self.params.workdir, self.params.qemu_id)).unwrap();
|
||||
fs::remove_file(&format!(
|
||||
"{}/ijon_{}",
|
||||
&self.params.workdir, self.params.qemu_id
|
||||
))
|
||||
.unwrap();
|
||||
fs::copy(
|
||||
&format!("{}/ijon", shm_path),
|
||||
&format!("{}/ijon_{}", &self.params.workdir, self.params.qemu_id),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
/* remove this shm directory */
|
||||
fs::remove_dir_all(&self.shm_work_dir).unwrap();
|
||||
@ -429,17 +463,17 @@ impl QemuProcess {
|
||||
self.remove_shm_work_dir();
|
||||
}
|
||||
|
||||
pub fn wait_for_workdir(workdir: &str){
|
||||
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",
|
||||
"snapshot/fast_snapshot.qemu_state"
|
||||
"snapshot/fast_snapshot.qemu_state",
|
||||
];
|
||||
for file in files.iter() {
|
||||
while !Path::new(&format!("{}/{}", workdir, file)).exists(){
|
||||
while !Path::new(&format!("{}/{}", workdir, file)).exists() {
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
@ -483,18 +517,31 @@ impl QemuProcess {
|
||||
.open(format!("{}/page_cache.addr", workdir))
|
||||
.unwrap();
|
||||
|
||||
OpenOptions::new().create(true).write(true).open(format!("{}/program", workdir)).unwrap();
|
||||
OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.open(format!("{}/program", workdir))
|
||||
.unwrap();
|
||||
|
||||
//println!("IMPORT STUFF FOR {:?}", seed_path);
|
||||
if let Some(path) = seed_path {
|
||||
let pattern = format!("{}/*", path);
|
||||
//println!("IMPORT STUFF FOR {}", pattern);
|
||||
for (i,p) in glob::glob(&pattern).expect("couldn't glob seed pattern??").enumerate()
|
||||
for (i, p) in glob::glob(&pattern)
|
||||
.expect("couldn't glob seed pattern??")
|
||||
.enumerate()
|
||||
{
|
||||
let src = p.unwrap_or_else(|e| panic!("invalid seed path found {:?}",e));
|
||||
let src = p.unwrap_or_else(|e| panic!("invalid seed path found {:?}", e));
|
||||
//println!("import {} to {}/seeds/seed_{}",src.to_string_lossy(), workdir,i);
|
||||
let dst = format!("{}/seeds/seed_{}.bin",workdir, i);
|
||||
fs::copy(&src, &dst).unwrap_or_else(|e| panic!("couldn't copy seed {} to {} {:?}",src.to_string_lossy(),dst,e));
|
||||
let dst = format!("{}/seeds/seed_{}.bin", workdir, i);
|
||||
fs::copy(&src, &dst).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"couldn't copy seed {} to {} {:?}",
|
||||
src.to_string_lossy(),
|
||||
dst,
|
||||
e
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,41 +551,36 @@ impl QemuProcess {
|
||||
.expect("couldn't initialize workdir");
|
||||
}
|
||||
|
||||
fn remove_unused_shm_work_dirs(){
|
||||
fn remove_unused_shm_work_dirs() {
|
||||
/* find and remove orphaned Nyx shm workdirs in /dev/shm */
|
||||
for p in glob::glob(&format!("/dev/shm/nyx_*")).expect("couldn't glob??"){
|
||||
for p in glob::glob(&format!("/dev/shm/nyx_*")).expect("couldn't glob??") {
|
||||
let mut path = p.unwrap();
|
||||
|
||||
path.push("lock");
|
||||
if path.exists(){
|
||||
|
||||
let file_lock = match OpenOptions::new()
|
||||
.read(true)
|
||||
.open(&path){
|
||||
if path.exists() {
|
||||
let file_lock = match OpenOptions::new().read(true).open(&path) {
|
||||
Err(x) => {
|
||||
println!("Warning: {}", x);
|
||||
Err(x)
|
||||
},
|
||||
x => {
|
||||
x
|
||||
},
|
||||
}
|
||||
x => x,
|
||||
};
|
||||
|
||||
if file_lock.is_ok(){
|
||||
if file_lock.is_ok() {
|
||||
path.pop();
|
||||
|
||||
match file_lock.unwrap().try_lock_exclusive(){
|
||||
match file_lock.unwrap().try_lock_exclusive() {
|
||||
Ok(_) => {
|
||||
if path.starts_with("/dev/shm/") {
|
||||
match fs::remove_dir_all(path){
|
||||
match fs::remove_dir_all(path) {
|
||||
Err(x) => {
|
||||
println!("Warning: {}", x);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(_) => {},
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user