Toka d4410c072a
ForkserverExecutor (#111)
* add Forkserver, Pipe Outfile struct

* add forkserver executor struct, and shmem init

* close pipes in the destructor of Forkserver

* fill pre_exec to write out the inputs

* fix

* read_st, write_ctl

* more handshakes

* wrap Pipe in Arc, fill post_exec

* add Forkserver, Pipe Outfile struct

* add forkserver executor struct, and shmem init

* close pipes in the destructor of Forkserver

* fill pre_exec to write out the inputs

* fix

* read_st, write_ctl

* more handshakes

* wrap Pipe in Arc, fill post_exec

* fix for the lastest HasExecHooks trait

* use Dominik's pipe, remove Arc and temporarily pass RawFd to setstdin but trying to figure out other solutions

* add libafl_tests, put a very simple vulnerable program

* fix

* added forkserver_simple (mostly copy-pasted from babyfuzzer)

* fix test

* handle crash in post_exec

* add README.md

* check exec time to see why it's so slow

* remove double invokation of is_interesting for the obejctive

* make forkserver_simple AFL-like and improve speed

* some debugging help

* do not evaluate feedback if solution

* speedup the things

* working input placement via stdin in Forkserver

* don't call panic! but return errors, rewrite some comments

* use AFLplusplus/afl-cc instead of AFL

* use .cur_input like AFL

* bring the test for forkserver back

* add better README.md message

* failing the initial handshake should return an error

* delete some commented-out code

* format

* format

* ForkserverExecutor needs std and is unix-only for now

* clippy

* OutFile error handling

* fmt

* clippy

* don't build libafl_tests on windows

* fix

* keep test in forkserver.rs simple

* add forkserver_test feature for libafl_tests

* format

* some doc

Co-authored-by: Andrea Fioraldi <andreafioraldi@gmail.com>
2021-05-25 13:40:00 +02:00

104 lines
2.5 KiB
Rust

//! Unix `pipe` wrapper for `LibAFL`
use crate::Error;
use nix::unistd::{close, pipe};
#[cfg(feature = "std")]
use nix::unistd::{read, write};
#[cfg(feature = "std")]
use std::{
io::{self, ErrorKind, Read, Write},
os::unix::io::RawFd,
};
#[cfg(not(feature = "std"))]
type RawFd = i32;
#[derive(Debug, Clone)]
pub struct Pipe {
read_end: Option<RawFd>,
write_end: Option<RawFd>,
}
impl Pipe {
pub fn new() -> Result<Self, Error> {
let (read_end, write_end) = pipe()?;
Ok(Self {
read_end: Some(read_end),
write_end: Some(write_end),
})
}
pub fn close_read_end(&mut self) {
if let Some(read_end) = self.read_end {
let _ = close(read_end);
self.read_end = None;
}
}
pub fn close_write_end(&mut self) {
if let Some(write_end) = self.write_end {
let _ = close(write_end);
self.write_end = None;
}
}
#[must_use]
pub fn read_end(&self) -> Option<RawFd> {
self.read_end
}
#[must_use]
pub fn write_end(&self) -> Option<RawFd> {
self.write_end
}
}
#[cfg(feature = "std")]
impl Read for Pipe {
/// Reads a few bytes
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
match self.read_end {
Some(read_end) => match read(read_end, buf) {
Ok(res) => Ok(res),
Err(e) => Err(io::Error::from_raw_os_error(e.as_errno().unwrap() as i32)),
},
None => Err(io::Error::new(
ErrorKind::BrokenPipe,
"Read pipe end was already closed",
)),
}
}
}
#[cfg(feature = "std")]
impl Write for Pipe {
/// Writes a few bytes
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
match self.write_end {
Some(write_end) => match write(write_end, buf) {
Ok(res) => Ok(res),
Err(e) => Err(io::Error::from_raw_os_error(e.as_errno().unwrap() as i32)),
},
None => Err(io::Error::new(
ErrorKind::BrokenPipe,
"Write pipe end was already closed",
)),
}
}
fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
}
impl Drop for Pipe {
fn drop(&mut self) {
if let Some(read_end) = self.read_end {
let _ = close(read_end);
}
if let Some(write_end) = self.write_end {
let _ = close(write_end);
}
}
}