Enforce max_input_size and min_input_size in Forkserver (#2273)
* enforce minimum and maximum input size for Forkserver's shared memory map and file based testcases * explicit conversion to OwnedSlice * clippy * error if min_input_size > max_input_size when building forkserver
This commit is contained in:
parent
6373a1e1b3
commit
7dd345d18c
@ -21,6 +21,7 @@ use std::{
|
|||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
fs::{get_unique_std_input_file, InputFile},
|
fs::{get_unique_std_input_file, InputFile},
|
||||||
os::{dup2, pipes::Pipe},
|
os::{dup2, pipes::Pipe},
|
||||||
|
ownedref::OwnedSlice,
|
||||||
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
|
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
|
||||||
tuples::{Handle, Handled, MatchNameRef, Prepend, RefIndexable},
|
tuples::{Handle, Handled, MatchNameRef, Prepend, RefIndexable},
|
||||||
AsSlice, AsSliceMut, Truncate,
|
AsSlice, AsSliceMut, Truncate,
|
||||||
@ -102,6 +103,7 @@ fn report_error_and_exit(status: i32) -> Result<(), Error> {
|
|||||||
/// The length of header bytes which tells shmem size
|
/// The length of header bytes which tells shmem size
|
||||||
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
||||||
const MAX_INPUT_SIZE_DEFAULT: usize = 1024 * 1024;
|
const MAX_INPUT_SIZE_DEFAULT: usize = 1024 * 1024;
|
||||||
|
const MIN_INPUT_SIZE_DEFAULT: usize = 1;
|
||||||
|
|
||||||
/// The default signal to use to kill child processes
|
/// The default signal to use to kill child processes
|
||||||
const KILL_SIGNAL_DEFAULT: Signal = Signal::SIGTERM;
|
const KILL_SIGNAL_DEFAULT: Signal = Signal::SIGTERM;
|
||||||
@ -529,6 +531,8 @@ where
|
|||||||
map: Option<SP::ShMem>,
|
map: Option<SP::ShMem>,
|
||||||
phantom: PhantomData<S>,
|
phantom: PhantomData<S>,
|
||||||
map_size: Option<usize>,
|
map_size: Option<usize>,
|
||||||
|
min_input_size: usize,
|
||||||
|
max_input_size: usize,
|
||||||
#[cfg(feature = "regex")]
|
#[cfg(feature = "regex")]
|
||||||
asan_obs: Handle<AsanBacktraceObserver>,
|
asan_obs: Handle<AsanBacktraceObserver>,
|
||||||
timeout: TimeSpec,
|
timeout: TimeSpec,
|
||||||
@ -614,6 +618,7 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
|
|||||||
input_filename: Option<OsString>,
|
input_filename: Option<OsString>,
|
||||||
shmem_provider: Option<&'a mut SP>,
|
shmem_provider: Option<&'a mut SP>,
|
||||||
max_input_size: usize,
|
max_input_size: usize,
|
||||||
|
min_input_size: usize,
|
||||||
map_size: Option<usize>,
|
map_size: Option<usize>,
|
||||||
kill_signal: Option<Signal>,
|
kill_signal: Option<Signal>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
@ -656,6 +661,15 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
|||||||
Some(t) => t.into(),
|
Some(t) => t.into(),
|
||||||
None => Duration::from_millis(5000).into(),
|
None => Duration::from_millis(5000).into(),
|
||||||
};
|
};
|
||||||
|
if self.min_input_size > self.max_input_size {
|
||||||
|
return Err(Error::illegal_argument(
|
||||||
|
format!(
|
||||||
|
"Minimum input size ({}) must not exceed maximum input size ({})",
|
||||||
|
self.min_input_size, self.max_input_size
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(ForkserverExecutor {
|
Ok(ForkserverExecutor {
|
||||||
target,
|
target,
|
||||||
@ -667,6 +681,8 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
|||||||
map,
|
map,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
map_size: self.map_size,
|
map_size: self.map_size,
|
||||||
|
min_input_size: self.min_input_size,
|
||||||
|
max_input_size: self.max_input_size,
|
||||||
timeout,
|
timeout,
|
||||||
asan_obs: self
|
asan_obs: self
|
||||||
.asan_obs
|
.asan_obs
|
||||||
@ -729,6 +745,8 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
|||||||
map,
|
map,
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
map_size: self.map_size,
|
map_size: self.map_size,
|
||||||
|
min_input_size: self.min_input_size,
|
||||||
|
max_input_size: self.max_input_size,
|
||||||
timeout,
|
timeout,
|
||||||
asan_obs: self
|
asan_obs: self
|
||||||
.asan_obs
|
.asan_obs
|
||||||
@ -1010,6 +1028,20 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the max input size
|
||||||
|
#[must_use]
|
||||||
|
pub fn max_input_size(mut self, size: usize) -> Self {
|
||||||
|
self.max_input_size = size;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the min input size
|
||||||
|
#[must_use]
|
||||||
|
pub fn min_input_size(mut self, size: usize) -> Self {
|
||||||
|
self.min_input_size = size;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds an environmental var to the harness's commandline
|
/// Adds an environmental var to the harness's commandline
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn env<K, V>(mut self, key: K, val: V) -> Self
|
pub fn env<K, V>(mut self, key: K, val: V) -> Self
|
||||||
@ -1131,6 +1163,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
|||||||
shmem_provider: None,
|
shmem_provider: None,
|
||||||
map_size: None,
|
map_size: None,
|
||||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||||
|
min_input_size: MIN_INPUT_SIZE_DEFAULT,
|
||||||
kill_signal: None,
|
kill_signal: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
asan_obs: None,
|
asan_obs: None,
|
||||||
@ -1157,6 +1190,7 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
|||||||
shmem_provider: Some(shmem_provider),
|
shmem_provider: Some(shmem_provider),
|
||||||
map_size: self.map_size,
|
map_size: self.map_size,
|
||||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||||
|
min_input_size: MIN_INPUT_SIZE_DEFAULT,
|
||||||
kill_signal: None,
|
kill_signal: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
asan_obs: None,
|
asan_obs: None,
|
||||||
@ -1194,6 +1228,21 @@ where
|
|||||||
|
|
||||||
let last_run_timed_out = self.forkserver.last_run_timed_out_raw();
|
let last_run_timed_out = self.forkserver.last_run_timed_out_raw();
|
||||||
|
|
||||||
|
let mut input_bytes = input.target_bytes();
|
||||||
|
let mut input_size = input_bytes.as_slice().len();
|
||||||
|
if input_size > self.max_input_size {
|
||||||
|
// Truncate like AFL++ does
|
||||||
|
input_size = self.max_input_size;
|
||||||
|
} else if input_size < self.min_input_size {
|
||||||
|
// Extend like AFL++ does
|
||||||
|
input_size = self.min_input_size;
|
||||||
|
let mut input_bytes_copy = Vec::with_capacity(input_size);
|
||||||
|
input_bytes_copy
|
||||||
|
.as_slice_mut()
|
||||||
|
.copy_from_slice(input_bytes.as_slice());
|
||||||
|
input_bytes = OwnedSlice::from(input_bytes_copy);
|
||||||
|
}
|
||||||
|
let input_size_in_bytes = input_size.to_ne_bytes();
|
||||||
if self.uses_shmem_testcase {
|
if self.uses_shmem_testcase {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
self.map.is_some(),
|
self.map.is_some(),
|
||||||
@ -1202,21 +1251,14 @@ where
|
|||||||
// # Safety
|
// # Safety
|
||||||
// Struct can never be created when uses_shmem_testcase is true and map is none.
|
// Struct can never be created when uses_shmem_testcase is true and map is none.
|
||||||
let map = unsafe { self.map.as_mut().unwrap_unchecked() };
|
let map = unsafe { self.map.as_mut().unwrap_unchecked() };
|
||||||
let target_bytes = input.target_bytes();
|
// The first four bytes declares the size of the shmem.
|
||||||
let mut size = target_bytes.as_slice().len();
|
|
||||||
let max_size = map.len() - SHMEM_FUZZ_HDR_SIZE;
|
|
||||||
if size > max_size {
|
|
||||||
// Truncate like AFL++ does
|
|
||||||
size = max_size;
|
|
||||||
}
|
|
||||||
let size_in_bytes = size.to_ne_bytes();
|
|
||||||
// The first four bytes tells the size of the shmem.
|
|
||||||
map.as_slice_mut()[..SHMEM_FUZZ_HDR_SIZE]
|
map.as_slice_mut()[..SHMEM_FUZZ_HDR_SIZE]
|
||||||
.copy_from_slice(&size_in_bytes[..SHMEM_FUZZ_HDR_SIZE]);
|
.copy_from_slice(&input_size_in_bytes[..SHMEM_FUZZ_HDR_SIZE]);
|
||||||
map.as_slice_mut()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + size)]
|
map.as_slice_mut()[SHMEM_FUZZ_HDR_SIZE..(SHMEM_FUZZ_HDR_SIZE + input_size)]
|
||||||
.copy_from_slice(&target_bytes.as_slice()[..size]);
|
.copy_from_slice(&input_bytes.as_slice()[..input_size]);
|
||||||
} else {
|
} else {
|
||||||
self.input_file.write_buf(input.target_bytes().as_slice())?;
|
self.input_file
|
||||||
|
.write_buf(&input_bytes.as_slice()[..input_size])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let send_len = self.forkserver.write_ctl(last_run_timed_out)?;
|
let send_len = self.forkserver.write_ctl(last_run_timed_out)?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user