* forkserver: Add an API to setup the shared memory region for edge coverage This is inspired from and meant to be similar to afl-cc's instrumentation. Remove ! return type from __afl_start_forkserver as it returns in several cases. * Add example fuzzer using LibAFL's forkserver The fuzzer is instrumented with libafl_cc as well. Co-authored-by: ergrelet <ergrelet@users.noreply.github.com>
This commit is contained in:
parent
676a149497
commit
3e38862837
32
fuzzers/forkserver_libafl_cc/Cargo.toml
Normal file
32
fuzzers/forkserver_libafl_cc/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "forkserver_libafl_cc"
|
||||||
|
version = "0.8.2"
|
||||||
|
authors = ["ergrelet <ergrelet@users.noreply.github.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
# Forces a crash
|
||||||
|
crash = []
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
which = { version = "4.0.2" }
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/", features = ["default"] }
|
||||||
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
|
nix = "0.25"
|
||||||
|
libafl_targets = { path = "../../libafl_targets/" }
|
||||||
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "libforkserver_libafl_cc"
|
||||||
|
crate-type = ["staticlib"]
|
115
fuzzers/forkserver_libafl_cc/Makefile.toml
Normal file
115
fuzzers/forkserver_libafl_cc/Makefile.toml
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# Variables
|
||||||
|
[env]
|
||||||
|
FUZZER_NAME='fuzzer_libafl_cc'
|
||||||
|
CARGO_TARGET_DIR = { value = "${PROJECT_DIR}/target", condition = { env_not_set = ["CARGO_TARGET_DIR"] } }
|
||||||
|
LIBAFL_CC = '${CARGO_TARGET_DIR}/release/libafl_cc'
|
||||||
|
LIBAFL_CXX = '${CARGO_TARGET_DIR}/release/libafl_cxx'
|
||||||
|
FUZZER = '${CARGO_TARGET_DIR}/release/${FUZZER_NAME}'
|
||||||
|
PROJECT_DIR = { script = ["pwd"] }
|
||||||
|
|
||||||
|
[tasks.unsupported]
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
echo "Cargo-make not integrated yet on this"
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Compilers
|
||||||
|
[tasks.cxx]
|
||||||
|
linux_alias = "cxx_unix"
|
||||||
|
mac_alias = "cxx_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.cxx_unix]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["build" , "--release"]
|
||||||
|
|
||||||
|
[tasks.cc]
|
||||||
|
linux_alias = "cc_unix"
|
||||||
|
mac_alias = "cc_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.cc_unix]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["build" , "--release"]
|
||||||
|
|
||||||
|
[tasks.crash_cxx]
|
||||||
|
linux_alias = "crash_cxx_unix"
|
||||||
|
mac_alias = "crash_cxx_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.crash_cxx_unix]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["build" , "--release", "--features=crash"]
|
||||||
|
|
||||||
|
[tasks.crash_cc]
|
||||||
|
linux_alias = "crash_cc_unix"
|
||||||
|
mac_alias = "crash_cc_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.crash_cc_unix]
|
||||||
|
command = "cargo"
|
||||||
|
args = ["build" , "--release", "--features=crash"]
|
||||||
|
|
||||||
|
# Harness
|
||||||
|
[tasks.fuzzer]
|
||||||
|
linux_alias = "fuzzer_unix"
|
||||||
|
mac_alias = "fuzzer_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.fuzzer_unix]
|
||||||
|
command = "${CARGO_TARGET_DIR}/release/libafl_cc"
|
||||||
|
args = ["${PROJECT_DIR}/src/program.c", "-o", "${FUZZER_NAME}", "-lm"]
|
||||||
|
dependencies = [ "cxx", "cc" ]
|
||||||
|
|
||||||
|
# Crashing Harness
|
||||||
|
[tasks.fuzzer_crash]
|
||||||
|
linux_alias = "fuzzer_crash_unix"
|
||||||
|
mac_alias = "fuzzer_crash_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.fuzzer_crash_unix]
|
||||||
|
command = "${CARGO_TARGET_DIR}/release/libafl_cc"
|
||||||
|
args = ["${PROJECT_DIR}/src/program.c", "-o", "${FUZZER_NAME}_crash", "-lm"]
|
||||||
|
dependencies = [ "crash_cxx", "crash_cc" ]
|
||||||
|
|
||||||
|
# Run the fuzzer
|
||||||
|
[tasks.run]
|
||||||
|
linux_alias = "run_unix"
|
||||||
|
mac_alias = "run_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.run_unix]
|
||||||
|
script_runner = "@shell"
|
||||||
|
script='''
|
||||||
|
taskset -c 1 ${CARGO_TARGET_DIR}/release/${CARGO_MAKE_PROJECT_NAME} ./${FUZZER_NAME} ./corpus/ -t 1000
|
||||||
|
'''
|
||||||
|
dependencies = [ "fuzzer" ]
|
||||||
|
|
||||||
|
|
||||||
|
# Run the fuzzer with a crash
|
||||||
|
[tasks.crash]
|
||||||
|
linux_alias = "crash_unix"
|
||||||
|
mac_alias = "crash_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.crash_unix]
|
||||||
|
script_runner = "@shell"
|
||||||
|
script='''
|
||||||
|
taskset -c 1 ${CARGO_TARGET_DIR}/release/${CARGO_MAKE_PROJECT_NAME} ./${FUZZER_NAME}_crash ./corpus/ -t 1000
|
||||||
|
'''
|
||||||
|
dependencies = [ "fuzzer_crash" ]
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
[tasks.clean]
|
||||||
|
linux_alias = "clean_unix"
|
||||||
|
mac_alias = "clean_unix"
|
||||||
|
windows_alias = "unsupported"
|
||||||
|
|
||||||
|
[tasks.clean_unix]
|
||||||
|
# Disable default `clean` definition
|
||||||
|
clear = true
|
||||||
|
script_runner="@shell"
|
||||||
|
script='''
|
||||||
|
rm -f ./${FUZZER_NAME}
|
||||||
|
cargo clean
|
||||||
|
'''
|
13
fuzzers/forkserver_libafl_cc/README.md
Normal file
13
fuzzers/forkserver_libafl_cc/README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Simple Forkserver Fuzzer
|
||||||
|
|
||||||
|
This is a simple example fuzzer to fuzz an executable instrumented by libafl_cc.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
You can build this example by running `cargo make fuzzer`.
|
||||||
|
This compiles, libafl_cc, the fuzzer and the example harness program in
|
||||||
|
`src/program.c` with libafl_cc.
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
You can run this example by running `cargo make run`.
|
1
fuzzers/forkserver_libafl_cc/corpus/testfile
Normal file
1
fuzzers/forkserver_libafl_cc/corpus/testfile
Normal file
@ -0,0 +1 @@
|
|||||||
|
aaa
|
45
fuzzers/forkserver_libafl_cc/src/bin/libafl_cc.rs
Normal file
45
fuzzers/forkserver_libafl_cc/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
|
"cc" => false,
|
||||||
|
"++" | "pp" | "xx" => true,
|
||||||
|
_ => panic!("Could not figure out if c or c++ wrapper was called. Expected {dir:?} to end with c or cxx"),
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.pop();
|
||||||
|
|
||||||
|
let mut cc = ClangWrapper::new();
|
||||||
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
|
.parse_args(&args)
|
||||||
|
.expect("Failed to parse the command line")
|
||||||
|
// Enable libafl's coverage instrumentation
|
||||||
|
.add_pass(LLVMPasses::AFLCoverage)
|
||||||
|
.add_arg("-mllvm")
|
||||||
|
.add_arg("-ctx") // Context sensitive coverage
|
||||||
|
// Imitate afl-cc's compile definitions
|
||||||
|
.add_arg("-D__AFL_FUZZ_INIT()=int __afl_sharedmem_fuzzing = 1;extern unsigned int *__afl_fuzz_len;extern unsigned char *__afl_fuzz_ptr;unsigned char __afl_fuzz_alt[1048576];unsigned char *__afl_fuzz_alt_ptr = __afl_fuzz_alt;void libafl_start_forkserver(void)")
|
||||||
|
.add_arg("-D__AFL_FUZZ_TESTCASE_BUF=(__afl_fuzz_ptr ? __afl_fuzz_ptr : __afl_fuzz_alt_ptr)")
|
||||||
|
.add_arg("-D__AFL_FUZZ_TESTCASE_LEN=(__afl_fuzz_ptr ? *__afl_fuzz_len : (*__afl_fuzz_len = read(0, __afl_fuzz_alt_ptr, 1048576)) == 0xffffffff ? 0 : *__afl_fuzz_len)")
|
||||||
|
.add_arg("-D__AFL_INIT()=libafl_start_forkserver()")
|
||||||
|
// Link with libafl's forkserver implementation
|
||||||
|
.link_staticlib(&dir, "libforkserver_libafl_cc")
|
||||||
|
.run()
|
||||||
|
.expect("Failed to run the wrapped compiler")
|
||||||
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("LibAFL CC: No Arguments given");
|
||||||
|
}
|
||||||
|
}
|
5
fuzzers/forkserver_libafl_cc/src/bin/libafl_cxx.rs
Normal file
5
fuzzers/forkserver_libafl_cc/src/bin/libafl_cxx.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
pub mod libafl_cc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
libafl_cc::main();
|
||||||
|
}
|
9
fuzzers/forkserver_libafl_cc/src/lib.rs
Normal file
9
fuzzers/forkserver_libafl_cc/src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use libafl_targets::{map_shared_memory, start_forkserver};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn libafl_start_forkserver() {
|
||||||
|
// Map shared memory region for the edge coverage map
|
||||||
|
map_shared_memory();
|
||||||
|
// Start the forkserver
|
||||||
|
start_forkserver();
|
||||||
|
}
|
215
fuzzers/forkserver_libafl_cc/src/main.rs
Normal file
215
fuzzers/forkserver_libafl_cc/src/main.rs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
use core::time::Duration;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use clap::{self, Parser};
|
||||||
|
use libafl::{
|
||||||
|
bolts::{
|
||||||
|
current_nanos,
|
||||||
|
rands::StdRand,
|
||||||
|
shmem::{ShMem, ShMemProvider, UnixShMemProvider},
|
||||||
|
tuples::{tuple_list, MatchName, Merge},
|
||||||
|
AsMutSlice,
|
||||||
|
},
|
||||||
|
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
|
||||||
|
events::SimpleEventManager,
|
||||||
|
executors::{
|
||||||
|
forkserver::{ForkserverExecutor, TimeoutForkserverExecutor},
|
||||||
|
HasObservers,
|
||||||
|
},
|
||||||
|
feedback_and_fast, feedback_or,
|
||||||
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
|
inputs::BytesInput,
|
||||||
|
monitors::SimpleMonitor,
|
||||||
|
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
|
||||||
|
observers::{HitcountsMapObserver, MapObserver, StdMapObserver, TimeObserver},
|
||||||
|
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
|
||||||
|
stages::mutational::StdMutationalStage,
|
||||||
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
|
};
|
||||||
|
use nix::sys::signal::Signal;
|
||||||
|
|
||||||
|
/// The commandline args this fuzzer accepts
|
||||||
|
#[derive(Debug, Parser)]
|
||||||
|
#[command(
|
||||||
|
name = "forkserver_libafl_cc",
|
||||||
|
about = "This is a simple example fuzzer to fuzz a executable instrumented by libafl_cc.",
|
||||||
|
author = "ergrelet <ergrelet@users.noreply.github.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[arg(
|
||||||
|
help = "The instrumented binary we want to fuzz",
|
||||||
|
name = "EXEC",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
executable: String,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
help = "The directory to read initial inputs from ('seeds')",
|
||||||
|
name = "INPUT_DIR",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
in_dir: PathBuf,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
help = "Timeout for each individual execution, in milliseconds",
|
||||||
|
short = 't',
|
||||||
|
long = "timeout",
|
||||||
|
default_value = "1200"
|
||||||
|
)]
|
||||||
|
timeout: u64,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
help = "If not set, the child's stdout and stderror will be redirected to /dev/null",
|
||||||
|
short = 'd',
|
||||||
|
long = "debug-child",
|
||||||
|
default_value = "false"
|
||||||
|
)]
|
||||||
|
debug_child: bool,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
help = "Arguments passed to the target",
|
||||||
|
name = "arguments",
|
||||||
|
num_args(1..),
|
||||||
|
allow_hyphen_values = true,
|
||||||
|
)]
|
||||||
|
arguments: Vec<String>,
|
||||||
|
|
||||||
|
#[arg(
|
||||||
|
help = "Signal used to stop child",
|
||||||
|
short = 's',
|
||||||
|
long = "signal",
|
||||||
|
value_parser = str::parse::<Signal>,
|
||||||
|
default_value = "SIGKILL"
|
||||||
|
)]
|
||||||
|
signal: Signal,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::similar_names)]
|
||||||
|
pub fn main() {
|
||||||
|
const MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
let corpus_dirs: Vec<PathBuf> = [opt.in_dir].to_vec();
|
||||||
|
|
||||||
|
// The unix shmem provider supported by LibAFL for shared memory
|
||||||
|
let mut shmem_provider = UnixShMemProvider::new().unwrap();
|
||||||
|
|
||||||
|
// The coverage map shared between observer and executor
|
||||||
|
let mut shmem = shmem_provider.new_shmem(MAP_SIZE).unwrap();
|
||||||
|
// let the forkserver know the shmid
|
||||||
|
shmem.write_to_env("__AFL_SHM_ID").unwrap();
|
||||||
|
let shmem_buf = shmem.as_mut_slice();
|
||||||
|
|
||||||
|
// Create an observation channel using the signals map
|
||||||
|
let edges_observer =
|
||||||
|
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) };
|
||||||
|
|
||||||
|
// Create an observation channel to keep track of the execution time
|
||||||
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
|
// Feedback to rate the interestingness of an input
|
||||||
|
// This one is composed by two Feedbacks in OR
|
||||||
|
let mut feedback = feedback_or!(
|
||||||
|
// New maximization map feedback linked to the edges observer and the feedback state
|
||||||
|
MaxMapFeedback::new_tracking(&edges_observer, true, false),
|
||||||
|
// Time feedback, this one does not need a feedback state
|
||||||
|
TimeFeedback::new_with_observer(&time_observer)
|
||||||
|
);
|
||||||
|
|
||||||
|
// A feedback to choose if an input is a solution or not
|
||||||
|
// We want to do the same crash deduplication that AFL does
|
||||||
|
let mut objective = feedback_and_fast!(
|
||||||
|
// Must be a crash
|
||||||
|
CrashFeedback::new(),
|
||||||
|
// Take it onlt if trigger new coverage over crashes
|
||||||
|
MaxMapFeedback::new(&edges_observer)
|
||||||
|
);
|
||||||
|
|
||||||
|
// create a State from scratch
|
||||||
|
let mut state = StdState::new(
|
||||||
|
// RNG
|
||||||
|
StdRand::with_seed(current_nanos()),
|
||||||
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
|
InMemoryCorpus::<BytesInput>::new(),
|
||||||
|
// Corpus in which we store solutions (crashes in this example),
|
||||||
|
// on disk so the user can get them after stopping the fuzzer
|
||||||
|
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
|
||||||
|
// States of the feedbacks.
|
||||||
|
// The feedbacks can report the data that should persist in the State.
|
||||||
|
&mut feedback,
|
||||||
|
// Same for objective feedbacks
|
||||||
|
&mut objective,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// The Monitor trait define how the fuzzer stats are reported to the user
|
||||||
|
let monitor = SimpleMonitor::new(|s| println!("{s}"));
|
||||||
|
|
||||||
|
// The event manager handle the various events generated during the fuzzing loop
|
||||||
|
// such as the notification of the addition of a new item to the corpus
|
||||||
|
let mut mgr = SimpleEventManager::new(monitor);
|
||||||
|
|
||||||
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
|
||||||
|
|
||||||
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
|
// If we should debug the child
|
||||||
|
let debug_child = opt.debug_child;
|
||||||
|
|
||||||
|
// Create the executor for the forkserver
|
||||||
|
let args = opt.arguments;
|
||||||
|
|
||||||
|
let mut tokens = Tokens::new();
|
||||||
|
let mut forkserver = ForkserverExecutor::builder()
|
||||||
|
.program(opt.executable)
|
||||||
|
.debug_child(debug_child)
|
||||||
|
.shmem_provider(&mut shmem_provider)
|
||||||
|
.autotokens(&mut tokens)
|
||||||
|
.parse_afl_cmdline(args)
|
||||||
|
.coverage_map_size(MAP_SIZE)
|
||||||
|
.build(tuple_list!(time_observer, edges_observer))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(dynamic_map_size) = forkserver.coverage_map_size() {
|
||||||
|
forkserver
|
||||||
|
.observers_mut()
|
||||||
|
.match_name_mut::<HitcountsMapObserver<StdMapObserver<'_, u8, false>>>("shared_mem")
|
||||||
|
.unwrap()
|
||||||
|
.downsize_map(dynamic_map_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut executor = TimeoutForkserverExecutor::with_signal(
|
||||||
|
forkserver,
|
||||||
|
Duration::from_millis(opt.timeout),
|
||||||
|
opt.signal,
|
||||||
|
)
|
||||||
|
.expect("Failed to create the executor.");
|
||||||
|
|
||||||
|
// In case the corpus is empty (on first run), reset
|
||||||
|
if state.corpus().count() < 1 {
|
||||||
|
state
|
||||||
|
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs)
|
||||||
|
.unwrap_or_else(|err| {
|
||||||
|
panic!(
|
||||||
|
"Failed to load initial corpus at {:?}: {:?}",
|
||||||
|
&corpus_dirs, err
|
||||||
|
)
|
||||||
|
});
|
||||||
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.add_metadata(tokens);
|
||||||
|
|
||||||
|
// Setup a mutational stage with a basic bytes mutator
|
||||||
|
let mutator =
|
||||||
|
StdScheduledMutator::with_max_stack_pow(havoc_mutations().merge(tokens_mutations()), 6);
|
||||||
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
|
fuzzer
|
||||||
|
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
|
||||||
|
.expect("Error in the fuzzing loop");
|
||||||
|
}
|
37
fuzzers/forkserver_libafl_cc/src/program.c
Normal file
37
fuzzers/forkserver_libafl_cc/src/program.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// The following line is needed for shared memory testcase fuzzing
|
||||||
|
__AFL_FUZZ_INIT();
|
||||||
|
|
||||||
|
void vuln(char *buf) {
|
||||||
|
if (strcmp(buf, "vuln") == 0) { abort(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
// Start the forkserver at this point (i.e., forks will happen here)
|
||||||
|
__AFL_INIT();
|
||||||
|
|
||||||
|
// The following five lines are for normal fuzzing.
|
||||||
|
/*
|
||||||
|
FILE *file = stdin;
|
||||||
|
if (argc > 1) { file = fopen(argv[1], "rb"); }
|
||||||
|
char buf[16];
|
||||||
|
char *p = fgets(buf, 16, file);
|
||||||
|
buf[15] = 0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The following line is also needed for shared memory testcase fuzzing
|
||||||
|
unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF; // must be after __AFL_INIT
|
||||||
|
|
||||||
|
// printf("input: %s\n", buf);
|
||||||
|
if (buf[0] == 'b') {
|
||||||
|
if (buf[1] == 'a') {
|
||||||
|
if (buf[2] == 'd') { abort(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vuln((char *)buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -7,17 +7,24 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#ifndef USEMMAP
|
#ifndef USEMMAP
|
||||||
#include <sys/shm.h>
|
#include <sys/shm.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define write_error(s) fprintf(stderr, "Error at %s:%d: %s\n", __FILE__, __LINE__, s)
|
#define write_error(s) \
|
||||||
|
fprintf(stderr, "Error at %s:%d: %s\n", __FILE__, __LINE__, s)
|
||||||
|
|
||||||
// AFL++ constants
|
// AFL++ constants
|
||||||
#define FORKSRV_FD 198
|
#define FORKSRV_FD 198
|
||||||
#define MAX_FILE (1024 * 1024)
|
#define MAX_FILE (1024 * 1024)
|
||||||
#define SHMEM_FUZZ_HDR_SIZE 4
|
#define SHMEM_FUZZ_HDR_SIZE 4
|
||||||
|
#define SHM_ENV_VAR "__AFL_SHM_ID"
|
||||||
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
#define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID"
|
||||||
|
#define DEFAULT_PERMISSION 0600
|
||||||
|
|
||||||
/* Reporting errors */
|
/* Reporting errors */
|
||||||
#define FS_OPT_ERROR 0xf800008f
|
#define FS_OPT_ERROR 0xf800008f
|
||||||
@ -45,18 +52,21 @@
|
|||||||
#define FS_OPT_SET_MAPSIZE(x) \
|
#define FS_OPT_SET_MAPSIZE(x) \
|
||||||
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
(x <= 1 || x > FS_OPT_MAX_MAPSIZE ? 0 : ((x - 1) << 1))
|
||||||
|
|
||||||
// Set by this macro https://github.com/AFLplusplus/AFLplusplus/blob/stable/src/afl-cc.c#L993
|
// Set by this macro
|
||||||
|
// https://github.com/AFLplusplus/AFLplusplus/blob/stable/src/afl-cc.c#L993
|
||||||
|
|
||||||
int __afl_sharedmem_fuzzing __attribute__((weak));
|
int __afl_sharedmem_fuzzing __attribute__((weak));
|
||||||
|
|
||||||
extern size_t __afl_map_size;
|
extern uint8_t *__afl_area_ptr;
|
||||||
extern uint8_t* __token_start;
|
extern size_t __afl_map_size;
|
||||||
extern uint8_t* __token_stop;
|
extern uint8_t *__token_start;
|
||||||
|
extern uint8_t *__token_stop;
|
||||||
|
|
||||||
uint8_t* __afl_fuzz_ptr;
|
uint8_t *__afl_fuzz_ptr;
|
||||||
static uint32_t __afl_fuzz_len_local;
|
static uint32_t __afl_fuzz_len_local;
|
||||||
uint32_t* __afl_fuzz_len = &__afl_fuzz_len_local;
|
uint32_t *__afl_fuzz_len = &__afl_fuzz_len_local;
|
||||||
|
|
||||||
|
int already_initialized_shm;
|
||||||
int already_initialized_forkserver;
|
int already_initialized_forkserver;
|
||||||
|
|
||||||
static int child_pid;
|
static int child_pid;
|
||||||
@ -65,48 +75,98 @@ static void (*old_sigterm_handler)(int) = 0;
|
|||||||
static uint8_t is_persistent;
|
static uint8_t is_persistent;
|
||||||
|
|
||||||
void __afl_set_persistent_mode(uint8_t mode) {
|
void __afl_set_persistent_mode(uint8_t mode) {
|
||||||
|
|
||||||
is_persistent = mode;
|
is_persistent = mode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Error reporting to forkserver controller */
|
/* Error reporting to forkserver controller */
|
||||||
|
|
||||||
static void send_forkserver_error(int error) {
|
static void send_forkserver_error(int error) {
|
||||||
|
|
||||||
uint32_t status;
|
uint32_t status;
|
||||||
if (!error || error > 0xffff) return;
|
if (!error || error > 0xffff) return;
|
||||||
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error));
|
||||||
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
|
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure we kill the child on termination */
|
/* Ensure we kill the child on termination */
|
||||||
|
|
||||||
static void at_exit(int signal) {
|
static void at_exit(int signal) {
|
||||||
|
|
||||||
(void)signal;
|
(void)signal;
|
||||||
|
|
||||||
if (child_pid > 0) {
|
if (child_pid > 0) {
|
||||||
|
|
||||||
kill(child_pid, SIGKILL);
|
kill(child_pid, SIGKILL);
|
||||||
child_pid = -1;
|
child_pid = -1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_exit(0);
|
_exit(0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHM fuzzing setup. */
|
/* SHM fuzzing setup. */
|
||||||
|
|
||||||
static void map_input_shared_memory() {
|
void __afl_map_shm(void) {
|
||||||
|
if (already_initialized_shm) return;
|
||||||
|
already_initialized_shm = 1;
|
||||||
|
|
||||||
|
char *id_str = getenv(SHM_ENV_VAR);
|
||||||
|
|
||||||
|
if (id_str) {
|
||||||
|
#ifdef USEMMAP
|
||||||
|
const char *shm_file_path = id_str;
|
||||||
|
int shm_fd = -1;
|
||||||
|
unsigned char *shm_base = NULL;
|
||||||
|
|
||||||
|
/* create the shared memory segment as if it was a file */
|
||||||
|
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||||
|
if (shm_fd == -1) {
|
||||||
|
fprintf(stderr, "shm_open() failed\n");
|
||||||
|
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
shm_base =
|
||||||
|
mmap(0, __afl_map_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
|
||||||
|
|
||||||
|
close(shm_fd);
|
||||||
|
shm_fd = -1;
|
||||||
|
|
||||||
|
if (shm_base == MAP_FAILED) {
|
||||||
|
fprintf(stderr, "mmap() failed\n");
|
||||||
|
perror("mmap for map");
|
||||||
|
send_forkserver_error(FS_ERROR_MMAP);
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
__afl_area_ptr = shm_base;
|
||||||
|
#else
|
||||||
|
uint32_t shm_id = atoi(id_str);
|
||||||
|
__afl_area_ptr = (uint8_t *)shmat(shm_id, NULL, 0);
|
||||||
|
|
||||||
|
/* Whooooops. */
|
||||||
|
|
||||||
|
if (!__afl_area_ptr || __afl_area_ptr == (void *)-1) {
|
||||||
|
send_forkserver_error(FS_ERROR_SHMAT);
|
||||||
|
perror("shmat for map");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Write something into the bitmap so that even with low AFL_INST_RATIO,
|
||||||
|
our parent doesn't give up on us. */
|
||||||
|
|
||||||
|
__afl_area_ptr[0] = 1;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: variable for edge coverage shared memory is not set\n");
|
||||||
|
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void map_input_shared_memory() {
|
||||||
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
|
char *id_str = getenv(SHM_FUZZ_ENV_VAR);
|
||||||
|
|
||||||
if (id_str) {
|
if (id_str) {
|
||||||
|
uint8_t *map = NULL;
|
||||||
uint8_t* map = NULL;
|
|
||||||
|
|
||||||
#ifdef USEMMAP
|
#ifdef USEMMAP
|
||||||
const char *shm_file_path = id_str;
|
const char *shm_file_path = id_str;
|
||||||
@ -115,48 +175,41 @@ static void map_input_shared_memory() {
|
|||||||
/* create the shared memory segment as if it was a file */
|
/* create the shared memory segment as if it was a file */
|
||||||
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
shm_fd = shm_open(shm_file_path, O_RDWR, DEFAULT_PERMISSION);
|
||||||
if (shm_fd == -1) {
|
if (shm_fd == -1) {
|
||||||
|
|
||||||
fprintf(stderr, "shm_open() failed for fuzz\n");
|
fprintf(stderr, "shm_open() failed for fuzz\n");
|
||||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map = (uint8_t* )mmap(0, MAX_FILE + sizeof(uint32_t), PROT_READ, MAP_SHARED, shm_fd, 0);
|
map = (uint8_t *)mmap(0, MAX_FILE + sizeof(uint32_t), PROT_READ, MAP_SHARED,
|
||||||
|
shm_fd, 0);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
uint32_t shm_id = atoi(id_str);
|
uint32_t shm_id = atoi(id_str);
|
||||||
map = (uint8_t* )shmat(shm_id, NULL, 0);
|
map = (uint8_t *)shmat(shm_id, NULL, 0);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Whooooops. */
|
/* Whooooops. */
|
||||||
|
|
||||||
if (!map || map == (void *)-1) {
|
if (!map || map == (void *)-1) {
|
||||||
|
|
||||||
perror("Could not access fuzzing shared memory");
|
perror("Could not access fuzzing shared memory");
|
||||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__afl_fuzz_len = (uint32_t* )map;
|
__afl_fuzz_len = (uint32_t *)map;
|
||||||
__afl_fuzz_ptr = map + sizeof(uint32_t);
|
__afl_fuzz_ptr = map + sizeof(uint32_t);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
|
fprintf(stderr, "Error: variable for fuzzing shared memory is not set\n");
|
||||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fork server logic. */
|
/* Fork server logic. */
|
||||||
|
|
||||||
void __afl_start_forkserver(void) {
|
void __afl_start_forkserver(void) {
|
||||||
|
|
||||||
if (already_initialized_forkserver) return;
|
if (already_initialized_forkserver) return;
|
||||||
already_initialized_forkserver = 1;
|
already_initialized_forkserver = 1;
|
||||||
|
|
||||||
@ -175,24 +228,14 @@ void __afl_start_forkserver(void) {
|
|||||||
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) {
|
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
|
||||||
|
|
||||||
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_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) {
|
if (autodict_on) { status_for_fsrv |= FS_OPT_AUTODICT; }
|
||||||
|
|
||||||
status_for_fsrv |= FS_OPT_AUTODICT;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
|
if (__afl_sharedmem_fuzzing != 0) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
|
||||||
if (status_for_fsrv) {
|
if (status_for_fsrv) { status_for_fsrv |= FS_OPT_ENABLED; }
|
||||||
|
|
||||||
status_for_fsrv |= FS_OPT_ENABLED;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(tmp, &status_for_fsrv, 4);
|
memcpy(tmp, &status_for_fsrv, 4);
|
||||||
|
|
||||||
@ -202,73 +245,57 @@ void __afl_start_forkserver(void) {
|
|||||||
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
|
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
|
||||||
|
|
||||||
if (__afl_sharedmem_fuzzing || autodict_on) {
|
if (__afl_sharedmem_fuzzing || autodict_on) {
|
||||||
|
|
||||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1);
|
||||||
|
|
||||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
|
||||||
|
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
|
||||||
map_input_shared_memory();
|
map_input_shared_memory();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == (FS_OPT_ENABLED | FS_OPT_AUTODICT) && autodict_on) {
|
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
|
// great lets pass the dictionary through the forkserver FD
|
||||||
uint32_t len = (__token_stop - __token_start), offset = 0;
|
uint32_t len = (__token_stop - __token_start), offset = 0;
|
||||||
|
|
||||||
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
|
||||||
|
|
||||||
write_error("could not send dictionary len");
|
write_error("could not send dictionary len");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
|
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
ret = write(FORKSRV_FD + 1, __token_start + offset, len);
|
ret = write(FORKSRV_FD + 1, __token_start + offset, len);
|
||||||
|
|
||||||
if (ret < 1) {
|
if (ret < 1) {
|
||||||
|
|
||||||
write_error("could not send dictionary");
|
write_error("could not send dictionary");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
len -= ret;
|
len -= ret;
|
||||||
offset += ret;
|
offset += ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// uh this forkserver does not understand extended option passing
|
// uh this forkserver does not understand extended option passing
|
||||||
// or does not want the dictionary
|
// or does not want the dictionary
|
||||||
if (!__afl_fuzz_ptr) already_read_first = 1;
|
if (!__afl_fuzz_ptr) already_read_first = 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
/* Wait for parent by reading from the pipe. Abort if read fails. */
|
||||||
|
|
||||||
if (already_read_first) {
|
if (already_read_first) {
|
||||||
|
|
||||||
already_read_first = 0;
|
already_read_first = 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
|
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
|
||||||
|
|
||||||
// write_error("read from afl-fuzz");
|
// write_error("read from afl-fuzz");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we stopped the child in persistent mode, but there was a race
|
/* If we stopped the child in persistent mode, but there was a race
|
||||||
@ -276,33 +303,25 @@ void __afl_start_forkserver(void) {
|
|||||||
process. */
|
process. */
|
||||||
|
|
||||||
if (child_stopped && was_killed) {
|
if (child_stopped && was_killed) {
|
||||||
|
|
||||||
child_stopped = 0;
|
child_stopped = 0;
|
||||||
if (waitpid(child_pid, &status, 0) < 0) {
|
if (waitpid(child_pid, &status, 0) < 0) {
|
||||||
|
|
||||||
write_error("child_stopped && was_killed");
|
write_error("child_stopped && was_killed");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!child_stopped) {
|
if (!child_stopped) {
|
||||||
|
|
||||||
/* Once woken up, create a clone of our process. */
|
/* Once woken up, create a clone of our process. */
|
||||||
|
|
||||||
child_pid = fork();
|
child_pid = fork();
|
||||||
if (child_pid < 0) {
|
if (child_pid < 0) {
|
||||||
|
|
||||||
write_error("fork");
|
write_error("fork");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In child process: close fds, resume execution. */
|
/* In child process: close fds, resume execution. */
|
||||||
|
|
||||||
if (!child_pid) {
|
if (!child_pid) {
|
||||||
|
|
||||||
//(void)nice(-20);
|
//(void)nice(-20);
|
||||||
|
|
||||||
signal(SIGCHLD, old_sigchld_handler);
|
signal(SIGCHLD, old_sigchld_handler);
|
||||||
@ -311,33 +330,26 @@ void __afl_start_forkserver(void) {
|
|||||||
close(FORKSRV_FD);
|
close(FORKSRV_FD);
|
||||||
close(FORKSRV_FD + 1);
|
close(FORKSRV_FD + 1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Special handling for persistent mode: if the child is alive but
|
/* Special handling for persistent mode: if the child is alive but
|
||||||
currently stopped, simply restart it with SIGCONT. */
|
currently stopped, simply restart it with SIGCONT. */
|
||||||
|
|
||||||
kill(child_pid, SIGCONT);
|
kill(child_pid, SIGCONT);
|
||||||
child_stopped = 0;
|
child_stopped = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In parent process: write PID to pipe, then wait for child. */
|
/* In parent process: write PID to pipe, then wait for child. */
|
||||||
|
|
||||||
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
|
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
|
||||||
|
|
||||||
write_error("write to afl-fuzz");
|
write_error("write to afl-fuzz");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) {
|
if (waitpid(child_pid, &status, is_persistent ? WUNTRACED : 0) < 0) {
|
||||||
|
|
||||||
write_error("waitpid");
|
write_error("waitpid");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In persistent mode, the child stops itself with SIGSTOP to indicate
|
/* In persistent mode, the child stops itself with SIGSTOP to indicate
|
||||||
@ -349,12 +361,8 @@ void __afl_start_forkserver(void) {
|
|||||||
/* Relay wait status to pipe, then loop back. */
|
/* Relay wait status to pipe, then loop back. */
|
||||||
|
|
||||||
if (write(FORKSRV_FD + 1, &status, 4) != 4) {
|
if (write(FORKSRV_FD + 1, &status, 4) != 4) {
|
||||||
|
|
||||||
write_error("writing to afl-fuzz");
|
write_error("writing to afl-fuzz");
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,19 @@
|
|||||||
//! Forkserver logic into targets
|
//! Forkserver logic into targets
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
/// Map a shared memory region for the edge coverage map.
|
||||||
|
fn __afl_map_shm();
|
||||||
/// Start the forkserver.
|
/// Start the forkserver.
|
||||||
fn __afl_start_forkserver() -> !;
|
fn __afl_start_forkserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map a shared memory region for the edge coverage map.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// The function's logic is written in C and this code is a wrapper.
|
||||||
|
pub fn map_shared_memory() {
|
||||||
|
unsafe { __afl_map_shm() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the forkserver from this point. Any shared memory must be created before.
|
/// Start the forkserver from this point. Any shared memory must be created before.
|
||||||
@ -10,6 +21,6 @@ extern "C" {
|
|||||||
/// # Note
|
/// # Note
|
||||||
///
|
///
|
||||||
/// The forkserver logic is written in C and this code is a wrapper.
|
/// The forkserver logic is written in C and this code is a wrapper.
|
||||||
pub fn start_forkserver() -> ! {
|
pub fn start_forkserver() {
|
||||||
unsafe { __afl_start_forkserver() }
|
unsafe { __afl_start_forkserver() }
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user