Debug output for forkserver (#413)

* usability fixes for forkserver

* don't call target_bytes twice in TimeoutForkserverExecutor

* don't call target_bytes twice in ForkserverExecutor
This commit is contained in:
Andrea Fioraldi 2021-12-10 14:52:23 +01:00 committed by GitHub
parent 4aa6550bf2
commit b4c2551544
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 30 deletions

View File

@ -195,15 +195,22 @@ impl Forkserver {
out_filefd: RawFd,
use_stdin: bool,
memlimit: u64,
debug_output: bool,
) -> Result<Self, Error> {
let mut st_pipe = Pipe::new().unwrap();
let mut ctl_pipe = Pipe::new().unwrap();
let (stdout, stderr) = if debug_output {
(Stdio::inherit(), Stdio::inherit())
} else {
(Stdio::null(), Stdio::null())
};
match Command::new(target)
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.stdout(stdout)
.stderr(stderr)
.env("LD_BIND_LAZY", "1")
.setlimit(memlimit)
.setsid()
@ -364,12 +371,13 @@ where
match &mut self.executor.map_mut() {
Some(map) => {
let size = input.target_bytes().as_slice().len();
let target_bytes = input.target_bytes();
let size = target_bytes.as_slice().len();
let size_in_bytes = size.to_ne_bytes();
// The first four bytes tells the size of the shmem.
map.map_mut()[..4].copy_from_slice(&size_in_bytes[..4]);
map.map_mut()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + size)]
.copy_from_slice(input.target_bytes().as_slice());
.copy_from_slice(target_bytes.as_slice());
}
None => {
self.executor
@ -466,6 +474,16 @@ where
arguments: &[String],
use_shmem_testcase: bool,
observers: OT,
) -> Result<Self, Error> {
Self::with_debug(target, arguments, use_shmem_testcase, observers, false)
}
pub fn with_debug(
target: String,
arguments: &[String],
use_shmem_testcase: bool,
observers: OT,
debug_output: bool,
) -> Result<Self, Error> {
let mut args = Vec::<String>::new();
let mut use_stdin = true;
@ -500,6 +518,7 @@ where
out_file.as_raw_fd(),
use_stdin,
0,
debug_output,
)?;
let (rlen, status) = forkserver.read_st()?; // Initial handshake, read 4-bytes hello message from the forkserver.
@ -573,12 +592,13 @@ where
// Write to testcase
match &mut self.map {
Some(map) => {
let size = input.target_bytes().as_slice().len();
let target_bytes = input.target_bytes();
let size = target_bytes.as_slice().len();
let size_in_bytes = size.to_ne_bytes();
// The first four bytes tells the size of the shmem.
map.map_mut()[..4].copy_from_slice(&size_in_bytes[..4]);
map.map_mut()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + size)]
.copy_from_slice(input.target_bytes().as_slice());
.copy_from_slice(target_bytes.as_slice());
}
None => {
self.out_file.write_buf(input.target_bytes().as_slice());

View File

@ -31,10 +31,10 @@ use libafl::{
use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS};
pub const MAP_SIZE: usize = 65536;
pub const DEFAULT_MAP_SIZE: usize = 65536;
#[derive(TypedBuilder)]
pub struct ForkserverBytesCoverageSugar<'a> {
pub struct ForkserverBytesCoverageSugar<'a, const MAP_SIZE: usize> {
/// Laucher configuration (default is random)
#[builder(default = None, setter(strip_option))]
configuration: Option<String>,
@ -66,13 +66,13 @@ pub struct ForkserverBytesCoverageSugar<'a> {
#[builder(default = false)]
/// Use shared mem testcase delivery
shmem_testcase: bool,
// Coverage map size
//#[builder(default = MAP_SIZE)]
//map_size: usize,
#[builder(default = false)]
/// Print target program output
debug_output: bool,
}
#[allow(clippy::similar_names)]
impl<'a> ForkserverBytesCoverageSugar<'a> {
impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
#[allow(clippy::too_many_lines, clippy::similar_names)]
pub fn run(&mut self) {
let conf = match self.configuration.as_ref() {
@ -166,11 +166,12 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = TimeoutForkserverExecutor::new(
ForkserverExecutor::new(
ForkserverExecutor::with_debug(
self.program.clone(),
self.arguments,
self.shmem_testcase,
tuple_list!(edges_observer, time_observer),
self.debug_output,
)
.expect("Failed to create the executor."),
timeout,
@ -248,16 +249,14 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
}
}
/*
#[cfg(feature = "python")]
pub mod pybind {
use crate::inmemory;
use crate::forkserver;
use pyo3::prelude::*;
use pyo3::types::PyBytes;
use std::path::PathBuf;
#[pyclass(unsendable)]
struct InMemoryBytesCoverageSugar {
struct ForkserverBytesCoverageSugar {
input_dirs: Vec<PathBuf>,
output_dir: PathBuf,
broker_port: u16,
@ -265,7 +264,7 @@ pub mod pybind {
}
#[pymethods]
impl InMemoryBytesCoverageSugar {
impl ForkserverBytesCoverageSugar {
#[new]
fn new(
input_dirs: Vec<PathBuf>,
@ -282,27 +281,21 @@ pub mod pybind {
}
#[allow(clippy::needless_pass_by_value)]
pub fn run(&self, harness: PyObject) {
inmemory::InMemoryBytesCoverageSugar::builder()
pub fn run(&self, program: String, arguments: Vec<String>) {
forkserver::ForkserverBytesCoverageSugar::<{ forkserver::DEFAULT_MAP_SIZE }>::builder()
.input_dirs(&self.input_dirs)
.output_dir(self.output_dir.clone())
.broker_port(self.broker_port)
.cores(&self.cores)
.harness(|buf| {
Python::with_gil(|py| -> PyResult<()> {
let args = (PyBytes::new(py, buf),); // TODO avoid copy
harness.call1(py, args)?;
Ok(())
})
.unwrap();
})
.program(program)
.arguments(&arguments)
.build()
.run();
}
}
pub fn register(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<InMemoryBytesCoverageSugar>()?;
m.add_class::<ForkserverBytesCoverageSugar>()?;
Ok(())
}
}*/
}