From 82110472d60b8d40b3466f0f055828ca1c29df2f Mon Sep 17 00:00:00 2001 From: Dominik Maier Date: Sat, 28 Sep 2024 16:46:39 +0200 Subject: [PATCH] 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 --- fuzzers/README.md | 2 +- fuzzers/baby/tutorial/src/lib.rs | 8 ++- .../baby_fuzzer_wasm/pkg/index.html | 14 ++++++ .../baby_fuzzer_wasm/pkg/package.json | 17 +++++++ fuzzers/inprocess/dynamic_analysis/src/lib.rs | 12 +++-- fuzzers/inprocess/fuzzbench/src/lib.rs | 12 +++-- fuzzers/inprocess/fuzzbench_ctx/src/lib.rs | 12 +++-- fuzzers/inprocess/fuzzbench_text/src/lib.rs | 18 ++++--- .../inprocess/libfuzzer_libmozjpeg/src/lib.rs | 6 ++- fuzzers/inprocess/libfuzzer_libpng/src/lib.rs | 6 ++- .../libfuzzer_libpng_accounting/src/lib.rs | 6 ++- .../libfuzzer_libpng_centralized/src/lib.rs | 6 ++- .../libfuzzer_libpng_cmin/src/lib.rs | 6 ++- .../libfuzzer_libpng_launcher/src/lib.rs | 6 ++- .../libfuzzer_libpng_norestart/src/lib.rs | 6 ++- .../libfuzzer_libpng_tcp_manager/src/lib.rs | 6 ++- .../inprocess/libfuzzer_stb_image/src/main.rs | 6 ++- .../libfuzzer_stb_image_sugar/src/main.rs | 4 +- .../libfuzzer_windows_asan/src/lib.rs | 6 ++- .../src/lib.rs | 6 ++- .../fuzzer/src/main.rs | 6 ++- .../nautilus_sync/Makefile.toml | 2 +- .../structure_aware/nautilus_sync/src/lib.rs | 6 ++- libafl/src/executors/hooks/inprocess.rs | 49 ++++++++++++++----- libafl/src/executors/hooks/inprocess_fork.rs | 16 +++--- libafl/src/executors/hooks/timer.rs | 14 ++++-- libafl/src/observers/map/hitcount_map.rs | 8 +-- libafl_bolts/src/core_affinity.rs | 4 ++ libafl_bolts/src/llmp.rs | 15 ++++++ libafl_bolts/src/serdeany.rs | 2 +- libafl_bolts/src/shmem.rs | 6 +++ libafl_frida/src/alloc.rs | 23 +++++++-- libafl_frida/src/asan/asan_rt.rs | 12 ++++- libafl_frida/src/asan/hook_funcs.rs | 4 +- libafl_nyx/src/executor.rs | 7 ++- libafl_qemu/libafl_qemu_build/src/lib.rs | 28 +++++------ libafl_qemu/libafl_qemu_sys/src/lib.rs | 4 +- libafl_qemu/src/emu/hooks.rs | 46 ++++++++++++++--- libafl_qemu/src/executor.rs | 29 ++++++----- libafl_qemu/src/modules/calls.rs | 17 ++++--- libafl_qemu/src/modules/cmplog.rs | 4 +- libafl_qemu/src/modules/edges.rs | 23 +++++++-- libafl_qemu/src/modules/usermode/asan.rs | 22 +++++++-- libafl_qemu/src/qemu/hooks.rs | 4 +- libafl_qemu/src/qemu/mod.rs | 8 ++- libafl_qemu/src/qemu/usermode.rs | 4 +- libafl_targets/src/coverage.rs | 16 +++++- libafl_targets/src/libfuzzer/mod.rs | 10 ++-- libafl_targets/src/sancov_8bit.rs | 5 +- libafl_targets/src/sancov_pcguard.rs | 26 ++++++---- 50 files changed, 426 insertions(+), 159 deletions(-) create mode 100644 fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/index.html create mode 100644 fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/package.json diff --git a/fuzzers/README.md b/fuzzers/README.md index 68be233c8f..22aaffcafa 100644 --- a/fuzzers/README.md +++ b/fuzzers/README.md @@ -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. diff --git a/fuzzers/baby/tutorial/src/lib.rs b/fuzzers/baby/tutorial/src/lib.rs index 343511d6fc..9801ee7d76 100644 --- a/fuzzers/baby/tutorial/src/lib.rs +++ b/fuzzers/baby/tutorial/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/index.html b/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/index.html new file mode 100644 index 0000000000..f7077f9d6c --- /dev/null +++ b/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/index.html @@ -0,0 +1,14 @@ + + + + + libafl_wasm test + + + + + \ No newline at end of file diff --git a/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/package.json b/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/package.json new file mode 100644 index 0000000000..cdfba2f3b8 --- /dev/null +++ b/fuzzers/fuzz_anything/baby_fuzzer_wasm/pkg/package.json @@ -0,0 +1,17 @@ +{ + "name": "baby_fuzzer_wasm", + "collaborators": [ + "Addison Crump " + ], + "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/*" + ] +} \ No newline at end of file diff --git a/fuzzers/inprocess/dynamic_analysis/src/lib.rs b/fuzzers/inprocess/dynamic_analysis/src/lib.rs index 89c95facf5..0c655c6de8 100644 --- a/fuzzers/inprocess/dynamic_analysis/src/lib.rs +++ b/fuzzers/inprocess/dynamic_analysis/src/lib.rs @@ -176,7 +176,7 @@ fn run_testcases(filenames: &[&str]) { // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. let args: Vec = 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 = 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 }; diff --git a/fuzzers/inprocess/fuzzbench/src/lib.rs b/fuzzers/inprocess/fuzzbench/src/lib.rs index 4e308071d4..16db9882d6 100644 --- a/fuzzers/inprocess/fuzzbench/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench/src/lib.rs @@ -174,7 +174,7 @@ fn run_testcases(filenames: &[&str]) { // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. let args: Vec = 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 = 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 }; diff --git a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs index 3ccb152989..4a368ced85 100644 --- a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs @@ -179,7 +179,7 @@ fn run_testcases(filenames: &[&str]) { // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. let args: Vec = 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 = 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 }; diff --git a/fuzzers/inprocess/fuzzbench_text/src/lib.rs b/fuzzers/inprocess/fuzzbench_text/src/lib.rs index 2d7f81ea4b..8dc73143e4 100644 --- a/fuzzers/inprocess/fuzzbench_text/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_text/src/lib.rs @@ -236,7 +236,7 @@ fn run_testcases(filenames: &[&str]) { // The actual target run starts here. // Call LLVMFUzzerInitialize() if present. let args: Vec = 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 = 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 = 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 }; diff --git a/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs index ab029f1c34..2384a53239 100644 --- a/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libmozjpeg/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs index 8008bf94f3..9718674d32 100644 --- a/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs index 60a5f7c514..729ed948ac 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_accounting/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs index ae7da19c3a..60a42e27af 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_centralized/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs index 1e0000aaad..823b04d79d 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_cmin/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_launcher/src/lib.rs index 6d626124e4..c863f51a54 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_launcher/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_norestart/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_norestart/src/lib.rs index 79f9e22ade..17e5670d91 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_norestart/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_norestart/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs index bc9a60b381..e2b23d599e 100644 --- a/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_libpng_tcp_manager/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_stb_image/src/main.rs b/fuzzers/inprocess/libfuzzer_stb_image/src/main.rs index 964d2b26c5..77e7e06f1d 100644 --- a/fuzzers/inprocess/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/inprocess/libfuzzer_stb_image/src/main.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/libfuzzer_stb_image_sugar/src/main.rs b/fuzzers/inprocess/libfuzzer_stb_image_sugar/src/main.rs index ef4f169fd1..70722fdd53 100644 --- a/fuzzers/inprocess/libfuzzer_stb_image_sugar/src/main.rs +++ b/fuzzers/inprocess/libfuzzer_stb_image_sugar/src/main.rs @@ -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 = 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() diff --git a/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs b/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs index 5623242966..3ae7f82b15 100644 --- a/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs +++ b/fuzzers/inprocess/libfuzzer_windows_asan/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/inprocess/sqlite_centralized_multi_machine/src/lib.rs b/fuzzers/inprocess/sqlite_centralized_multi_machine/src/lib.rs index f2d37be2ee..356af56373 100644 --- a/fuzzers/inprocess/sqlite_centralized_multi_machine/src/lib.rs +++ b/fuzzers/inprocess/sqlite_centralized_multi_machine/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/structure_aware/libfuzzer_stb_image_concolic/fuzzer/src/main.rs b/fuzzers/structure_aware/libfuzzer_stb_image_concolic/fuzzer/src/main.rs index 611b4cb05e..a88b71ca7b 100644 --- a/fuzzers/structure_aware/libfuzzer_stb_image_concolic/fuzzer/src/main.rs +++ b/fuzzers/structure_aware/libfuzzer_stb_image_concolic/fuzzer/src/main.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/fuzzers/structure_aware/nautilus_sync/Makefile.toml b/fuzzers/structure_aware/nautilus_sync/Makefile.toml index acf021f9b5..4e821c4c80 100644 --- a/fuzzers/structure_aware/nautilus_sync/Makefile.toml +++ b/fuzzers/structure_aware/nautilus_sync/Makefile.toml @@ -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"] diff --git a/fuzzers/structure_aware/nautilus_sync/src/lib.rs b/fuzzers/structure_aware/nautilus_sync/src/lib.rs index ecfe0df244..309f0e6b02 100644 --- a/fuzzers/structure_aware/nautilus_sync/src/lib.rs +++ b/fuzzers/structure_aware/nautilus_sync/src/lib.rs @@ -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 = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { + if unsafe { libfuzzer_initialize(&args) } == -1 { println!("Warning: LLVMFuzzerInitialize failed with -1"); } diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index a63a6032e4..207d9367b5 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -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 } diff --git a/libafl/src/executors/hooks/inprocess_fork.rs b/libafl/src/executors/hooks/inprocess_fork.rs index 2602aa1d43..e11dcbbd5e 100644 --- a/libafl/src/executors/hooks/inprocess_fork.rs +++ b/libafl/src/executors/hooks/inprocess_fork.rs @@ -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 diff --git a/libafl/src/executors/hooks/timer.rs b/libafl/src/executors/hooks/timer.rs index c8a585c030..9d93d18d48 100644 --- a/libafl/src/executors/hooks/timer.rs +++ b/libafl/src/executors/hooks/timer.rs @@ -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); diff --git a/libafl/src/observers/map/hitcount_map.rs b/libafl/src/observers/map/hitcount_map.rs index b17379434f..132f07b455 100644 --- a/libafl/src/observers/map/hitcount_map.rs +++ b/libafl/src/observers/map/hitcount_map.rs @@ -38,11 +38,11 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [ static mut COUNT_CLASS_LOOKUP_16: Vec = 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); diff --git a/libafl_bolts/src/core_affinity.rs b/libafl_bolts/src/core_affinity.rs index da06b5b160..d3bbcbfc6b 100644 --- a/libafl_bolts/src/core_affinity.rs +++ b/libafl_bolts/src/core_affinity.rs @@ -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::() } } @@ -733,6 +735,8 @@ mod netbsd { } fn new_cpuset() -> *mut _cpuset { + // # Safety + // Simply creating new empty cpuset. No user-provided params. unsafe { _cpuset_create() } } } diff --git a/libafl_bolts/src/llmp.rs b/libafl_bolts/src/llmp.rs index af7f1402b1..10de1e1cb8 100644 --- a/libafl_bolts/src/llmp.rs +++ b/libafl_bolts/src/llmp.rs @@ -663,6 +663,8 @@ impl LlmpMsg { /// Gets the buffer from this message as slice, with the correct length. #[inline] pub fn try_as_slice(&self, map: &mut LlmpSharedMap) -> 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, 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, client_id: u32) -> Result<(), Error> { + // # Safety + // No user-provided potentially unsafe parameters. unsafe { let msg = sender .alloc_next(size_of::()) diff --git a/libafl_bolts/src/serdeany.rs b/libafl_bolts/src/serdeany.rs index be5b956b92..37ec99dc6c 100644 --- a/libafl_bolts/src/serdeany.rs +++ b/libafl_bolts/src/serdeany.rs @@ -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(); } diff --git a/libafl_bolts/src/shmem.rs b/libafl_bolts/src/shmem.rs index c34121ab21..a78ad04aef 100644 --- a/libafl_bolts/src/shmem.rs +++ b/libafl_bolts/src/shmem.rs @@ -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 { + // # 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 { + // # 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")] diff --git a/libafl_frida/src/alloc.rs b/libafl_frida/src/alloc.rs index b57f20a4e8..232e8d2a16 100644 --- a/libafl_frida/src/alloc.rs +++ b/libafl_frida/src/alloc.rs @@ -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( diff --git a/libafl_frida/src/asan/asan_rt.rs b/libafl_frida/src/asan/asan_rt.rs index 12cdb21190..1a37024861 100644 --- a/libafl_frida/src/asan/asan_rt.rs +++ b/libafl_frida/src/asan/asan_rt.rs @@ -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); } diff --git a/libafl_frida/src/asan/hook_funcs.rs b/libafl_frida/src/asan/hook_funcs.rs index 7cd575cdf4..3d5a122f61 100644 --- a/libafl_frida/src/asan/hook_funcs.rs +++ b/libafl_frida/src/asan/hook_funcs.rs @@ -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, diff --git a/libafl_nyx/src/executor.rs b/libafl_nyx/src/executor.rs index d219d1d379..c7d7b3abf1 100644 --- a/libafl_nyx/src/executor.rs +++ b/libafl_nyx/src/executor.rs @@ -138,8 +138,11 @@ where } impl NyxExecutor { - /// 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) } diff --git a/libafl_qemu/libafl_qemu_build/src/lib.rs b/libafl_qemu/libafl_qemu_build/src/lib.rs index 0095defef7..e09d8b35ad 100644 --- a/libafl_qemu/libafl_qemu_build/src/lib.rs +++ b/libafl_qemu/libafl_qemu_build/src/lib.rs @@ -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> = None; +static CARGO_RPATH: LazyLock>> = 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}"); } } diff --git a/libafl_qemu/libafl_qemu_sys/src/lib.rs b/libafl_qemu/libafl_qemu_sys/src/lib.rs index b377e195b6..e3c480ee4e 100644 --- a/libafl_qemu/libafl_qemu_sys/src/lib.rs +++ b/libafl_qemu/libafl_qemu_sys/src/lib.rs @@ -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 } } diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index 542d487d91..7d15e6c3ef 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -650,7 +650,9 @@ where } } - pub fn backdoor_closure(&mut self, hook: BackdoorHookClosure) -> BackdoorHookId { + /// # Safety + /// Will dereference the hook as [`FatPtr`]. + pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure) -> BackdoorHookId { unsafe { let fat: FatPtr = transmute(hook); self.backdoor_hooks @@ -689,7 +691,9 @@ where } } - pub fn backdoor(&mut self, hook: BackdoorHook) -> Option { + /// # Safety + /// This can call through to a potentialy unsafe `backtoor_function` + pub unsafe fn backdoor(&mut self, hook: BackdoorHook) -> Option { 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) -> PreSyscallHookId { + // # Safety + // Will dereference the hook as [`FatPtr`]. unsafe { self.qemu_hooks .add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::) @@ -788,6 +794,8 @@ where #[allow(clippy::type_complexity)] pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure) -> 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) -> 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::) @@ -869,12 +879,16 @@ where } pub fn crash_function(&mut self, hook: fn(&mut EmulatorModules, target_signal: i32)) { + // # Safety + // Will cast the valid hook to a ptr. self.qemu_hooks.set_crash_hook(crash_hook_wrapper::); self.crash_hooks .push(HookRepr::Function(hook as *const libc::c_void)); } pub fn crash_closure(&mut self, hook: CrashHookClosure) { + // # Safety + // Will cast the hook to a [`FatPtr`]. unsafe { self.qemu_hooks.set_crash_hook(crash_hook_wrapper::); self.crash_hooks.push(HookRepr::Closure(transmute(hook))); @@ -1044,7 +1058,9 @@ where ) } - pub fn backdoor(&mut self, hook: BackdoorHook) -> Option { + /// # Safety + /// This will potentially call an unsafe backdoor hook + pub unsafe fn backdoor(&mut self, hook: BackdoorHook) -> Option { self.hooks.backdoor(hook) } @@ -1052,7 +1068,9 @@ where self.hooks.backdoor_function(hook) } - pub fn backdoor_closure(&mut self, hook: BackdoorHookClosure) -> BackdoorHookId { + /// # Safety + /// Calls through to the potentially unsafe `backdoor_closure` + pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure) -> 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, @@ -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, @@ -1296,7 +1324,9 @@ where self.hooks.crash_function(hook); } - pub fn crash_closure(&mut self, hook: CrashHookClosure) { + /// # Safety + /// Calls through to the, potentially unsafe, registered `crash_closure` + pub unsafe fn crash_closure(&mut self, hook: CrashHookClosure) { self.hooks.crash_closure(hook); } } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 7ebf2c75bb..99d9a074c2 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -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( signal: Signal, @@ -89,7 +94,7 @@ pub unsafe fn inproc_qemu_timeout_handler( <::State as HasSolutions>::Solutions: Corpus, //delete me <<::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::( @@ -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( diff --git a/libafl_qemu/src/modules/calls.rs b/libafl_qemu/src/modules/calls.rs index 1bf3023894..fca18ee30e 100644 --- a/libafl_qemu/src/modules/calls.rs +++ b/libafl_qemu/src/modules/calls.rs @@ -543,19 +543,19 @@ static mut CALLSTACKS: Option>>> = 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()) diff --git a/libafl_qemu/src/modules/cmplog.rs b/libafl_qemu/src/modules/cmplog.rs index 24711f8489..ebdae305bc 100644 --- a/libafl_qemu/src/modules/cmplog.rs +++ b/libafl_qemu/src/modules/cmplog.rs @@ -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; diff --git a/libafl_qemu/src/modules/edges.rs b/libafl_qemu/src/modules/edges.rs index 6cec27f1ed..42cd7ad90a 100644 --- a/libafl_qemu/src/modules/edges.rs +++ b/libafl_qemu/src/modules/edges.rs @@ -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); diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index be3d28ed31..5b475aa61f 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -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>, 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() { diff --git a/libafl_qemu/src/qemu/hooks.rs b/libafl_qemu/src/qemu/hooks.rs index 3004858ac0..fe55e75a52 100644 --- a/libafl_qemu/src/qemu/hooks.rs +++ b/libafl_qemu/src/qemu/hooks.rs @@ -549,7 +549,7 @@ create_hook_types!( EdgeExec, fn(&mut EmulatorModules, Option<&mut S>, id: u64), Box FnMut(&'a mut EmulatorModules, 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 { diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index 84a900b51f..4205c461aa 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -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); diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index 1bca46b698..9f1d1dea42 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -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); } diff --git a/libafl_targets/src/coverage.rs b/libafl_targets/src/coverage.rs index a6dfad6453..bfb5fa5d0e 100644 --- a/libafl_targets/src/coverage.rs +++ b/libafl_targets/src/coverage.rs @@ -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 { + // # 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 { /// 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() } } } diff --git a/libafl_targets/src/libfuzzer/mod.rs b/libafl_targets/src/libfuzzer/mod.rs index 47dcc1d9b7..5de51c0d4b 100644 --- a/libafl_targets/src/libfuzzer/mod.rs +++ b/libafl_targets/src/libfuzzer/mod.rs @@ -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 = 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()) } } diff --git a/libafl_targets/src/sancov_8bit.rs b/libafl_targets/src/sancov_8bit.rs index 9d81828d29..9eda43bbe5 100644 --- a/libafl_targets/src/sancov_8bit.rs +++ b/libafl_targets/src/sancov_8bit.rs @@ -27,10 +27,13 @@ pub unsafe fn extra_counters() -> Vec> { } /// 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 { diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index de98ca2faf..6e6f2f1ff5 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -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 // 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() } }