Mark unsafe functions unsafe, as Ferris intended (#2559)

* Mark unsafe functions unsafe, as Ferris inteded

* More

* more safety?

* more fix

* actually safe

* More cleanup

* More fix

* more unsafe

* fix imports

* more unsafe

* fixes

* bring back the memories
This commit is contained in:
Dominik Maier 2024-09-28 16:46:39 +02:00 committed by GitHub
parent afb682bff2
commit 82110472d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 426 additions and 159 deletions

View File

@ -9,7 +9,7 @@ They are sorted by focus:
- [`binary_only`](./binary_only/): Fuzzers for binary-only targets.
- [`forkserver`](./forkserver/): Fuzzers that use a forkserver-style executor.
- [`full_system`](./full_system/): Fuzzers for full-system targets (kernels, firmwares, etc...).
- [`fuzz-anything`](./fuzz_anything/): Fuzzers for advanced targets like WASM or python, and other fuzzers that can be used for anything.
- [`fuzz_anything`](./fuzz_anything/): Fuzzers for advanced targets like WASM or python, and other fuzzers that can be used for anything.
- [`inprocess`](./inprocess/): Common In-process fuzzers. Most of the time, this is what you want.
- [`structure_aware`](./structure_aware/): Grammar fuzzers, fuzzers for certain languages, fuzzers with custom inputs, and more.

View File

@ -59,7 +59,11 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut harness = |input: &PacketData| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
// # Safety
// We're looking for crashes in there!
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -155,7 +159,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>libafl_wasm test</title>
</head>
<body>
<script type="module">
import libafl_wasm from './libafl_wasm.js'
libafl_wasm().then(wasm => wasm.fuzz())
</script>
</body>
</html>

View File

@ -0,0 +1,17 @@
{
"name": "baby_fuzzer_wasm",
"collaborators": [
"Addison Crump <research@addisoncrump.info>"
],
"version": "0.1.0",
"files": [
"baby_fuzzer_wasm_bg.wasm",
"baby_fuzzer_wasm.js",
"baby_fuzzer_wasm.d.ts"
],
"module": "baby_fuzzer_wasm.js",
"types": "baby_fuzzer_wasm.d.ts",
"sideEffects": [
"./snippets/*"
]
}

View File

@ -176,7 +176,7 @@ fn run_testcases(filenames: &[&str]) {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -191,7 +191,9 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow");
libfuzzer_test_one_input(&buffer);
unsafe {
libfuzzer_test_one_input(&buffer);
}
}
}
@ -296,7 +298,7 @@ fn fuzz(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -331,7 +333,9 @@ fn fuzz(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};

View File

@ -174,7 +174,7 @@ fn run_testcases(filenames: &[&str]) {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -189,7 +189,9 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow");
libfuzzer_test_one_input(&buffer);
unsafe {
libfuzzer_test_one_input(&buffer);
}
}
}
@ -290,7 +292,7 @@ fn fuzz(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -325,7 +327,9 @@ fn fuzz(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};

View File

@ -179,7 +179,7 @@ fn run_testcases(filenames: &[&str]) {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -194,7 +194,9 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow");
libfuzzer_test_one_input(&buffer);
unsafe {
libfuzzer_test_one_input(&buffer);
}
}
}
@ -300,7 +302,7 @@ fn fuzz(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -335,7 +337,9 @@ fn fuzz(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};

View File

@ -236,7 +236,7 @@ fn run_testcases(filenames: &[&str]) {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -251,7 +251,9 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow");
libfuzzer_test_one_input(&buffer);
unsafe {
libfuzzer_test_one_input(&buffer);
}
}
}
@ -357,7 +359,7 @@ fn fuzz_binary(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -392,7 +394,9 @@ fn fuzz_binary(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -570,7 +574,7 @@ fn fuzz_text(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -618,7 +622,9 @@ fn fuzz_text(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};

View File

@ -143,7 +143,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -159,7 +161,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -173,7 +173,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
*addr = 1;
}
}
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -191,7 +193,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -210,7 +210,9 @@ pub extern "C" fn libafl_main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -227,7 +229,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -205,7 +205,9 @@ pub extern "C" fn libafl_main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -233,7 +235,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -170,7 +170,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
*addr = 1;
}
}
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -187,7 +189,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -204,7 +204,9 @@ pub extern "C" fn libafl_main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -232,7 +234,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -229,7 +229,9 @@ pub extern "C" fn libafl_main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -245,7 +247,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -171,7 +171,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
*addr = 1;
}
}
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -188,7 +190,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -118,7 +118,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -137,7 +139,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -31,7 +31,7 @@ pub fn main() {
fn fuzz(input_dirs: &[PathBuf], output_dir: PathBuf, cores: &Cores, broker_port: u16) {
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
@ -40,7 +40,7 @@ fn fuzz(input_dirs: &[PathBuf], output_dir: PathBuf, cores: &Cores, broker_port:
.output_dir(output_dir)
.cores(cores)
.broker_port(broker_port)
.harness(|buf| {
.harness(|buf| unsafe {
libfuzzer_test_one_input(buf);
})
.build()

View File

@ -132,7 +132,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -155,7 +157,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -224,7 +224,9 @@ pub extern "C" fn libafl_main() {
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -252,7 +254,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -156,7 +156,9 @@ fn fuzz(
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
unsafe {
libfuzzer_test_one_input(buf);
}
ExitKind::Ok
};
@ -175,7 +177,7 @@ fn fuzz(
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -63,7 +63,7 @@ script_runner = "@shell"
script = '''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd "${PROJECT_DIR}"
cp ../../structure-aware/baby_fuzzer_nautilus/grammar.json .
cp ../../structure_aware/baby_fuzzer_nautilus/grammar.json .
make -C libpng-1.6.37 CC="${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cc" CXX="${CARGO_TARGET_DIR}/${PROFILE_DIR}/libafl_cxx"
'''
dependencies = ["libpng", "cxx", "cc"]

View File

@ -140,7 +140,9 @@ pub extern "C" fn libafl_main() {
// The closure that we want to fuzz
let mut harness = |input: &NautilusInput| {
input.unparse(&context, &mut bytes);
libfuzzer_test_one_input(&bytes);
unsafe {
libfuzzer_test_one_input(&bytes);
}
ExitKind::Ok
};
@ -202,7 +204,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}

View File

@ -218,6 +218,8 @@ where
#[allow(clippy::unused_self)]
fn post_exec(&mut self, _state: &mut S, _input: &S::Input) {
// timeout stuff
// # Safety
// We're calling this only once per execution, in a single thread.
#[cfg(all(feature = "std", not(all(miri, target_vendor = "apple"))))]
self.timer_mut().unset_timer();
}
@ -393,28 +395,38 @@ unsafe impl Send for InProcessExecutorHandlerData {}
unsafe impl Sync for InProcessExecutorHandlerData {}
impl InProcessExecutorHandlerData {
/// # Safety
/// Only safe if not called twice and if the executor is not used from another borrow after this.
#[cfg(any(unix, feature = "std"))]
pub(crate) fn executor_mut<'a, E>(&self) -> &'a mut E {
pub(crate) unsafe fn executor_mut<'a, E>(&self) -> &'a mut E {
unsafe { (self.executor_ptr as *mut E).as_mut().unwrap() }
}
/// # Safety
/// Only safe if not called twice and if the state is not used from another borrow after this.
#[cfg(any(unix, feature = "std"))]
pub(crate) fn state_mut<'a, S>(&self) -> &'a mut S {
pub(crate) unsafe fn state_mut<'a, S>(&self) -> &'a mut S {
unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
}
/// # Safety
/// Only safe if not called twice and if the event manager is not used from another borrow after this.
#[cfg(any(unix, feature = "std"))]
pub(crate) fn event_mgr_mut<'a, EM>(&self) -> &'a mut EM {
pub(crate) unsafe fn event_mgr_mut<'a, EM>(&self) -> &'a mut EM {
unsafe { (self.event_mgr_ptr as *mut EM).as_mut().unwrap() }
}
/// # Safety
/// Only safe if not called twice and if the fuzzer is not used from another borrow after this.
#[cfg(any(unix, feature = "std"))]
pub(crate) fn fuzzer_mut<'a, Z>(&self) -> &'a mut Z {
pub(crate) unsafe fn fuzzer_mut<'a, Z>(&self) -> &'a mut Z {
unsafe { (self.fuzzer_ptr as *mut Z).as_mut().unwrap() }
}
/// # Safety
/// Only safe if not called concurrently.
#[cfg(any(unix, feature = "std"))]
pub(crate) fn take_current_input<'a, I>(&mut self) -> &'a I {
pub(crate) unsafe fn take_current_input<'a, I>(&mut self) -> &'a I {
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
self.current_input_ptr = ptr::null();
r
@ -463,36 +475,51 @@ pub(crate) static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExec
};
/// Get the inprocess [`crate::state::State`]
///
/// # Safety
/// Only safe if not called twice and if the state is not accessed from another borrow while this one is alive.
#[must_use]
pub fn inprocess_get_state<'a, S>() -> Option<&'a mut S> {
pub unsafe fn inprocess_get_state<'a, S>() -> Option<&'a mut S> {
unsafe { (GLOBAL_STATE.state_ptr as *mut S).as_mut() }
}
/// Get the [`crate::events::EventManager`]
///
/// # Safety
/// Only safe if not called twice and if the event manager is not accessed from another borrow while this one is alive.
#[must_use]
pub fn inprocess_get_event_manager<'a, EM>() -> Option<&'a mut EM> {
pub unsafe fn inprocess_get_event_manager<'a, EM>() -> Option<&'a mut EM> {
unsafe { (GLOBAL_STATE.event_mgr_ptr as *mut EM).as_mut() }
}
/// Gets the inprocess [`crate::fuzzer::Fuzzer`]
///
/// # Safety
/// Only safe if not called twice and if the fuzzer is not accessed from another borrow while this one is alive.
#[must_use]
pub fn inprocess_get_fuzzer<'a, F>() -> Option<&'a mut F> {
pub unsafe fn inprocess_get_fuzzer<'a, F>() -> Option<&'a mut F> {
unsafe { (GLOBAL_STATE.fuzzer_ptr as *mut F).as_mut() }
}
/// Gets the inprocess [`Executor`]
///
/// # Safety
/// Only safe if not called twice and if the executor is not accessed from another borrow while this one is alive.
#[must_use]
pub fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> {
pub unsafe fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> {
unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() }
}
/// Gets the inprocess input
///
/// # Safety
/// Only safe if not called concurrently and if the input is not used mutably while this reference is alive.
#[must_use]
pub fn inprocess_get_input<'a, I>() -> Option<&'a I> {
pub unsafe fn inprocess_get_input<'a, I>() -> Option<&'a I> {
unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() }
}
/// Know if we ar eexecuting in a crash/timeout handler
/// Returns if we are executing in a crash/timeout handler
#[must_use]
pub fn inprocess_in_handler() -> bool {
unsafe { GLOBAL_STATE.in_handler }

View File

@ -107,19 +107,21 @@ unsafe impl Sync for InProcessForkExecutorGlobalData {}
unsafe impl Send for InProcessForkExecutorGlobalData {}
impl InProcessForkExecutorGlobalData {
pub(crate) fn executor_mut<'a, E>(&self) -> &'a mut E {
/// # Safety
/// Only safe if not called twice and if the executor is not used from another borrow after this.
pub(crate) unsafe fn executor_mut<'a, E>(&self) -> &'a mut E {
unsafe { (self.executor_ptr as *mut E).as_mut().unwrap() }
}
pub(crate) fn state_mut<'a, S>(&self) -> &'a mut S {
/// # Safety
/// Only safe if not called twice and if the state is not used from another borrow after this.
pub(crate) unsafe fn state_mut<'a, S>(&self) -> &'a mut S {
unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
}
/*fn current_input<'a, I>(&self) -> &'a I {
unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() }
}*/
pub(crate) fn take_current_input<'a, I>(&mut self) -> &'a I {
/// # Safety
/// Only safe if not called concurrently.
pub(crate) unsafe fn take_current_input<'a, I>(&mut self) -> &'a I {
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
self.current_input_ptr = null();
r

View File

@ -256,6 +256,8 @@ impl TimerStruct {
#[cfg(all(unix, not(target_os = "linux")))]
/// Set up timer
pub fn set_timer(&mut self) {
// # Safety
// Safe because the variables are all alive at this time and don't contain pointers.
unsafe {
setitimer(ITIMER_REAL, &mut self.itimerval, core::ptr::null_mut());
}
@ -310,18 +312,22 @@ impl TimerStruct {
}
#[cfg(all(unix, not(target_os = "linux")))]
/// Disalarm timer
/// Disable the timer
pub fn unset_timer(&mut self) {
// # Safety
// No user-provided values.
unsafe {
let mut itimerval_zero: Itimerval = core::mem::zeroed();
setitimer(ITIMER_REAL, &mut itimerval_zero, core::ptr::null_mut());
}
}
/// Disalarm timer
/// Disable the timer
#[cfg(target_os = "linux")]
#[allow(unused_variables)]
pub fn unset_timer(&mut self) {
// # Safety
// Just API calls, no user-provided inputs
if self.batch_mode {
unsafe {
let elapsed = current_time().saturating_sub(self.tmout_start_time);
@ -354,8 +360,10 @@ impl TimerStruct {
}
#[cfg(windows)]
/// Disalarm
/// Disable the timer
pub fn unset_timer(&mut self) {
// # Safety
// The value accesses are guarded by a critical section.
unsafe {
let data = addr_of_mut!(GLOBAL_STATE);

View File

@ -38,11 +38,11 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [
static mut COUNT_CLASS_LOOKUP_16: Vec<u16> = vec![];
/// Initialize the 16-byte hitcounts map
///
/// # Safety
///
/// Calling this from multiple threads may be racey and hence leak 65k mem or even create a broken lookup vec.
fn init_count_class_16() {
// # Safety
//
// Calling this from multiple threads may be racey and hence leak 65k mem or even create a broken lookup vec.
// We can live with that.
unsafe {
let count_class_lookup_16 = &mut *addr_of_mut!(COUNT_CLASS_LOOKUP_16);

View File

@ -310,6 +310,8 @@ mod linux {
}
fn new_cpu_set() -> cpu_set_t {
// # Safety
// Returning a new zeroed value that is allowed to be 0.
unsafe { zeroed::<cpu_set_t>() }
}
@ -733,6 +735,8 @@ mod netbsd {
}
fn new_cpuset() -> *mut _cpuset {
// # Safety
// Simply creating new empty cpuset. No user-provided params.
unsafe { _cpuset_create() }
}
}

View File

@ -663,6 +663,8 @@ impl LlmpMsg {
/// Gets the buffer from this message as slice, with the correct length.
#[inline]
pub fn try_as_slice<SHM: ShMem>(&self, map: &mut LlmpSharedMap<SHM>) -> Result<&[u8], Error> {
// # Safety
// Safe because we check if we're in a valid shmem region first.
unsafe {
if self.in_shmem(map) {
Ok(self.as_slice_unsafe())
@ -1818,6 +1820,8 @@ where
#[allow(clippy::type_complexity)]
#[inline]
pub fn recv_buf_with_flags(&mut self) -> Result<Option<(ClientId, Tag, Flags, &[u8])>, Error> {
// # Safety
// No user-provided potentially unsafe parameters.
unsafe {
Ok(match self.recv()? {
Some(msg) => Some((
@ -1835,6 +1839,8 @@ where
#[allow(clippy::type_complexity)]
#[inline]
pub fn recv_buf_blocking_with_flags(&mut self) -> Result<(ClientId, Tag, Flags, &[u8]), Error> {
// # Safety
// No user-provided potentially unsafe parameters.
unsafe {
let msg = self.recv_blocking()?;
Ok((
@ -1849,6 +1855,8 @@ where
/// Returns the next sender, tag, buf, looping until it becomes available
#[inline]
pub fn recv_buf_blocking(&mut self) -> Result<(ClientId, Tag, &[u8]), Error> {
// # Safety
// No user-provided potentially unsafe parameters.
unsafe {
let msg = self.recv_blocking()?;
Ok((
@ -1953,6 +1961,8 @@ where
/// Marks the containing page as `safe_to_unmap`.
/// This indicates, that the page may safely be unmapped by the sender.
pub fn mark_safe_to_unmap(&mut self) {
// # Safety
// No user-provided potentially unsafe parameters.
unsafe {
(*self.page_mut()).receiver_joined();
}
@ -3028,6 +3038,9 @@ where
#[cfg(any(unix, all(windows, feature = "std")))]
#[allow(clippy::unused_self)]
fn is_shutting_down(&self) -> bool {
// # Safety
// No user-provided potentially unsafe parameters.
// Volatile read.
unsafe { ptr::read_volatile(ptr::addr_of!(LLMP_SIGHANDLER_STATE.shutting_down)) }
}
@ -3091,6 +3104,8 @@ where
/// Tell the broker to disconnect this client from it.
#[cfg(feature = "std")]
fn announce_client_exit(sender: &mut LlmpSender<SP>, client_id: u32) -> Result<(), Error> {
// # Safety
// No user-provided potentially unsafe parameters.
unsafe {
let msg = sender
.alloc_next(size_of::<LlmpClientExitInfo>())

View File

@ -242,7 +242,7 @@ pub mod serdeany_registry {
/// # Safety
/// This may never be called concurrently or at the same time as `register`.
/// It dereferences the `REGISTRY` hashmap and adds the given type to it.
pub fn finalize() {
pub unsafe fn finalize() {
unsafe {
(*addr_of_mut!(REGISTRY)).finalize();
}

View File

@ -693,6 +693,9 @@ pub mod unix_shmem {
/// Create a new [`MmapShMem`]
/// This will *NOT* automatically delete the shmem files, meaning that it's user's responsibility to delete all `/dev/shm/libafl_*` after fuzzing
pub fn new(map_size: usize, rand_id: u32) -> Result<Self, Error> {
// # Safety
// No user-provided potentially unsafe parameters.
// FFI Calls.
unsafe {
let mut full_file_name = format!("/libafl_{}_{}", process::id(), rand_id);
// leave one byte space for the null byte.
@ -765,6 +768,9 @@ pub mod unix_shmem {
#[allow(clippy::unnecessary_wraps)]
fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
// # Safety
// No user-provided potentially unsafe parameters.
// FFI Calls.
unsafe {
/* map the shared memory segment to the address space of the process */
#[cfg(target_vendor = "apple")]

View File

@ -324,7 +324,9 @@ impl Allocator {
continue;
}
// First poison the memory.
Self::poison(map_to_shadow!(self, address), allocation.size);
unsafe {
Self::poison(map_to_shadow!(self, address), allocation.size);
}
// Reset the allocaiton metadata object
allocation.size = 0;
@ -359,7 +361,11 @@ impl Allocator {
}
}
fn unpoison(start: usize, size: usize) {
/// Unpoison an area in memory
///
/// # Safety
/// start needs to be a valid address, We need to be able to fill `size / 8` bytes.
unsafe fn unpoison(start: usize, size: usize) {
unsafe {
std::slice::from_raw_parts_mut(start as *mut u8, size / 8).fill(0xff);
@ -372,8 +378,11 @@ impl Allocator {
}
}
/// Poisonn an area in memory
pub fn poison(start: usize, size: usize) {
/// Poison an area in memory
///
/// # Safety
/// start needs to be a valid address, We need to be able to fill `size / 8` bytes.
pub unsafe fn poison(start: usize, size: usize) {
unsafe {
std::slice::from_raw_parts_mut(start as *mut u8, size / 8).fill(0x0);
@ -445,7 +454,9 @@ impl Allocator {
}
if unpoison {
Self::unpoison(shadow_mapping_start, end - start);
unsafe {
Self::unpoison(shadow_mapping_start, end - start);
}
}
(shadow_mapping_start, (end - start) / 8 + 1)
@ -633,6 +644,8 @@ impl Allocator {
size = 0;
}
}
/// Unpoisons all memory
#[cfg(not(target_vendor = "apple"))]
pub fn unpoison_all_existing_memory(&mut self) {
RangeDetails::enumerate_with_prot(

View File

@ -216,7 +216,11 @@ impl FridaRuntime for AsanRuntime {
let target_bytes = input.target_bytes();
let slice = target_bytes.as_slice();
self.poison(slice.as_ptr() as usize, slice.len());
// # Safety
// The ptr and length are correct.
unsafe {
self.poison(slice.as_ptr() as usize, slice.len());
}
self.reset_allocations();
Ok(())
@ -282,7 +286,11 @@ impl AsanRuntime {
}
/// Make sure the specified memory is poisoned
pub fn poison(&mut self, address: usize, size: usize) {
///
/// # Safety
/// The address needs to be a valid address, the size needs to be correct.
/// This will dereference at the address.
pub unsafe fn poison(&mut self, address: usize, size: usize) {
Allocator::poison(self.allocator.map_to_shadow(address), size);
}

View File

@ -1237,8 +1237,10 @@ impl AsanRuntime {
res
}
/// # Safety
/// `addr` will get dereferenced.
#[inline]
pub fn hook_munmap(
pub unsafe fn hook_munmap(
&mut self,
original: extern "C" fn(addr: *const c_void, length: usize) -> i32,
addr: *const c_void,

View File

@ -138,8 +138,11 @@ where
}
impl<S, OT> NyxExecutor<S, OT> {
/// convert `trace_bits` ptr into real trace map
pub fn trace_bits(self) -> &'static mut [u8] {
/// Convert `trace_bits` ptr into real trace map
///
/// # Safety
/// Mutable borrow may only be used once at a time.
pub unsafe fn trace_bits(self) -> &'static mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(self.helper.bitmap_buffer, self.helper.bitmap_size)
}

View File

@ -5,13 +5,13 @@
// use std::io::{BufRead, BufReader};
use std::{
collections::hash_map,
env, fs,
fs::File,
env,
fs::{self, File},
hash::Hasher,
io::{Read, Seek, SeekFrom, Write},
path::{Path, PathBuf},
process::Command,
ptr::addr_of_mut,
sync::{LazyLock, Mutex},
};
//#[rustversion::nightly]
@ -30,25 +30,21 @@ use crate::build::QEMU_REVISION;
const LLVM_VERSION_MAX: i32 = 33;
static mut CARGO_RPATH: Option<Vec<String>> = None;
static CARGO_RPATH: LazyLock<Mutex<Vec<String>>> = LazyLock::new(Mutex::default);
static CARGO_RPATH_SEPARATOR: &str = "|";
// Add to the list of `rpath`s.
// Later, print the `cargo::rpath` using [`cargo_propagate_rpath`]
pub fn cargo_add_rpath(rpath: &str) {
unsafe {
if let Some(rpaths) = &mut *addr_of_mut!(CARGO_RPATH) {
rpaths.push(rpath.to_string());
} else {
CARGO_RPATH = Some(vec![rpath.to_string()]);
}
}
CARGO_RPATH.lock().unwrap().push(rpath.to_string());
}
// Print the `rpath`, set via [`cargo_add_rpath`] as `cargo::rpath`
pub fn cargo_propagate_rpath() {
unsafe {
if let Some(cargo_cmds) = &mut *addr_of_mut!(CARGO_RPATH) {
let rpath = cargo_cmds.join(CARGO_RPATH_SEPARATOR);
println!("cargo:rpath={rpath}");
}
let cargo_cmds = CARGO_RPATH.lock().unwrap();
if !cargo_cmds.is_empty() {
let rpath = cargo_cmds.join(CARGO_RPATH_SEPARATOR);
println!("cargo:rpath={rpath}");
}
}

View File

@ -171,7 +171,9 @@ pub fn make_plugin_meminfo(oi: MemOpIdx, rw: qemu_plugin_mem_rw) -> qemu_plugin_
// from include/hw/core/cpu.h
/// # Safety
/// Will dereference the `cpu` pointer.
#[cfg(target_os = "linux")]
pub fn cpu_env(cpu: *mut CPUState) -> *mut CPUArchState {
pub unsafe fn cpu_env(cpu: *mut CPUState) -> *mut CPUArchState {
unsafe { cpu.add(1) as *mut CPUArchState }
}

View File

@ -650,7 +650,9 @@ where
}
}
pub fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
/// # Safety
/// Will dereference the hook as [`FatPtr`].
pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
unsafe {
let fat: FatPtr = transmute(hook);
self.backdoor_hooks
@ -689,7 +691,9 @@ where
}
}
pub fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
/// # Safety
/// This can call through to a potentialy unsafe `backtoor_function`
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
match hook {
Hook::Function(f) => Some(self.backdoor_function(f)),
Hook::Closure(c) => Some(self.backdoor_closure(c)),
@ -780,6 +784,8 @@ where
#[allow(clippy::type_complexity)]
pub fn syscalls_function(&mut self, hook: PreSyscallHookFn<ET, S>) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe {
self.qemu_hooks
.add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<ET, S>)
@ -788,6 +794,8 @@ where
#[allow(clippy::type_complexity)]
pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure<ET, S>) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe {
let fat: FatPtr = transmute(hook);
@ -830,6 +838,8 @@ where
#[allow(clippy::type_complexity)]
pub fn after_syscalls_function(&mut self, hook: PostSyscallHookFn<ET, S>) -> PostSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`]. This should be ok.
unsafe {
self.qemu_hooks
.add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<ET, S>)
@ -869,12 +879,16 @@ where
}
pub fn crash_function(&mut self, hook: fn(&mut EmulatorModules<ET, S>, target_signal: i32)) {
// # Safety
// Will cast the valid hook to a ptr.
self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.crash_hooks
.push(HookRepr::Function(hook as *const libc::c_void));
}
pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
// # Safety
// Will cast the hook to a [`FatPtr`].
unsafe {
self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.crash_hooks.push(HookRepr::Closure(transmute(hook)));
@ -1044,7 +1058,9 @@ where
)
}
pub fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
/// # Safety
/// This will potentially call an unsafe backdoor hook
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
self.hooks.backdoor(hook)
}
@ -1052,7 +1068,9 @@ where
self.hooks.backdoor_function(hook)
}
pub fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
/// # Safety
/// Calls through to the potentially unsafe `backdoor_closure`
pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
self.hooks.backdoor_closure(hook)
}
@ -1119,6 +1137,8 @@ where
}
pub fn first_exec_all(&mut self, state: &mut S) {
// # Safety
// We assume that the emulator was initialized correctly
unsafe {
self.modules_mut()
.first_exec_all(Self::emulator_modules_mut_unchecked(), state);
@ -1126,6 +1146,8 @@ where
}
pub fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) {
// # Safety
// We assume that the emulator was initialized correctly
unsafe {
self.modules_mut()
.pre_exec_all(Self::emulator_modules_mut_unchecked(), state, input);
@ -1201,8 +1223,10 @@ where
self.hooks.syscalls(hook)
}
/// # Safety
/// Calls through to the, potentially unsafe, `syscalls_function`
#[allow(clippy::type_complexity)]
pub fn syscalls_function(
pub unsafe fn syscalls_function(
&mut self,
hook: fn(
&mut EmulatorModules<ET, S>,
@ -1221,8 +1245,10 @@ where
self.hooks.syscalls_function(hook)
}
/// # Safety
/// Calls through to the, potentially unsafe, `syscalls_closure`
#[allow(clippy::type_complexity)]
pub fn syscalls_closure(
pub unsafe fn syscalls_closure(
&mut self,
hook: Box<
dyn for<'a> FnMut(
@ -1248,8 +1274,10 @@ where
self.hooks.after_syscalls(hook)
}
/// # Safety
/// Calls through to the, potentially unsafe, `after_syscalls_function`
#[allow(clippy::type_complexity)]
pub fn after_syscalls_function(
pub unsafe fn after_syscalls_function(
&mut self,
hook: fn(
&mut EmulatorModules<ET, S>,
@ -1296,7 +1324,9 @@ where
self.hooks.crash_function(hook);
}
pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
/// # Safety
/// Calls through to the, potentially unsafe, registered `crash_closure`
pub unsafe fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
self.hooks.crash_closure(hook);
}
}

View File

@ -6,6 +6,8 @@ use core::{
};
#[cfg(emulation_mode = "usermode")]
use std::ptr;
#[cfg(emulation_mode = "systemmode")]
use std::sync::atomic::{AtomicBool, Ordering};
use libafl::{
corpus::Corpus,
@ -17,14 +19,14 @@ use libafl::{
},
feedbacks::Feedback,
fuzzer::HasObjective,
inputs::UsesInput,
observers::{ObserversTuple, UsesObservers},
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, ExecutionProcessor, HasScheduler,
};
#[cfg(feature = "fork")]
use libafl::{
events::EventManager, executors::InProcessForkExecutor, state::HasLastReportTime, HasMetadata,
events::EventManager, executors::InProcessForkExecutor, inputs::UsesInput,
state::HasLastReportTime, HasMetadata,
};
#[cfg(feature = "fork")]
use libafl_bolts::shmem::ShMemProvider;
@ -72,8 +74,11 @@ pub unsafe fn inproc_qemu_crash_handler(
}
#[cfg(emulation_mode = "systemmode")]
pub(crate) static mut BREAK_ON_TMOUT: bool = false;
pub(crate) static BREAK_ON_TMOUT: AtomicBool = AtomicBool::new(false);
/// # Safety
/// Can call through the `unix_signal_handler::inproc_timeout_handler`.
/// Calling this method multiple times concurrently can lead to race conditions.
#[cfg(emulation_mode = "systemmode")]
pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
signal: Signal,
@ -89,7 +94,7 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, OF, Z>(
<<E as UsesState>::State as HasSolutions>::Solutions: Corpus<Input = E::Input>, //delete me
<<<E as UsesState>::State as HasCorpus>::Corpus as Corpus>::Input: Clone, //delete me
{
if BREAK_ON_TMOUT {
if BREAK_ON_TMOUT.load(Ordering::Acquire) {
libafl_exit_request_timeout();
} else {
libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<E, EM, OF, Z>(
@ -157,10 +162,14 @@ where
}
};
inner
.exposed_executor_state_mut()
.modules_mut()
.crash_closure(Box::new(handler));
// # Safety
// We assume our crash handlers to be safe/quit after execution.
unsafe {
inner
.exposed_executor_state_mut()
.modules_mut()
.crash_closure(Box::new(handler));
}
}
#[cfg(emulation_mode = "systemmode")]
@ -185,9 +194,7 @@ where
#[cfg(emulation_mode = "systemmode")]
pub fn break_on_timeout(&mut self) {
unsafe {
BREAK_ON_TMOUT = true;
}
BREAK_ON_TMOUT.store(true, Ordering::Release);
}
pub fn inner_mut(

View File

@ -543,19 +543,19 @@ static mut CALLSTACKS: Option<ThreadLocal<UnsafeCell<Vec<GuestAddr>>>> = None;
#[derive(Debug)]
pub struct FullBacktraceCollector {}
impl Default for FullBacktraceCollector {
fn default() -> Self {
Self::new()
}
}
impl FullBacktraceCollector {
pub fn new() -> Self {
/// # Safety
/// This accesses the global [`CALLSTACKS`] variable and may not be called concurrently.
pub unsafe fn new() -> Self {
unsafe { (*addr_of_mut!(CALLSTACKS)) = Some(ThreadLocal::new()) };
Self {}
}
pub fn reset(&mut self) {
// # Safety
// This accesses the global [`CALLSTACKS`] variable.
// While it is racey, it might be fine if multiple clear the vecs concurrently.
// TODO: This should probably be rewritten in a safer way.
unsafe {
for tls in (*addr_of_mut!(CALLSTACKS)).as_mut().unwrap().iter_mut() {
(*tls.get()).clear();
@ -564,6 +564,9 @@ impl FullBacktraceCollector {
}
pub fn backtrace() -> Option<&'static [GuestAddr]> {
// # Safety
// This accesses the global [`CALLSTACKS`] variable.
// However, the actual variable access is behind a `ThreadLocal` class.
unsafe {
if let Some(c) = (*addr_of_mut!(CALLSTACKS)).as_mut() {
Some(&*c.get_or_default().get())

View File

@ -269,7 +269,9 @@ impl CmpLogRoutinesModule {
self.address_filter.allowed(&addr)
}
extern "C" fn on_call(k: u64, _pc: GuestAddr) {
/// # Safety
/// Dereferences k as pointer eventually.
unsafe extern "C" fn on_call(k: u64, _pc: GuestAddr) {
unsafe {
if CMPLOG_ENABLED == 0 {
return;

View File

@ -592,13 +592,17 @@ where
}
}
pub extern "C" fn trace_edge_hitcount(_: *const (), id: u64) {
// # Safety
// Calling this concurrently for the same id is racey and may lose updates.
pub unsafe extern "C" fn trace_edge_hitcount(_: *const (), id: u64) {
unsafe {
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
}
}
pub extern "C" fn trace_edge_single(_: *const (), id: u64) {
// # Safety
// Worst case we set the byte to 1 multiple times..
unsafe {
EDGES_MAP[id as usize] = 1;
}
@ -649,14 +653,19 @@ where
Some(id)
}
pub extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
/// # Safety
/// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently.
pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = (*ptr).wrapping_add(1);
}
}
pub extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) {
/// # Safety
/// Fine.
/// Worst case we set the byte to 1 multiple times.
pub unsafe extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) {
unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = 1;
@ -708,7 +717,9 @@ where
Some(id)
}
pub extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
/// # Safety
/// Dereferences the global `PREV_LOC` variable. May not be called concurrently.
pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
unsafe {
PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1);
@ -719,7 +730,9 @@ pub extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
}
}
pub extern "C" fn trace_block_transition_single(_: *const (), id: u64) {
/// # Safety
/// Dereferences the global `PREV_LOC` variable. May not be called concurrently.
pub unsafe extern "C" fn trace_block_transition_single(_: *const (), id: u64) {
unsafe {
PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1);

View File

@ -479,6 +479,9 @@ impl AsanGiovese {
}
pub fn alloc_insert(&mut self, pc: GuestAddr, start: GuestAddr, end: GuestAddr) {
// # Safety
// Will access the global [`FullBacktraceCollector`].
// Calling this function concurrently might be racey.
let backtrace = FullBacktraceCollector::backtrace()
.map(|r| {
let mut v = r.to_vec();
@ -504,6 +507,9 @@ impl AsanGiovese {
}
pub fn alloc_free(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) {
// # Safety
// Will access the global [`FullBacktraceCollector`].
// Calling this function concurrently might be racey.
let mut chunk = None;
self.alloc_map_mut(addr, |interval, item| {
chunk = Some(*interval);
@ -796,13 +802,20 @@ impl AsanModule {
}
}
/// # Safety
/// The `ASan` error report accesses [`FullBacktraceCollector`]
#[must_use]
pub fn with_asan_report(
pub unsafe fn with_asan_report(
rt: Pin<Box<AsanGiovese>>,
filter: StdAddressFilter,
options: QemuAsanOptions,
) -> Self {
Self::with_error_callback(rt, filter, Box::new(asan_report), options)
Self::with_error_callback(
rt,
filter,
Box::new(|rt, qemu, pc, err| unsafe { asan_report(rt, qemu, pc, err) }),
options,
)
}
#[must_use]
@ -1518,9 +1531,12 @@ mod addr2line_legacy {
}
}
/// # Safety
/// Will access the global [`FullBacktraceCollector`].
/// Calling this function concurrently might be racey.
#[allow(clippy::unnecessary_cast)]
#[allow(clippy::too_many_lines)]
pub fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: AsanError) {
pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: AsanError) {
let mut regions = HashMap::new();
for region in qemu.mappings() {
if let Some(path) = region.path() {

View File

@ -549,7 +549,7 @@ create_hook_types!(
EdgeExec,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, id: u64),
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64)>,
extern "C" fn(*const (), id: u64)
unsafe extern "C" fn(*const (), id: u64)
);
create_hook_id!(Edge, libafl_qemu_remove_edge_hook, true);
create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId);
@ -746,7 +746,7 @@ impl QemuHooks {
&self,
data: T,
addr: GuestAddr,
callback: extern "C" fn(T, GuestAddr),
callback: unsafe extern "C" fn(T, GuestAddr),
invalidate_block: bool,
) -> InstructionHookId {
unsafe {

View File

@ -1083,7 +1083,9 @@ pub mod pybind {
self.qemu.flush_jit();
}
fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
/// # Safety
/// Removes a hooke from `PY_GENERIC_HOOKS` -> may not be called concurrently!
unsafe fn set_hook(&self, addr: GuestAddr, hook: PyObject) {
unsafe {
let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS);
let idx = hooks.len();
@ -1097,7 +1099,9 @@ pub mod pybind {
}
}
fn remove_hooks_at(&self, addr: GuestAddr) -> usize {
/// # Safety
/// Removes a hooke from `PY_GENERIC_HOOKS` -> may not be called concurrently!
unsafe fn remove_hooks_at(&self, addr: GuestAddr) -> usize {
unsafe {
let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS);
hooks.retain(|(a, _)| *a != addr);

View File

@ -338,7 +338,9 @@ pub mod pybind {
self.qemu.unmap(addr, size).map_err(PyValueError::new_err)
}
fn set_syscall_hook(&self, hook: PyObject) {
/// # Safety
/// Accesses the global `PY_SYSCALL_HOOK` and may not be called concurrently.
unsafe fn set_syscall_hook(&self, hook: PyObject) {
unsafe {
(*core::ptr::addr_of_mut!(PY_SYSCALL_HOOK)) = Some(hook);
}

View File

@ -7,6 +7,14 @@
feature = "sancov_ctx"
))]
use alloc::borrow::Cow;
#[cfg(any(
feature = "sancov_pcguard_edges",
feature = "sancov_pcguard_hitcounts",
feature = "sancov_ngram4",
feature = "sancov_ctx"
))]
#[cfg(not(feature = "pointer_maps"))]
use core::ptr::addr_of;
use core::ptr::addr_of_mut;
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
@ -16,16 +24,19 @@ use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_
/// The map for edges.
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_SIZE_MAX] = [0; EDGES_MAP_SIZE_MAX];
pub use __afl_area_ptr_local as EDGES_MAP;
/// The map for data dependency
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __ddg_area_ptr_local: [u8; DDG_MAP_SIZE] = [0; DDG_MAP_SIZE];
pub use __ddg_area_ptr_local as DDG_MAP;
/// The map for accounting mem writes.
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __afl_acc_memop_ptr_local: [u32; ACCOUNTING_MAP_SIZE] = [0; ACCOUNTING_MAP_SIZE];
pub use __afl_acc_memop_ptr_local as ACCOUNTING_MEMOP_MAP;
@ -60,6 +71,8 @@ pub use __ddg_area_ptr as DDG_MAP_PTR;
/// Return Tokens from the compile-time token section
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn autotokens() -> Result<Tokens, Error> {
// # Safety
// All values are checked before dereferencing.
unsafe {
if __token_start.is_null() || __token_stop.is_null() {
Ok(Tokens::default())
@ -73,6 +86,7 @@ pub fn autotokens() -> Result<Tokens, Error> {
/// The actual size we use for the map of edges.
/// This is used for forkserver backend
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE;
#[cfg(any(
@ -182,7 +196,7 @@ pub fn edges_max_num() -> usize {
}
#[cfg(not(feature = "pointer_maps"))]
{
EDGES_MAP.len()
(*addr_of!(EDGES_MAP)).len()
}
}
}

View File

@ -23,11 +23,12 @@ extern "C" {
/// Calls the (native) libfuzzer initialize function.
/// Returns the value returned by the init function.
/// # Note
///
/// # Safety
/// Calls the libfuzzer-style init function which is native code.
#[allow(clippy::similar_names)]
#[allow(clippy::must_use_candidate)] // nobody uses that return code...
pub fn libfuzzer_initialize(args: &[String]) -> i32 {
pub unsafe fn libfuzzer_initialize(args: &[String]) -> i32 {
let args: Vec<String> = args.iter().map(|x| x.clone() + "\0").collect();
let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect();
assert!(argv.len() < i32::MAX as usize);
@ -40,9 +41,10 @@ pub fn libfuzzer_initialize(args: &[String]) -> i32 {
}
/// Call a single input of a libfuzzer-style cpp-harness
/// # Note
///
/// # Safety
/// Calls the libfuzzer harness. We actually think the target is unsafe and crashes eventually, that's why we do all this fuzzing.
#[allow(clippy::must_use_candidate)]
pub fn libfuzzer_test_one_input(buf: &[u8]) -> i32 {
pub unsafe fn libfuzzer_test_one_input(buf: &[u8]) -> i32 {
unsafe { LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len()) }
}

View File

@ -27,10 +27,13 @@ pub unsafe fn extra_counters() -> Vec<OwnedMutSlice<'static, u8>> {
}
/// Initialize the sancov `8-bit-counters` - usually called by `llvm`.
///
/// # Safety
/// Start and stop are being dereferenced.
#[no_mangle]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub extern "C" fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut u8) {
pub unsafe extern "C" fn __sanitizer_cov_8bit_counters_init(start: *mut u8, stop: *mut u8) {
unsafe {
let counter_maps = &mut *addr_of_mut!(COUNTERS_MAPS);
for existing in counter_maps {

View File

@ -3,7 +3,11 @@
#[rustversion::nightly]
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
use core::simd::num::SimdUint;
use core::{mem::align_of, slice};
use core::{
mem::align_of,
ptr::{addr_of, addr_of_mut},
slice,
};
#[cfg(any(
feature = "sancov_ngram4",
@ -186,7 +190,7 @@ unsafe fn update_ngram(pos: usize) -> usize {
let mut reduced = pos;
#[cfg(feature = "sancov_ngram4")]
{
let prev_array_4 = &mut *core::ptr::addr_of_mut!(PREV_ARRAY_4);
let prev_array_4 = &mut *addr_of_mut!(PREV_ARRAY_4);
*prev_array_4 = prev_array_4.rotate_elements_right::<1>();
prev_array_4.shl_assign(SHR_4);
prev_array_4.as_mut_array()[0] = pos as u32;
@ -194,7 +198,7 @@ unsafe fn update_ngram(pos: usize) -> usize {
}
#[cfg(feature = "sancov_ngram8")]
{
let prev_array_8 = &mut *core::ptr::addr_of_mut!(PREV_ARRAY_8);
let prev_array_8 = &mut *addr_of_mut!(PREV_ARRAY_8);
*prev_array_8 = prev_array_8.rotate_elements_right::<1>();
prev_array_8.shl_assign(SHR_8);
prev_array_8.as_mut_array()[0] = pos as u32;
@ -253,14 +257,15 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
}
#[cfg(not(feature = "pointer_maps"))]
{
let edges_map = &mut *addr_of_mut!(EDGES_MAP);
#[cfg(feature = "sancov_pcguard_edges")]
{
*EDGES_MAP.get_unchecked_mut(pos) = 1;
*(edges_map).get_unchecked_mut(pos) = 1;
}
#[cfg(feature = "sancov_pcguard_hitcounts")]
{
let val = (*EDGES_MAP.get_unchecked(pos)).wrapping_add(1);
*EDGES_MAP.get_unchecked_mut(pos) = val;
let val = (*edges_map.get_unchecked(pos)).wrapping_add(1);
*edges_map.get_unchecked_mut(pos) = val;
}
}
}
@ -273,7 +278,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
#[cfg(feature = "pointer_maps")]
if EDGES_MAP_PTR.is_null() {
EDGES_MAP_PTR = core::ptr::addr_of_mut!(EDGES_MAP) as *mut u8;
EDGES_MAP_PTR = addr_of_mut!(EDGES_MAP) as *mut u8;
}
if start == stop || *start != 0 {
@ -290,8 +295,9 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32
}
#[cfg(not(feature = "pointer_maps"))]
{
let edges_map_len = (*addr_of!(EDGES_MAP)).len();
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1);
assert!((MAX_EDGES_FOUND <= EDGES_MAP.len()), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({}). Use the LIBAFL_EDGES_MAP_SIZE_IN_USE env to increase it at compile time.", EDGES_MAP.len());
assert!((MAX_EDGES_FOUND <= edges_map_len), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({edges_map_len}). Use the LIBAFL_EDGES_MAP_SIZE_IN_USE env to increase it at compile time.");
}
}
}
@ -314,7 +320,7 @@ unsafe extern "C" fn __sanitizer_cov_pcs_init(pcs_beg: *const usize, pcs_end: *c
"Unaligned PC Table - start: {pcs_beg:x?} end: {pcs_end:x?}"
);
let pc_tables = &mut *core::ptr::addr_of_mut!(PC_TABLES);
let pc_tables = &mut *addr_of_mut!(PC_TABLES);
pc_tables.push(slice::from_raw_parts(pcs_beg as *const PcTableEntry, len));
}
@ -345,7 +351,7 @@ pub fn sanitizer_cov_pc_table<'a>() -> impl Iterator<Item = &'a [PcTableEntry]>
// SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So
// there's no TOCTOU issue.
unsafe {
let pc_tables = &*core::ptr::addr_of!(PC_TABLES);
let pc_tables = &*addr_of!(PC_TABLES);
pc_tables.iter().copied()
}
}