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_bolts = { path = "../../libafl_bolts/" }
|
||||||
libafl_cc = { path = "../../libafl_cc/" }
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer", "pointer_maps"] }
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer", "pointer_maps"] }
|
||||||
|
env_logger = "0.10"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "libforkserver_libafl_cc"
|
name = "libforkserver_libafl_cc"
|
||||||
|
@ -85,6 +85,8 @@ struct Opt {
|
|||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
const MAP_SIZE: usize = EDGES_MAP_SIZE_IN_USE; //65536;
|
const MAP_SIZE: usize = EDGES_MAP_SIZE_IN_USE; //65536;
|
||||||
let opt = Opt::parse();
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ codegen-units = 1
|
|||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
env_logger = "0.10"
|
||||||
libafl = { path = "../../libafl/", features = ["std", "derive"] }
|
libafl = { path = "../../libafl/", features = ["std", "derive"] }
|
||||||
libafl_bolts = { path = "../../libafl_bolts/" }
|
libafl_bolts = { path = "../../libafl_bolts/" }
|
||||||
clap = { version = "4.0", features = ["derive"] }
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
|
@ -85,6 +85,7 @@ struct Opt {
|
|||||||
|
|
||||||
#[allow(clippy::similar_names)]
|
#[allow(clippy::similar_names)]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
env_logger::init();
|
||||||
const MAP_SIZE: usize = 65536;
|
const MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
let opt = Opt::parse();
|
let opt = Opt::parse();
|
||||||
|
@ -48,24 +48,56 @@ use crate::{
|
|||||||
|
|
||||||
const FORKSRV_FD: i32 = 198;
|
const FORKSRV_FD: i32 = 198;
|
||||||
#[allow(clippy::cast_possible_wrap)]
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
const FS_OPT_ENABLED: i32 = 0x80000001_u32 as i32;
|
const FS_NEW_ERROR: i32 = 0xeffe0000_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;
|
|
||||||
|
|
||||||
// #[allow(clippy::cast_possible_wrap)]
|
const FS_NEW_VERSION_MIN: u32 = 1;
|
||||||
// const FS_OPT_MAX_MAPSIZE: i32 = ((0x00fffffe_u32 >> 1) + 1) as i32; // 8388608
|
const FS_NEW_VERSION_MAX: u32 = 1;
|
||||||
const fn fs_opt_get_mapsize(x: i32) -> i32 {
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
((x & 0x00fffffe) >> 1) + 1
|
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
|
/// The length of header bytes which tells shmem size
|
||||||
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
const SHMEM_FUZZ_HDR_SIZE: usize = 4;
|
||||||
@ -583,7 +615,6 @@ pub struct ForkserverExecutorBuilder<'a, SP> {
|
|||||||
shmem_provider: Option<&'a mut SP>,
|
shmem_provider: Option<&'a mut SP>,
|
||||||
max_input_size: usize,
|
max_input_size: usize,
|
||||||
map_size: Option<usize>,
|
map_size: Option<usize>,
|
||||||
real_map_size: i32,
|
|
||||||
kill_signal: Option<Signal>,
|
kill_signal: Option<Signal>,
|
||||||
timeout: Option<Duration>,
|
timeout: Option<Duration>,
|
||||||
#[cfg(feature = "regex")]
|
#[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 {
|
if rlen != 4 {
|
||||||
return Err(Error::unknown("Failed to start a forkserver".to_string()));
|
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 {
|
if (version_status & FS_NEW_ERROR) == FS_NEW_ERROR {
|
||||||
let mut map_size = fs_opt_get_mapsize(status);
|
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
|
// When 0, we assume that map_size was filled by the user or const
|
||||||
/* TODO autofill map size from the observer
|
/* 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);
|
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 {
|
if map_size % 64 != 0 {
|
||||||
map_size = ((map_size + 63) >> 6) << 6;
|
map_size = ((map_size + 63) >> 6) << 6;
|
||||||
}
|
}
|
||||||
@ -780,68 +855,57 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
|
|||||||
// TODO set AFL_MAP_SIZE
|
// TODO set AFL_MAP_SIZE
|
||||||
assert!(self.map_size.is_none() || map_size as usize <= self.map_size.unwrap());
|
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);
|
self.map_size = Some(map_size as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only with SHMEM or AUTODICT we can send send_status back or it breaks!
|
if status & FS_NEW_OPT_SHDMEM_FUZZ != 0 {
|
||||||
// If forkserver is responding, we then check if there's any option enabled.
|
if map.is_some() {
|
||||||
// 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() {
|
|
||||||
log::info!("Using SHARED MEMORY FUZZING feature.");
|
log::info!("Using SHARED MEMORY FUZZING feature.");
|
||||||
send_status |= FS_OPT_SHDMEM_FUZZ;
|
|
||||||
self.uses_shmem_testcase = true;
|
self.uses_shmem_testcase = true;
|
||||||
|
} else {
|
||||||
|
return Err(Error::unknown(
|
||||||
|
"Target requested sharedmem fuzzing, but you didn't prepare shmem",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(
|
||||||
|
"Failed to read dictionary size from forkserver".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & FS_OPT_AUTODICT == FS_OPT_AUTODICT) && self.autotokens.is_some() {
|
if !(2..=0xffffff).contains(&dict_size) {
|
||||||
log::info!("Using AUTODICT feature");
|
return Err(Error::illegal_state(
|
||||||
send_status |= FS_OPT_AUTODICT;
|
"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 send_status != FS_OPT_ENABLED {
|
if rlen != dict_size as usize {
|
||||||
// if send_status is not changed (Options are available but we didn't use any), then don't send the next write_ctl message.
|
return Err(Error::unknown("Failed to load autodictionary".to_string()));
|
||||||
// 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 {
|
|
||||||
let (read_len, dict_size) = forkserver.read_st()?;
|
|
||||||
if read_len != 4 {
|
|
||||||
return Err(Error::unknown(
|
|
||||||
"Reading from forkserver failed.".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(2..=0xffffff).contains(&dict_size) {
|
|
||||||
return Err(Error::illegal_state(
|
|
||||||
"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 {
|
|
||||||
return Err(Error::unknown("Failed to load autodictionary".to_string()));
|
|
||||||
}
|
|
||||||
if let Some(t) = &mut self.autotokens {
|
|
||||||
t.parse_autodict(&buf, dict_size as usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
if let Some(t) = &mut self.autotokens {
|
||||||
log::warn!("Forkserver Options are not available.");
|
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()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if aflx != version_status {
|
||||||
|
return Err(Error::unknown(format!(
|
||||||
|
"Error in forkserver communication ({:x}=>{:x})",
|
||||||
|
keep, aflx
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((forkserver, input_file, map))
|
Ok((forkserver, input_file, map))
|
||||||
@ -1066,7 +1130,6 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
|||||||
input_filename: None,
|
input_filename: None,
|
||||||
shmem_provider: None,
|
shmem_provider: None,
|
||||||
map_size: None,
|
map_size: None,
|
||||||
real_map_size: 0,
|
|
||||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||||
kill_signal: None,
|
kill_signal: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
@ -1093,7 +1156,6 @@ impl<'a> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
|
|||||||
input_filename: self.input_filename,
|
input_filename: self.input_filename,
|
||||||
shmem_provider: Some(shmem_provider),
|
shmem_provider: Some(shmem_provider),
|
||||||
map_size: self.map_size,
|
map_size: self.map_size,
|
||||||
real_map_size: self.real_map_size,
|
|
||||||
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
max_input_size: MAX_INPUT_SIZE_DEFAULT,
|
||||||
kill_signal: None,
|
kill_signal: None,
|
||||||
timeout: None,
|
timeout: None,
|
||||||
|
@ -516,12 +516,10 @@ impl AFLppCmpValuesMetadata {
|
|||||||
/// - reserved: Reserved for future use
|
/// - reserved: Reserved for future use
|
||||||
pub struct AFLppCmpLogHeader {
|
pub struct AFLppCmpLogHeader {
|
||||||
/// The header values
|
/// The header values
|
||||||
#[bitfield(name = "hits", ty = "u32", bits = "0..=23")]
|
#[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 = "id", ty = "u32", bits = "24..=47")]
|
#[bitfield(name = "shape", ty = "u32", bits = "6..=10")] // 31 + 1 bytes max
|
||||||
#[bitfield(name = "shape", ty = "u32", bits = "48..=52")]
|
#[bitfield(name = "_type", ty = "u8", bits = "11..=11")] // 2: cmp, rtn
|
||||||
#[bitfield(name = "_type", ty = "u32", bits = "53..=54")]
|
#[bitfield(name = "attribute", ty = "u32", bits = "12..=15")]
|
||||||
#[bitfield(name = "attribute", ty = "u32", bits = "55..=58")]
|
// 16 types for arithmetic comparison types
|
||||||
#[bitfield(name = "overflow", ty = "u32", bits = "59..=59")]
|
pub data: [u8; 2],
|
||||||
#[bitfield(name = "reserved", ty = "u32", bits = "60..=63")]
|
|
||||||
pub data: [u8; 8],
|
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,6 @@
|
|||||||
#define CMPLOG_KIND_INS 0
|
#define CMPLOG_KIND_INS 0
|
||||||
#define CMPLOG_KIND_RTN 1
|
#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 {
|
typedef struct CmpLogHeader {
|
||||||
uint16_t hits;
|
uint16_t hits;
|
||||||
uint8_t shape;
|
uint8_t shape;
|
||||||
@ -39,23 +35,17 @@ typedef struct CmpLogHeader {
|
|||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
typedef struct CmpLogHeaderExtended {
|
typedef struct CmpLogHeaderExtended {
|
||||||
unsigned hits : 24;
|
unsigned hits : 6;
|
||||||
unsigned id : 24;
|
|
||||||
unsigned shape : 5;
|
unsigned shape : 5;
|
||||||
unsigned type : 2;
|
unsigned type : 1;
|
||||||
unsigned attribute : 4;
|
unsigned attribute : 4;
|
||||||
unsigned overflow : 1;
|
|
||||||
unsigned reserved : 4;
|
|
||||||
} __attribute__((packed)) CmpLogHeaderExtended;
|
} __attribute__((packed)) CmpLogHeaderExtended;
|
||||||
#else
|
#else
|
||||||
__pragma(pack(push, 1)) typedef struct CmpLogHeaderExtended {
|
__pragma(pack(push, 1)) typedef struct CmpLogHeaderExtended {
|
||||||
unsigned hits : 24;
|
unsigned hits : 6;
|
||||||
unsigned id : 24;
|
|
||||||
unsigned shape : 5;
|
unsigned shape : 5;
|
||||||
unsigned type : 2;
|
unsigned type : 1;
|
||||||
unsigned attribute : 4;
|
unsigned attribute : 4;
|
||||||
unsigned overflow : 1;
|
|
||||||
unsigned reserved : 4;
|
|
||||||
} CmpLogHeaderExtended;
|
} CmpLogHeaderExtended;
|
||||||
__pragma(pack(pop))
|
__pragma(pack(pop))
|
||||||
#endif
|
#endif
|
||||||
@ -146,8 +136,8 @@ static inline void cmplog_instructions_extended_checked(
|
|||||||
|
|
||||||
// printf("%ld %ld %ld\n", k, arg1, arg2);
|
// printf("%ld %ld %ld\n", k, arg1, arg2);
|
||||||
uint16_t hits;
|
uint16_t hits;
|
||||||
if (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 = AFL_CMP_TYPE_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].hits = 1;
|
||||||
libafl_cmplog_map_extended_ptr->headers[k].shape = shape;
|
libafl_cmplog_map_extended_ptr->headers[k].shape = shape;
|
||||||
hits = 0;
|
hits = 0;
|
||||||
@ -207,8 +197,8 @@ static inline void cmplog_routines_checked_extended(uintptr_t k,
|
|||||||
libafl_cmplog_enabled = false;
|
libafl_cmplog_enabled = false;
|
||||||
uint32_t hits;
|
uint32_t hits;
|
||||||
// printf("RTN: %ld %ld %ld %ld\n", k, *ptr1, *ptr2, len);
|
// printf("RTN: %ld %ld %ld %ld\n", k, *ptr1, *ptr2, len);
|
||||||
if (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 = AFL_CMP_TYPE_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].hits = 1;
|
||||||
libafl_cmplog_map_extended_ptr->headers[k].shape = len;
|
libafl_cmplog_map_extended_ptr->headers[k].shape = len;
|
||||||
hits = 0;
|
hits = 0;
|
||||||
|
@ -41,11 +41,6 @@ pub const CMPLOG_KIND_INS: u8 = 0;
|
|||||||
/// `CmpLog` routine kind
|
/// `CmpLog` routine kind
|
||||||
pub const CMPLOG_KIND_RTN: u8 = 1;
|
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
|
// EXTERNS, GLOBALS
|
||||||
|
|
||||||
#[cfg(feature = "cmplog")]
|
#[cfg(feature = "cmplog")]
|
||||||
@ -415,7 +410,7 @@ pub static mut libafl_cmplog_map: CmpLogMap = CmpLogMap {
|
|||||||
#[cfg(feature = "cmplog_extended_instrumentation")]
|
#[cfg(feature = "cmplog_extended_instrumentation")]
|
||||||
#[allow(clippy::large_stack_arrays)]
|
#[allow(clippy::large_stack_arrays)]
|
||||||
pub static mut libafl_cmplog_map_extended: AFLppCmpLogMap = AFLppCmpLogMap {
|
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 {
|
vals: AFLppCmpLogVals {
|
||||||
operands: [[AFLppCmpLogOperands {
|
operands: [[AFLppCmpLogOperands {
|
||||||
v0: 0,
|
v0: 0,
|
||||||
@ -507,7 +502,7 @@ impl CmpMap for AFLppCmpLogMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn usable_executions_for(&self, idx: usize) -> usize {
|
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 {
|
if self.executions_for(idx) < CMPLOG_MAP_H {
|
||||||
self.executions_for(idx)
|
self.executions_for(idx)
|
||||||
} else {
|
} else {
|
||||||
@ -521,7 +516,7 @@ impl CmpMap for AFLppCmpLogMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn values_of(&self, idx: usize, execution: usize) -> Option<CmpValues> {
|
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 {
|
unsafe {
|
||||||
match self.headers[idx].shape() {
|
match self.headers[idx].shape() {
|
||||||
0 => Some(CmpValues::U8((
|
0 => Some(CmpValues::U8((
|
||||||
@ -559,7 +554,7 @@ impl CmpMap for AFLppCmpLogMap {
|
|||||||
|
|
||||||
fn reset(&mut self) -> Result<(), Error> {
|
fn reset(&mut self) -> Result<(), Error> {
|
||||||
// For performance, we reset just the headers
|
// For performance, we reset just the headers
|
||||||
self.headers.fill(AFLppCmpLogHeader { data: [0; 8] });
|
self.headers.fill(AFLppCmpLogHeader { data: [0; 2] });
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include "android-ashmem.h"
|
#include "android-ashmem.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -39,6 +40,11 @@
|
|||||||
#define FS_ERROR_OLD_CMPLOG 32
|
#define FS_ERROR_OLD_CMPLOG 32
|
||||||
#define FS_ERROR_OLD_CMPLOG_QEMU 64
|
#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 */
|
/* Reporting options */
|
||||||
#define FS_OPT_ENABLED 0x80000001
|
#define FS_OPT_ENABLED 0x80000001
|
||||||
#define FS_OPT_MAPSIZE 0x40000000
|
#define FS_OPT_MAPSIZE 0x40000000
|
||||||
@ -219,71 +225,78 @@ void __afl_start_forkserver(void) {
|
|||||||
old_sigterm_handler = orig_action.sa_handler;
|
old_sigterm_handler = orig_action.sa_handler;
|
||||||
signal(SIGTERM, at_exit);
|
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 already_read_first = 0;
|
||||||
uint32_t was_killed;
|
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;
|
uint8_t child_stopped = 0;
|
||||||
|
|
||||||
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
|
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;
|
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,
|
/* 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. */
|
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, reply, 4) != 4) { _exit(1); }
|
||||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
|
||||||
|
|
||||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
|
if (tmp != status2) {
|
||||||
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
write_error("wrong forkserver message from AFL++ tool");
|
||||||
map_input_shared_memory();
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(2, "Error: could not send dictionary len\n",
|
||||||
|
strlen("Error: could not send dictionary len\n"));
|
||||||
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
|
while (len != 0) {
|
||||||
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
|
int32_t ret;
|
||||||
autodict_on) {
|
ret = write(FORKSRV_FD + 1, __token_start + offset, len);
|
||||||
// great lets pass the dictionary through the forkserver FD
|
|
||||||
uint32_t len = (__token_stop - __token_start), offset = 0;
|
|
||||||
|
|
||||||
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
if (ret < 1) {
|
||||||
write_error("could not send dictionary len");
|
write_error("could not send dictionary");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len != 0) {
|
len -= ret;
|
||||||
int32_t ret;
|
offset += ret;
|
||||||
ret = write(FORKSRV_FD + 1, __token_start + offset, len);
|
|
||||||
|
|
||||||
if (ret < 1) {
|
|
||||||
write_error("could not send dictionary");
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
while (1) {
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user