New forkserver (#2213)
* step 1 * done * cmplog? * targets * check if working and add env_logger * typo
This commit is contained in:
parent
b7e10ca7af
commit
19ef29ed60
@ -27,6 +27,7 @@ libafl = { path = "../../libafl/" }
|
||||
libafl_bolts = { path = "../../libafl_bolts/" }
|
||||
libafl_cc = { path = "../../libafl_cc/" }
|
||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer", "pointer_maps"] }
|
||||
env_logger = "0.10"
|
||||
|
||||
[lib]
|
||||
name = "libforkserver_libafl_cc"
|
||||
|
@ -85,6 +85,8 @@ struct Opt {
|
||||
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn main() {
|
||||
env_logger::init();
|
||||
|
||||
const MAP_SIZE: usize = EDGES_MAP_SIZE_IN_USE; //65536;
|
||||
let opt = Opt::parse();
|
||||
|
||||
|
@ -16,6 +16,7 @@ codegen-units = 1
|
||||
opt-level = 3
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.10"
|
||||
libafl = { path = "../../libafl/", features = ["std", "derive"] }
|
||||
libafl_bolts = { path = "../../libafl_bolts/" }
|
||||
clap = { version = "4.0", features = ["derive"] }
|
||||
|
@ -85,6 +85,7 @@ struct Opt {
|
||||
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn main() {
|
||||
env_logger::init();
|
||||
const MAP_SIZE: usize = 65536;
|
||||
|
||||
let opt = Opt::parse();
|
||||
|
@ -48,24 +48,56 @@ use crate::{
|
||||
|
||||
const FORKSRV_FD: i32 = 198;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_OPT_ENABLED: i32 = 0x80000001_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_OPT_MAPSIZE: i32 = 0x40000000_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_OPT_SHDMEM_FUZZ: i32 = 0x01000000_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_OPT_AUTODICT: i32 = 0x10000000_u32 as i32;
|
||||
const FS_NEW_ERROR: i32 = 0xeffe0000_u32 as i32;
|
||||
|
||||
// #[allow(clippy::cast_possible_wrap)]
|
||||
// const FS_OPT_MAX_MAPSIZE: i32 = ((0x00fffffe_u32 >> 1) + 1) as i32; // 8388608
|
||||
const fn fs_opt_get_mapsize(x: i32) -> i32 {
|
||||
((x & 0x00fffffe) >> 1) + 1
|
||||
const FS_NEW_VERSION_MIN: u32 = 1;
|
||||
const FS_NEW_VERSION_MAX: u32 = 1;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_NEW_OPT_MAPSIZE: i32 = 1_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_NEW_OPT_SHDMEM_FUZZ: i32 = 2_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_NEW_OPT_AUTODICT: i32 = 0x00000800_u32 as i32;
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_MAP_SIZE: i32 = 1_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_MAP_ADDR: i32 = 2_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_SHM_OPEN: i32 = 4_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_SHMAT: i32 = 8_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_MMAP: i32 = 16_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_OLD_CMPLOG: i32 = 32_u32 as i32;
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
const FS_ERROR_OLD_CMPLOG_QEMU: i32 = 64_u32 as i32;
|
||||
|
||||
fn report_error_and_exit(status: i32) -> Result<(), Error> {
|
||||
/* Report on the error received via the forkserver controller and exit */
|
||||
match status {
|
||||
FS_ERROR_MAP_SIZE =>
|
||||
Err(Error::unknown(
|
||||
"AFL_MAP_SIZE is not set and fuzzing target reports that the required size is very large. Solution: Run the fuzzing target stand-alone with the environment variable AFL_DEBUG=1 set and set the value for __afl_final_loc in the AFL_MAP_SIZE environment variable for afl-fuzz.".to_string())),
|
||||
FS_ERROR_MAP_ADDR =>
|
||||
Err(Error::unknown(
|
||||
"the fuzzing target reports that hardcoded map address might be the reason the mmap of the shared memory failed. Solution: recompile the target with either afl-clang-lto and do not set AFL_LLVM_MAP_ADDR or recompile with afl-clang-fast.".to_string())),
|
||||
FS_ERROR_SHM_OPEN =>
|
||||
Err(Error::unknown("the fuzzing target reports that the shm_open() call failed.".to_string())),
|
||||
FS_ERROR_SHMAT =>
|
||||
Err(Error::unknown("the fuzzing target reports that the shmat() call failed.".to_string())),
|
||||
FS_ERROR_MMAP =>
|
||||
Err(Error::unknown("the fuzzing target reports that the mmap() call to the shared memory failed.".to_string())),
|
||||
FS_ERROR_OLD_CMPLOG =>
|
||||
Err(Error::unknown(
|
||||
"the -c cmplog target was instrumented with an too old AFL++ version, you need to recompile it.".to_string())),
|
||||
FS_ERROR_OLD_CMPLOG_QEMU =>
|
||||
Err(Error::unknown("The AFL++ QEMU/FRIDA loaders are from an older version, for -c you need to recompile it.".to_string())),
|
||||
_ =>
|
||||
Err(Error::unknown(format!("unknown error code {status} from fuzzing target!"))),
|
||||
}
|
||||
}
|
||||
/* const fn fs_opt_set_mapsize(x: usize) -> usize {
|
||||
if x <= 1 {
|
||||
if x > FS_OPT_MAX_MAPSIZE { 0 } else { (x - 1) << 1 }
|
||||
} else { 0 }
|
||||
} */
|
||||
|
||||
/// The length of header bytes which tells shmem size
|
||||
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
||||
@ -583,7 +615,6 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
|
||||
shmem_provider: Option<&'a mut SP>,
|
||||
max_input_size: usize,
|
||||
map_size: Option<usize>,
|
||||
real_map_size: i32,
|
||||
kill_signal: Option<Signal>,
|
||||
timeout: Option<Duration>,
|
||||
#[cfg(feature = "regex")]
|
||||
@ -755,15 +786,54 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
}
|
||||
};
|
||||
|
||||
let (rlen, status) = forkserver.read_st()?; // Initial handshake, read 4-bytes hello message from the forkserver.
|
||||
let (rlen, version_status) = forkserver.read_st()?; // Initial handshake, read 4-bytes hello message from the forkserver.
|
||||
|
||||
if rlen != 4 {
|
||||
return Err(Error::unknown("Failed to start a forkserver".to_string()));
|
||||
}
|
||||
log::info!("All right - fork server is up.");
|
||||
|
||||
if status & FS_OPT_ENABLED == FS_OPT_ENABLED && status & FS_OPT_MAPSIZE == FS_OPT_MAPSIZE {
|
||||
let mut map_size = fs_opt_get_mapsize(status);
|
||||
if (version_status & FS_NEW_ERROR) == FS_NEW_ERROR {
|
||||
report_error_and_exit(version_status & 0x0000ffff)?;
|
||||
}
|
||||
|
||||
let keep = version_status;
|
||||
let version: u32 = version_status as u32 - 0x41464c00_u32;
|
||||
if (0x41464c00..=0x41464cff).contains(&version_status) {
|
||||
match version {
|
||||
0 => {
|
||||
return Err(Error::unknown("Fork server version is not assigned, this should not happen. Recompile target."));
|
||||
}
|
||||
FS_NEW_VERSION_MIN..=FS_NEW_VERSION_MAX => {
|
||||
// good, do nothing
|
||||
}
|
||||
_ => {
|
||||
return Err(Error::unknown(
|
||||
"Fork server version is not supported. Recompile the target.",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let xored_version_status = (version_status as u32 ^ 0xffffffff) as i32;
|
||||
|
||||
let send_len = forkserver.write_ctl(xored_version_status)?;
|
||||
if send_len != 4 {
|
||||
return Err(Error::unknown("Writing to forkserver failed.".to_string()));
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"All right - new fork server model version {} is up",
|
||||
version
|
||||
);
|
||||
|
||||
let (read_len, status) = forkserver.read_st()?;
|
||||
if read_len != 4 {
|
||||
return Err(Error::unknown(
|
||||
"Reading from forkserver failed.".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if status & FS_NEW_OPT_MAPSIZE == FS_NEW_OPT_MAPSIZE {
|
||||
// When 0, we assume that map_size was filled by the user or const
|
||||
/* TODO autofill map size from the observer
|
||||
|
||||
@ -771,8 +841,13 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
self.map_size = Some(map_size as usize);
|
||||
}
|
||||
*/
|
||||
let (read_len, mut map_size) = forkserver.read_st()?;
|
||||
if read_len != 4 {
|
||||
return Err(Error::unknown(
|
||||
"Failed to read map size from forkserver".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
self.real_map_size = map_size;
|
||||
if map_size % 64 != 0 {
|
||||
map_size = ((map_size + 63) >> 6) << 6;
|
||||
}
|
||||
@ -780,45 +855,28 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
// TODO set AFL_MAP_SIZE
|
||||
assert!(self.map_size.is_none() || map_size as usize <= self.map_size.unwrap());
|
||||
|
||||
// we'll use this later when we truncate the observer
|
||||
self.map_size = Some(map_size as usize);
|
||||
}
|
||||
|
||||
// Only with SHMEM or AUTODICT we can send send_status back or it breaks!
|
||||
// If forkserver is responding, we then check if there's any option enabled.
|
||||
// We'll send 4-bytes message back to the forkserver to tell which features to use
|
||||
// The forkserver is listening to our response if either shmem fuzzing is enabled or auto dict is enabled
|
||||
// <https://github.com/AFLplusplus/AFLplusplus/blob/147654f8715d237fe45c1657c87b2fe36c4db22a/instrumentation/afl-compiler-rt.o.c#L1026>
|
||||
if status & FS_OPT_ENABLED == FS_OPT_ENABLED
|
||||
&& (status & FS_OPT_SHDMEM_FUZZ == FS_OPT_SHDMEM_FUZZ
|
||||
|| status & FS_OPT_AUTODICT == FS_OPT_AUTODICT)
|
||||
{
|
||||
let mut send_status = FS_OPT_ENABLED;
|
||||
|
||||
if (status & FS_OPT_SHDMEM_FUZZ == FS_OPT_SHDMEM_FUZZ) && map.is_some() {
|
||||
if status & FS_NEW_OPT_SHDMEM_FUZZ != 0 {
|
||||
if map.is_some() {
|
||||
log::info!("Using SHARED MEMORY FUZZING feature.");
|
||||
send_status |= FS_OPT_SHDMEM_FUZZ;
|
||||
self.uses_shmem_testcase = true;
|
||||
} else {
|
||||
return Err(Error::unknown(
|
||||
"Target requested sharedmem fuzzing, but you didn't prepare shmem",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if (status & FS_OPT_AUTODICT == FS_OPT_AUTODICT) && self.autotokens.is_some() {
|
||||
log::info!("Using AUTODICT feature");
|
||||
send_status |= FS_OPT_AUTODICT;
|
||||
}
|
||||
|
||||
if send_status != FS_OPT_ENABLED {
|
||||
// if send_status is not changed (Options are available but we didn't use any), then don't send the next write_ctl message.
|
||||
// This is important
|
||||
|
||||
let send_len = forkserver.write_ctl(send_status)?;
|
||||
if send_len != 4 {
|
||||
return Err(Error::unknown("Writing to forkserver failed.".to_string()));
|
||||
}
|
||||
|
||||
if (send_status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT {
|
||||
if status & FS_NEW_OPT_AUTODICT != 0 {
|
||||
// Here unlike shmem input fuzzing, we are forced to read things
|
||||
// hence no self.autotokens.is_some() to check if we proceed
|
||||
let (read_len, dict_size) = forkserver.read_st()?;
|
||||
if read_len != 4 {
|
||||
return Err(Error::unknown(
|
||||
"Reading from forkserver failed.".to_string(),
|
||||
"Failed to read dictionary size from forkserver".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
@ -827,9 +885,7 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
"Dictionary has an illegal size".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
log::info!("Autodict size {dict_size:x}");
|
||||
|
||||
let (rlen, buf) = forkserver.read_st_size(dict_size as usize)?;
|
||||
|
||||
if rlen != dict_size as usize {
|
||||
@ -839,9 +895,17 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
||||
t.parse_autodict(&buf, dict_size as usize);
|
||||
}
|
||||
}
|
||||
|
||||
let (read_len, aflx) = forkserver.read_st()?;
|
||||
if read_len != 4 {
|
||||
return Err(Error::unknown("Reading from forkserver failed".to_string()));
|
||||
}
|
||||
} else {
|
||||
log::warn!("Forkserver Options are not available.");
|
||||
|
||||
if aflx != version_status {
|
||||
return Err(Error::unknown(format!(
|
||||
"Error in forkserver communication ({:x}=>{:x})",
|
||||
keep, aflx
|
||||
)));
|
||||
}
|
||||
|
||||
Ok((forkserver, input_file, map))
|
||||
@ -1066,7 +1130,6 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
||||
input_filename: None,
|
||||
shmem_provider: None,
|
||||
map_size: None,
|
||||
real_map_size: 0,
|
||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||
kill_signal: None,
|
||||
timeout: None,
|
||||
@ -1093,7 +1156,6 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
||||
input_filename: self.input_filename,
|
||||
shmem_provider: Some(shmem_provider),
|
||||
map_size: self.map_size,
|
||||
real_map_size: self.real_map_size,
|
||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||
kill_signal: None,
|
||||
timeout: None,
|
||||
|
@ -516,12 +516,10 @@ impl AFLppCmpValuesMetadata {
|
||||
/// - reserved: Reserved for future use
|
||||
pub struct AFLppCmpLogHeader {
|
||||
/// The header values
|
||||
#[bitfield(name = "hits", ty = "u32", bits = "0..=23")]
|
||||
#[bitfield(name = "id", ty = "u32", bits = "24..=47")]
|
||||
#[bitfield(name = "shape", ty = "u32", bits = "48..=52")]
|
||||
#[bitfield(name = "_type", ty = "u32", bits = "53..=54")]
|
||||
#[bitfield(name = "attribute", ty = "u32", bits = "55..=58")]
|
||||
#[bitfield(name = "overflow", ty = "u32", bits = "59..=59")]
|
||||
#[bitfield(name = "reserved", ty = "u32", bits = "60..=63")]
|
||||
pub data: [u8; 8],
|
||||
#[bitfield(name = "hits", ty = "u32", bits = "0..=5")] // 6 bits up to 63 entries, we have CMP_MAP_H = 32 (so using half of it)
|
||||
#[bitfield(name = "shape", ty = "u32", bits = "6..=10")] // 31 + 1 bytes max
|
||||
#[bitfield(name = "_type", ty = "u8", bits = "11..=11")] // 2: cmp, rtn
|
||||
#[bitfield(name = "attribute", ty = "u32", bits = "12..=15")]
|
||||
// 16 types for arithmetic comparison types
|
||||
pub data: [u8; 2],
|
||||
}
|
||||
|
@ -27,10 +27,6 @@
|
||||
#define CMPLOG_KIND_INS 0
|
||||
#define CMPLOG_KIND_RTN 1
|
||||
|
||||
// Same, difference between aflpp and libafl
|
||||
#define AFL_CMP_TYPE_INS 1
|
||||
#define AFL_CMP_TYPE_RTN 2
|
||||
|
||||
typedef struct CmpLogHeader {
|
||||
uint16_t hits;
|
||||
uint8_t shape;
|
||||
@ -39,23 +35,17 @@ typedef struct CmpLogHeader {
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef struct CmpLogHeaderExtended {
|
||||
unsigned hits : 24;
|
||||
unsigned id : 24;
|
||||
unsigned hits : 6;
|
||||
unsigned shape : 5;
|
||||
unsigned type : 2;
|
||||
unsigned type : 1;
|
||||
unsigned attribute : 4;
|
||||
unsigned overflow : 1;
|
||||
unsigned reserved : 4;
|
||||
} __attribute__((packed)) CmpLogHeaderExtended;
|
||||
#else
|
||||
__pragma(pack(push, 1)) typedef struct CmpLogHeaderExtended {
|
||||
unsigned hits : 24;
|
||||
unsigned id : 24;
|
||||
unsigned hits : 6;
|
||||
unsigned shape : 5;
|
||||
unsigned type : 2;
|
||||
unsigned type : 1;
|
||||
unsigned attribute : 4;
|
||||
unsigned overflow : 1;
|
||||
unsigned reserved : 4;
|
||||
} CmpLogHeaderExtended;
|
||||
__pragma(pack(pop))
|
||||
#endif
|
||||
@ -146,8 +136,8 @@ static inline void cmplog_instructions_extended_checked(
|
||||
|
||||
// printf("%ld %ld %ld\n", k, arg1, arg2);
|
||||
uint16_t hits;
|
||||
if (libafl_cmplog_map_extended_ptr->headers[k].type != AFL_CMP_TYPE_INS) {
|
||||
libafl_cmplog_map_extended_ptr->headers[k].type = AFL_CMP_TYPE_INS;
|
||||
if (libafl_cmplog_map_extended_ptr->headers[k].type != CMPLOG_KIND_INS) {
|
||||
libafl_cmplog_map_extended_ptr->headers[k].type = CMPLOG_KIND_INS;
|
||||
libafl_cmplog_map_extended_ptr->headers[k].hits = 1;
|
||||
libafl_cmplog_map_extended_ptr->headers[k].shape = shape;
|
||||
hits = 0;
|
||||
@ -207,8 +197,8 @@ static inline void cmplog_routines_checked_extended(uintptr_t k,
|
||||
libafl_cmplog_enabled = false;
|
||||
uint32_t hits;
|
||||
// printf("RTN: %ld %ld %ld %ld\n", k, *ptr1, *ptr2, len);
|
||||
if (libafl_cmplog_map_extended_ptr->headers[k].type != AFL_CMP_TYPE_RTN) {
|
||||
libafl_cmplog_map_extended_ptr->headers[k].type = AFL_CMP_TYPE_RTN;
|
||||
if (libafl_cmplog_map_extended_ptr->headers[k].type != CMPLOG_KIND_RTN) {
|
||||
libafl_cmplog_map_extended_ptr->headers[k].type = CMPLOG_KIND_RTN;
|
||||
libafl_cmplog_map_extended_ptr->headers[k].hits = 1;
|
||||
libafl_cmplog_map_extended_ptr->headers[k].shape = len;
|
||||
hits = 0;
|
||||
|
@ -41,11 +41,6 @@ pub const CMPLOG_KIND_INS: u8 = 0;
|
||||
/// `CmpLog` routine kind
|
||||
pub const CMPLOG_KIND_RTN: u8 = 1;
|
||||
|
||||
/// The AFL++ `CMP_TYPE_INS`
|
||||
pub const AFL_CMP_TYPE_INS: u32 = 1;
|
||||
/// The AFL++ `CMP_TYPE_RTN`
|
||||
pub const AFL_CMP_TYPE_RTN: u32 = 2;
|
||||
|
||||
// EXTERNS, GLOBALS
|
||||
|
||||
#[cfg(feature = "cmplog")]
|
||||
@ -415,7 +410,7 @@ pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
|
||||
#[cfg(feature = "cmplog_extended_instrumentation")]
|
||||
#[allow(clippy::large_stack_arrays)]
|
||||
pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap {
|
||||
headers: [AFLppCmpLogHeader { data: [0; 8] }; CMPLOG_MAP_W],
|
||||
headers: [AFLppCmpLogHeader { data: [0; 2] }; CMPLOG_MAP_W],
|
||||
vals: AFLppCmpLogVals {
|
||||
operands: [[AFLppCmpLogOperands {
|
||||
v0: 0,
|
||||
@ -507,7 +502,7 @@ impl CmpMap for AFLppCmpLogMap {
|
||||
}
|
||||
|
||||
fn usable_executions_for(&self, idx: usize) -> usize {
|
||||
if self.headers[idx]._type() == AFL_CMP_TYPE_INS {
|
||||
if self.headers[idx]._type() == CMPLOG_KIND_INS {
|
||||
if self.executions_for(idx) < CMPLOG_MAP_H {
|
||||
self.executions_for(idx)
|
||||
} else {
|
||||
@ -521,7 +516,7 @@ impl CmpMap for AFLppCmpLogMap {
|
||||
}
|
||||
|
||||
fn values_of(&self, idx: usize, execution: usize) -> Option<CmpValues> {
|
||||
if self.headers[idx]._type() == AFL_CMP_TYPE_INS {
|
||||
if self.headers[idx]._type() == CMPLOG_KIND_INS {
|
||||
unsafe {
|
||||
match self.headers[idx].shape() {
|
||||
0 => Some(CmpValues::U8((
|
||||
@ -559,7 +554,7 @@ impl CmpMap for AFLppCmpLogMap {
|
||||
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
// For performance, we reset just the headers
|
||||
self.headers.fill(AFLppCmpLogHeader { data: [0; 8] });
|
||||
self.headers.fill(AFLppCmpLogHeader { data: [0; 2] });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "common.h"
|
||||
|
||||
#include "android-ashmem.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -39,6 +40,11 @@
|
||||
#define FS_ERROR_OLD_CMPLOG 32
|
||||
#define FS_ERROR_OLD_CMPLOG_QEMU 64
|
||||
|
||||
#define FS_NEW_VERSION_MAX 1
|
||||
#define FS_NEW_OPT_MAPSIZE 0x1
|
||||
#define FS_NEW_OPT_SHDMEM_FUZZ 0x2
|
||||
#define FS_NEW_OPT_AUTODICT 0x800
|
||||
|
||||
/* Reporting options */
|
||||
#define FS_OPT_ENABLED 0x80000001
|
||||
#define FS_OPT_MAPSIZE 0x40000000
|
||||
@ -219,48 +225,55 @@ void __afl_start_forkserver(void) {
|
||||
old_sigterm_handler = orig_action.sa_handler;
|
||||
signal(SIGTERM, at_exit);
|
||||
|
||||
uint8_t tmp[4] = {0, 0, 0, 0};
|
||||
uint32_t status_for_fsrv = 0;
|
||||
uint32_t already_read_first = 0;
|
||||
uint32_t was_killed;
|
||||
uint32_t version = 0x41464c00 + FS_NEW_VERSION_MAX;
|
||||
uint32_t tmp = version ^ 0xffffffff;
|
||||
uint32_t status = version;
|
||||
uint32_t status2 = version;
|
||||
|
||||
uint8_t *msg = (uint8_t *)&status;
|
||||
uint8_t *reply = (uint8_t *)&status2;
|
||||
|
||||
uint8_t child_stopped = 0;
|
||||
|
||||
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
|
||||
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
|
||||
}
|
||||
|
||||
int autodict_on = __token_start != NULL && __token_stop != NULL;
|
||||
if (autodict_on) { status_for_fsrv |= FS_OPT_AUTODICT; }
|
||||
|
||||
if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
|
||||
if (status_for_fsrv) { status_for_fsrv |= FS_OPT_ENABLED; }
|
||||
|
||||
memcpy(tmp, &status_for_fsrv, 4);
|
||||
|
||||
/* Phone home and tell the parent that we're OK. If parent isn't there,
|
||||
assume we're not running in forkserver mode and just execute program. */
|
||||
|
||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
|
||||
// return because possible non-forkserver usage
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
|
||||
|
||||
if (__afl_sharedmem_fuzzing || autodict_on) {
|
||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||
if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); }
|
||||
|
||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
|
||||
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||
map_input_shared_memory();
|
||||
if (tmp != status2) {
|
||||
write_error("wrong forkserver message from AFL++ tool");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
|
||||
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
|
||||
autodict_on) {
|
||||
// great lets pass the dictionary through the forkserver FD
|
||||
status = FS_NEW_OPT_MAPSIZE;
|
||||
if (__afl_sharedmem_fuzzing) { status |= FS_NEW_OPT_SHDMEM_FUZZ; }
|
||||
if (autodict_on) { status |= FS_NEW_OPT_AUTODICT; }
|
||||
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
|
||||
// Now send the parameters for the set options, increasing by option number
|
||||
|
||||
// FS_NEW_OPT_MAPSIZE - we always send the map size
|
||||
status = __afl_map_size;
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
|
||||
// FS_NEW_OPT_AUTODICT - send autodictionary
|
||||
if (autodict_on) {
|
||||
// pass the dictionary through the forkserver FD
|
||||
uint32_t len = (__token_stop - __token_start), offset = 0;
|
||||
|
||||
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
||||
write_error("could not send dictionary len");
|
||||
write(2, "Error: could not send dictionary len\n",
|
||||
strlen("Error: could not send dictionary len\n"));
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
@ -276,13 +289,13 @@ void __afl_start_forkserver(void) {
|
||||
len -= ret;
|
||||
offset += ret;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// uh this forkserver does not understand extended option passing
|
||||
// or does not want the dictionary
|
||||
if (!__afl_fuzz_ptr) already_read_first = 1;
|
||||
}
|
||||
}
|
||||
// send welcome message as final message
|
||||
status = version;
|
||||
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
|
||||
|
||||
if (__afl_sharedmem_fuzzing) { map_input_shared_memory(); }
|
||||
|
||||
while (1) {
|
||||
int status;
|
||||
|
Loading…
x
Reference in New Issue
Block a user