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. - [`binary_only`](./binary_only/): Fuzzers for binary-only targets.
- [`forkserver`](./forkserver/): Fuzzers that use a forkserver-style executor. - [`forkserver`](./forkserver/): Fuzzers that use a forkserver-style executor.
- [`full_system`](./full_system/): Fuzzers for full-system targets (kernels, firmwares, etc...). - [`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. - [`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. - [`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 mut harness = |input: &PacketData| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
// # Safety
// We're looking for crashes in there!
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -155,7 +159,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }
@ -191,8 +191,10 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![]; let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow"); file.read_to_end(&mut buffer).expect("Buffer overflow");
unsafe {
libfuzzer_test_one_input(&buffer); libfuzzer_test_one_input(&buffer);
} }
}
} }
/// The actual fuzzer /// The actual fuzzer
@ -296,7 +298,7 @@ fn fuzz(
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }
@ -331,7 +333,9 @@ fn fuzz(
let mut harness = |input: &BytesInput| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };

View File

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

View File

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

View File

@ -236,7 +236,7 @@ fn run_testcases(filenames: &[&str]) {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }
@ -251,8 +251,10 @@ fn run_testcases(filenames: &[&str]) {
let mut buffer = vec![]; let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("Buffer overflow"); file.read_to_end(&mut buffer).expect("Buffer overflow");
unsafe {
libfuzzer_test_one_input(&buffer); libfuzzer_test_one_input(&buffer);
} }
}
} }
/// The actual fuzzer /// The actual fuzzer
@ -357,7 +359,7 @@ fn fuzz_binary(
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }
@ -392,7 +394,9 @@ fn fuzz_binary(
let mut harness = |input: &BytesInput| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -570,7 +574,7 @@ fn fuzz_text(
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }
@ -618,7 +622,9 @@ fn fuzz_text(
let mut harness = |input: &BytesInput| { let mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok 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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -159,7 +161,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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; *addr = 1;
} }
} }
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -191,7 +193,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -227,7 +229,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -233,7 +235,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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; *addr = 1;
} }
} }
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -187,7 +189,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -232,7 +234,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -245,7 +247,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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; *addr = 1;
} }
} }
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -188,7 +190,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -137,7 +139,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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) { fn fuzz(input_dirs: &[PathBuf], output_dir: PathBuf, cores: &Cores, broker_port: u16) {
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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) .output_dir(output_dir)
.cores(cores) .cores(cores)
.broker_port(broker_port) .broker_port(broker_port)
.harness(|buf| { .harness(|buf| unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}) })
.build() .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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -155,7 +157,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -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 mut harness = |input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let buf = target.as_slice(); let buf = target.as_slice();
unsafe {
libfuzzer_test_one_input(buf); libfuzzer_test_one_input(buf);
}
ExitKind::Ok ExitKind::Ok
}; };
@ -252,7 +254,7 @@ pub extern "C" fn libafl_main() {
// The actual target run starts here. // The actual target run starts here.
// Call LLVMFUzzerInitialize() if present. // Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 { if unsafe { libfuzzer_initialize(&args) } == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1"); println!("Warning: LLVMFuzzerInitialize failed with -1");
} }

View File

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

View File

@ -63,7 +63,7 @@ script_runner = "@shell"
script = ''' script = '''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd "${PROJECT_DIR}" 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" 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"] dependencies = ["libpng", "cxx", "cc"]

View File

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

View File

@ -218,6 +218,8 @@ where
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
fn post_exec(&mut self, _state: &mut S, _input: &S::Input) { fn post_exec(&mut self, _state: &mut S, _input: &S::Input) {
// timeout stuff // 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"))))] #[cfg(all(feature = "std", not(all(miri, target_vendor = "apple"))))]
self.timer_mut().unset_timer(); self.timer_mut().unset_timer();
} }
@ -393,28 +395,38 @@ unsafe impl Send for InProcessExecutorHandlerData {}
unsafe impl Sync for InProcessExecutorHandlerData {} unsafe impl Sync for InProcessExecutorHandlerData {}
impl 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"))] #[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() } 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"))] #[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() } 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"))] #[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() } 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"))] #[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() } unsafe { (self.fuzzer_ptr as *mut Z).as_mut().unwrap() }
} }
/// # Safety
/// Only safe if not called concurrently.
#[cfg(any(unix, feature = "std"))] #[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() }; let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
self.current_input_ptr = ptr::null(); self.current_input_ptr = ptr::null();
r r
@ -463,36 +475,51 @@ pub(crate) static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExec
}; };
/// Get the inprocess [`crate::state::State`] /// 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] #[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() } unsafe { (GLOBAL_STATE.state_ptr as *mut S).as_mut() }
} }
/// Get the [`crate::events::EventManager`] /// 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] #[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() } unsafe { (GLOBAL_STATE.event_mgr_ptr as *mut EM).as_mut() }
} }
/// Gets the inprocess [`crate::fuzzer::Fuzzer`] /// 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] #[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() } unsafe { (GLOBAL_STATE.fuzzer_ptr as *mut F).as_mut() }
} }
/// Gets the inprocess [`Executor`] /// 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] #[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() } unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() }
} }
/// Gets the inprocess input /// 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] #[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() } 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] #[must_use]
pub fn inprocess_in_handler() -> bool { pub fn inprocess_in_handler() -> bool {
unsafe { GLOBAL_STATE.in_handler } unsafe { GLOBAL_STATE.in_handler }

View File

@ -107,19 +107,21 @@ unsafe impl Sync for InProcessForkExecutorGlobalData {}
unsafe impl Send for InProcessForkExecutorGlobalData {} unsafe impl Send for InProcessForkExecutorGlobalData {}
impl 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() } 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() } unsafe { (self.state_ptr as *mut S).as_mut().unwrap() }
} }
/*fn current_input<'a, I>(&self) -> &'a I { /// # Safety
unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() } /// Only safe if not called concurrently.
}*/ pub(crate) unsafe fn take_current_input<'a, I>(&mut self) -> &'a I {
pub(crate) fn take_current_input<'a, I>(&mut self) -> &'a I {
let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() }; let r = unsafe { (self.current_input_ptr as *const I).as_ref().unwrap() };
self.current_input_ptr = null(); self.current_input_ptr = null();
r r

View File

@ -256,6 +256,8 @@ impl TimerStruct {
#[cfg(all(unix, not(target_os = "linux")))] #[cfg(all(unix, not(target_os = "linux")))]
/// Set up timer /// Set up timer
pub fn set_timer(&mut self) { pub fn set_timer(&mut self) {
// # Safety
// Safe because the variables are all alive at this time and don't contain pointers.
unsafe { unsafe {
setitimer(ITIMER_REAL, &mut self.itimerval, core::ptr::null_mut()); setitimer(ITIMER_REAL, &mut self.itimerval, core::ptr::null_mut());
} }
@ -310,18 +312,22 @@ impl TimerStruct {
} }
#[cfg(all(unix, not(target_os = "linux")))] #[cfg(all(unix, not(target_os = "linux")))]
/// Disalarm timer /// Disable the timer
pub fn unset_timer(&mut self) { pub fn unset_timer(&mut self) {
// # Safety
// No user-provided values.
unsafe { unsafe {
let mut itimerval_zero: Itimerval = core::mem::zeroed(); let mut itimerval_zero: Itimerval = core::mem::zeroed();
setitimer(ITIMER_REAL, &mut itimerval_zero, core::ptr::null_mut()); setitimer(ITIMER_REAL, &mut itimerval_zero, core::ptr::null_mut());
} }
} }
/// Disalarm timer /// Disable the timer
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn unset_timer(&mut self) { pub fn unset_timer(&mut self) {
// # Safety
// Just API calls, no user-provided inputs
if self.batch_mode { if self.batch_mode {
unsafe { unsafe {
let elapsed = current_time().saturating_sub(self.tmout_start_time); let elapsed = current_time().saturating_sub(self.tmout_start_time);
@ -354,8 +360,10 @@ impl TimerStruct {
} }
#[cfg(windows)] #[cfg(windows)]
/// Disalarm /// Disable the timer
pub fn unset_timer(&mut self) { pub fn unset_timer(&mut self) {
// # Safety
// The value accesses are guarded by a critical section.
unsafe { unsafe {
let data = addr_of_mut!(GLOBAL_STATE); 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![]; static mut COUNT_CLASS_LOOKUP_16: Vec<u16> = vec![];
/// Initialize the 16-byte hitcounts map /// 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() { 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 { unsafe {
let count_class_lookup_16 = &mut *addr_of_mut!(COUNT_CLASS_LOOKUP_16); 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 { fn new_cpu_set() -> cpu_set_t {
// # Safety
// Returning a new zeroed value that is allowed to be 0.
unsafe { zeroed::<cpu_set_t>() } unsafe { zeroed::<cpu_set_t>() }
} }
@ -733,6 +735,8 @@ mod netbsd {
} }
fn new_cpuset() -> *mut _cpuset { fn new_cpuset() -> *mut _cpuset {
// # Safety
// Simply creating new empty cpuset. No user-provided params.
unsafe { _cpuset_create() } unsafe { _cpuset_create() }
} }
} }

View File

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

View File

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

View File

@ -693,6 +693,9 @@ pub mod unix_shmem {
/// Create a new [`MmapShMem`] /// 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 /// 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> { pub fn new(map_size: usize, rand_id: u32) -> Result<Self, Error> {
// # Safety
// No user-provided potentially unsafe parameters.
// FFI Calls.
unsafe { unsafe {
let mut full_file_name = format!("/libafl_{}_{}", process::id(), rand_id); let mut full_file_name = format!("/libafl_{}_{}", process::id(), rand_id);
// leave one byte space for the null byte. // leave one byte space for the null byte.
@ -765,6 +768,9 @@ pub mod unix_shmem {
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> { fn shmem_from_id_and_size(id: ShMemId, map_size: usize) -> Result<Self, Error> {
// # Safety
// No user-provided potentially unsafe parameters.
// FFI Calls.
unsafe { unsafe {
/* map the shared memory segment to the address space of the process */ /* map the shared memory segment to the address space of the process */
#[cfg(target_vendor = "apple")] #[cfg(target_vendor = "apple")]

View File

@ -324,7 +324,9 @@ impl Allocator {
continue; continue;
} }
// First poison the memory. // First poison the memory.
unsafe {
Self::poison(map_to_shadow!(self, address), allocation.size); Self::poison(map_to_shadow!(self, address), allocation.size);
}
// Reset the allocaiton metadata object // Reset the allocaiton metadata object
allocation.size = 0; 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 { unsafe {
std::slice::from_raw_parts_mut(start as *mut u8, size / 8).fill(0xff); 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 /// Poison an area in memory
pub fn poison(start: usize, size: usize) { ///
/// # 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 { unsafe {
std::slice::from_raw_parts_mut(start as *mut u8, size / 8).fill(0x0); std::slice::from_raw_parts_mut(start as *mut u8, size / 8).fill(0x0);
@ -445,8 +454,10 @@ impl Allocator {
} }
if unpoison { if unpoison {
unsafe {
Self::unpoison(shadow_mapping_start, end - start); Self::unpoison(shadow_mapping_start, end - start);
} }
}
(shadow_mapping_start, (end - start) / 8 + 1) (shadow_mapping_start, (end - start) / 8 + 1)
} }
@ -633,6 +644,8 @@ impl Allocator {
size = 0; size = 0;
} }
} }
/// Unpoisons all memory
#[cfg(not(target_vendor = "apple"))] #[cfg(not(target_vendor = "apple"))]
pub fn unpoison_all_existing_memory(&mut self) { pub fn unpoison_all_existing_memory(&mut self) {
RangeDetails::enumerate_with_prot( RangeDetails::enumerate_with_prot(

View File

@ -216,7 +216,11 @@ impl FridaRuntime for AsanRuntime {
let target_bytes = input.target_bytes(); let target_bytes = input.target_bytes();
let slice = target_bytes.as_slice(); let slice = target_bytes.as_slice();
// # Safety
// The ptr and length are correct.
unsafe {
self.poison(slice.as_ptr() as usize, slice.len()); self.poison(slice.as_ptr() as usize, slice.len());
}
self.reset_allocations(); self.reset_allocations();
Ok(()) Ok(())
@ -282,7 +286,11 @@ impl AsanRuntime {
} }
/// Make sure the specified memory is poisoned /// 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); Allocator::poison(self.allocator.map_to_shadow(address), size);
} }

View File

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

View File

@ -138,8 +138,11 @@ where
} }
impl<S, OT> NyxExecutor<S, OT> { impl<S, OT> NyxExecutor<S, OT> {
/// convert `trace_bits` ptr into real trace map /// Convert `trace_bits` ptr into real trace map
pub fn trace_bits(self) -> &'static mut [u8] { ///
/// # Safety
/// Mutable borrow may only be used once at a time.
pub unsafe fn trace_bits(self) -> &'static mut [u8] {
unsafe { unsafe {
std::slice::from_raw_parts_mut(self.helper.bitmap_buffer, self.helper.bitmap_size) 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::io::{BufRead, BufReader};
use std::{ use std::{
collections::hash_map, collections::hash_map,
env, fs, env,
fs::File, fs::{self, File},
hash::Hasher, hash::Hasher,
io::{Read, Seek, SeekFrom, Write}, io::{Read, Seek, SeekFrom, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
process::Command, process::Command,
ptr::addr_of_mut, sync::{LazyLock, Mutex},
}; };
//#[rustversion::nightly] //#[rustversion::nightly]
@ -30,26 +30,22 @@ use crate::build::QEMU_REVISION;
const LLVM_VERSION_MAX: i32 = 33; 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 = "|"; 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) { pub fn cargo_add_rpath(rpath: &str) {
unsafe { CARGO_RPATH.lock().unwrap().push(rpath.to_string());
if let Some(rpaths) = &mut *addr_of_mut!(CARGO_RPATH) {
rpaths.push(rpath.to_string());
} else {
CARGO_RPATH = Some(vec![rpath.to_string()]);
}
}
} }
// Print the `rpath`, set via [`cargo_add_rpath`] as `cargo::rpath`
pub fn cargo_propagate_rpath() { pub fn cargo_propagate_rpath() {
unsafe { let cargo_cmds = CARGO_RPATH.lock().unwrap();
if let Some(cargo_cmds) = &mut *addr_of_mut!(CARGO_RPATH) { if !cargo_cmds.is_empty() {
let rpath = cargo_cmds.join(CARGO_RPATH_SEPARATOR); let rpath = cargo_cmds.join(CARGO_RPATH_SEPARATOR);
println!("cargo:rpath={rpath}"); println!("cargo:rpath={rpath}");
} }
}
} }
/// Must be called from final binary crates /// Must be called from final binary crates

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 // from include/hw/core/cpu.h
/// # Safety
/// Will dereference the `cpu` pointer.
#[cfg(target_os = "linux")] #[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 } 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 { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
self.backdoor_hooks 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 { match hook {
Hook::Function(f) => Some(self.backdoor_function(f)), Hook::Function(f) => Some(self.backdoor_function(f)),
Hook::Closure(c) => Some(self.backdoor_closure(c)), Hook::Closure(c) => Some(self.backdoor_closure(c)),
@ -780,6 +784,8 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn syscalls_function(&mut self, hook: PreSyscallHookFn<ET, S>) -> PreSyscallHookId { pub fn syscalls_function(&mut self, hook: PreSyscallHookFn<ET, S>) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe { unsafe {
self.qemu_hooks self.qemu_hooks
.add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<ET, S>) .add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<ET, S>)
@ -788,6 +794,8 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure<ET, S>) -> PreSyscallHookId { pub fn syscalls_closure(&mut self, hook: PreSyscallHookClosure<ET, S>) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe { unsafe {
let fat: FatPtr = transmute(hook); let fat: FatPtr = transmute(hook);
@ -830,6 +838,8 @@ where
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn after_syscalls_function(&mut self, hook: PostSyscallHookFn<ET, S>) -> PostSyscallHookId { pub fn after_syscalls_function(&mut self, hook: PostSyscallHookFn<ET, S>) -> PostSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`]. This should be ok.
unsafe { unsafe {
self.qemu_hooks self.qemu_hooks
.add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<ET, S>) .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)) { 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.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.crash_hooks self.crash_hooks
.push(HookRepr::Function(hook as *const libc::c_void)); .push(HookRepr::Function(hook as *const libc::c_void));
} }
pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) { pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
// # Safety
// Will cast the hook to a [`FatPtr`].
unsafe { unsafe {
self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>); self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.crash_hooks.push(HookRepr::Closure(transmute(hook))); 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) self.hooks.backdoor(hook)
} }
@ -1052,7 +1068,9 @@ where
self.hooks.backdoor_function(hook) 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) self.hooks.backdoor_closure(hook)
} }
@ -1119,6 +1137,8 @@ where
} }
pub fn first_exec_all(&mut self, state: &mut S) { pub fn first_exec_all(&mut self, state: &mut S) {
// # Safety
// We assume that the emulator was initialized correctly
unsafe { unsafe {
self.modules_mut() self.modules_mut()
.first_exec_all(Self::emulator_modules_mut_unchecked(), state); .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) { pub fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) {
// # Safety
// We assume that the emulator was initialized correctly
unsafe { unsafe {
self.modules_mut() self.modules_mut()
.pre_exec_all(Self::emulator_modules_mut_unchecked(), state, input); .pre_exec_all(Self::emulator_modules_mut_unchecked(), state, input);
@ -1201,8 +1223,10 @@ where
self.hooks.syscalls(hook) self.hooks.syscalls(hook)
} }
/// # Safety
/// Calls through to the, potentially unsafe, `syscalls_function`
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn syscalls_function( pub unsafe fn syscalls_function(
&mut self, &mut self,
hook: fn( hook: fn(
&mut EmulatorModules<ET, S>, &mut EmulatorModules<ET, S>,
@ -1221,8 +1245,10 @@ where
self.hooks.syscalls_function(hook) self.hooks.syscalls_function(hook)
} }
/// # Safety
/// Calls through to the, potentially unsafe, `syscalls_closure`
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn syscalls_closure( pub unsafe fn syscalls_closure(
&mut self, &mut self,
hook: Box< hook: Box<
dyn for<'a> FnMut( dyn for<'a> FnMut(
@ -1248,8 +1274,10 @@ where
self.hooks.after_syscalls(hook) self.hooks.after_syscalls(hook)
} }
/// # Safety
/// Calls through to the, potentially unsafe, `after_syscalls_function`
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub fn after_syscalls_function( pub unsafe fn after_syscalls_function(
&mut self, &mut self,
hook: fn( hook: fn(
&mut EmulatorModules<ET, S>, &mut EmulatorModules<ET, S>,
@ -1296,7 +1324,9 @@ where
self.hooks.crash_function(hook); 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); self.hooks.crash_closure(hook);
} }
} }

View File

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

View File

@ -543,19 +543,19 @@ static mut CALLSTACKS: Option<ThreadLocal<UnsafeCell<Vec<GuestAddr>>>> = None;
#[derive(Debug)] #[derive(Debug)]
pub struct FullBacktraceCollector {} pub struct FullBacktraceCollector {}
impl Default for FullBacktraceCollector {
fn default() -> Self {
Self::new()
}
}
impl FullBacktraceCollector { 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()) }; unsafe { (*addr_of_mut!(CALLSTACKS)) = Some(ThreadLocal::new()) };
Self {} Self {}
} }
pub fn reset(&mut 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 { unsafe {
for tls in (*addr_of_mut!(CALLSTACKS)).as_mut().unwrap().iter_mut() { for tls in (*addr_of_mut!(CALLSTACKS)).as_mut().unwrap().iter_mut() {
(*tls.get()).clear(); (*tls.get()).clear();
@ -564,6 +564,9 @@ impl FullBacktraceCollector {
} }
pub fn backtrace() -> Option<&'static [GuestAddr]> { pub fn backtrace() -> Option<&'static [GuestAddr]> {
// # Safety
// This accesses the global [`CALLSTACKS`] variable.
// However, the actual variable access is behind a `ThreadLocal` class.
unsafe { unsafe {
if let Some(c) = (*addr_of_mut!(CALLSTACKS)).as_mut() { if let Some(c) = (*addr_of_mut!(CALLSTACKS)).as_mut() {
Some(&*c.get_or_default().get()) Some(&*c.get_or_default().get())

View File

@ -269,7 +269,9 @@ impl CmpLogRoutinesModule {
self.address_filter.allowed(&addr) 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 { unsafe {
if CMPLOG_ENABLED == 0 { if CMPLOG_ENABLED == 0 {
return; 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 { unsafe {
EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1); EDGES_MAP[id as usize] = EDGES_MAP[id as usize].wrapping_add(1);
} }
} }
pub extern "C" fn trace_edge_single(_: *const (), id: u64) { pub extern "C" fn trace_edge_single(_: *const (), id: u64) {
// # Safety
// Worst case we set the byte to 1 multiple times..
unsafe { unsafe {
EDGES_MAP[id as usize] = 1; EDGES_MAP[id as usize] = 1;
} }
@ -649,14 +653,19 @@ where
Some(id) 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 { unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize); let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = (*ptr).wrapping_add(1); *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 { unsafe {
let ptr = EDGES_MAP_PTR.add(id as usize); let ptr = EDGES_MAP_PTR.add(id as usize);
*ptr = 1; *ptr = 1;
@ -708,7 +717,9 @@ where
Some(id) 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 { unsafe {
PREV_LOC.with(|prev_loc| { PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1); 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 { unsafe {
PREV_LOC.with(|prev_loc| { PREV_LOC.with(|prev_loc| {
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1); 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) { 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() let backtrace = FullBacktraceCollector::backtrace()
.map(|r| { .map(|r| {
let mut v = r.to_vec(); let mut v = r.to_vec();
@ -504,6 +507,9 @@ impl AsanGiovese {
} }
pub fn alloc_free(&mut self, qemu: Qemu, pc: GuestAddr, addr: GuestAddr) { 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; let mut chunk = None;
self.alloc_map_mut(addr, |interval, item| { self.alloc_map_mut(addr, |interval, item| {
chunk = Some(*interval); chunk = Some(*interval);
@ -796,13 +802,20 @@ impl AsanModule {
} }
} }
/// # Safety
/// The `ASan` error report accesses [`FullBacktraceCollector`]
#[must_use] #[must_use]
pub fn with_asan_report( pub unsafe fn with_asan_report(
rt: Pin<Box<AsanGiovese>>, rt: Pin<Box<AsanGiovese>>,
filter: StdAddressFilter, filter: StdAddressFilter,
options: QemuAsanOptions, options: QemuAsanOptions,
) -> Self { ) -> 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] #[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::unnecessary_cast)]
#[allow(clippy::too_many_lines)] #[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(); let mut regions = HashMap::new();
for region in qemu.mappings() { for region in qemu.mappings() {
if let Some(path) = region.path() { if let Some(path) = region.path() {

View File

@ -549,7 +549,7 @@ create_hook_types!(
EdgeExec, EdgeExec,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, id: u64), 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)>, 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_hook_id!(Edge, libafl_qemu_remove_edge_hook, true);
create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId); create_gen_wrapper!(edge, (src: GuestAddr, dest: GuestAddr), u64, 1, EdgeHookId);
@ -746,7 +746,7 @@ impl QemuHooks {
&self, &self,
data: T, data: T,
addr: GuestAddr, addr: GuestAddr,
callback: extern "C" fn(T, GuestAddr), callback: unsafe extern "C" fn(T, GuestAddr),
invalidate_block: bool, invalidate_block: bool,
) -> InstructionHookId { ) -> InstructionHookId {
unsafe { unsafe {

View File

@ -1083,7 +1083,9 @@ pub mod pybind {
self.qemu.flush_jit(); 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 { unsafe {
let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS); let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS);
let idx = hooks.len(); 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 { unsafe {
let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS); let hooks = &mut *core::ptr::addr_of_mut!(PY_GENERIC_HOOKS);
hooks.retain(|(a, _)| *a != addr); hooks.retain(|(a, _)| *a != addr);

View File

@ -338,7 +338,9 @@ pub mod pybind {
self.qemu.unmap(addr, size).map_err(PyValueError::new_err) 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 { unsafe {
(*core::ptr::addr_of_mut!(PY_SYSCALL_HOOK)) = Some(hook); (*core::ptr::addr_of_mut!(PY_SYSCALL_HOOK)) = Some(hook);
} }

View File

@ -7,6 +7,14 @@
feature = "sancov_ctx" feature = "sancov_ctx"
))] ))]
use alloc::borrow::Cow; 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; use core::ptr::addr_of_mut;
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[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. /// The map for edges.
#[no_mangle] #[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 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; pub use __afl_area_ptr_local as EDGES_MAP;
/// The map for data dependency /// The map for data dependency
#[no_mangle] #[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __ddg_area_ptr_local: [u8; DDG_MAP_SIZE] = [0; DDG_MAP_SIZE]; pub static mut __ddg_area_ptr_local: [u8; DDG_MAP_SIZE] = [0; DDG_MAP_SIZE];
pub use __ddg_area_ptr_local as DDG_MAP; pub use __ddg_area_ptr_local as DDG_MAP;
/// The map for accounting mem writes. /// The map for accounting mem writes.
#[no_mangle] #[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __afl_acc_memop_ptr_local: [u32; ACCOUNTING_MAP_SIZE] = [0; ACCOUNTING_MAP_SIZE]; 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; 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 /// Return Tokens from the compile-time token section
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[cfg(any(target_os = "linux", target_vendor = "apple"))]
pub fn autotokens() -> Result<Tokens, Error> { pub fn autotokens() -> Result<Tokens, Error> {
// # Safety
// All values are checked before dereferencing.
unsafe { unsafe {
if __token_start.is_null() || __token_stop.is_null() { if __token_start.is_null() || __token_stop.is_null() {
Ok(Tokens::default()) Ok(Tokens::default())
@ -73,6 +86,7 @@ pub fn autotokens() -> Result<Tokens, Error> {
/// The actual size we use for the map of edges. /// The actual size we use for the map of edges.
/// This is used for forkserver backend /// This is used for forkserver backend
#[no_mangle] #[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE; pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE;
#[cfg(any( #[cfg(any(
@ -182,7 +196,7 @@ pub fn edges_max_num() -> usize {
} }
#[cfg(not(feature = "pointer_maps"))] #[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. /// Calls the (native) libfuzzer initialize function.
/// Returns the value returned by the init function. /// Returns the value returned by the init function.
/// # Note ///
/// # Safety
/// Calls the libfuzzer-style init function which is native code. /// Calls the libfuzzer-style init function which is native code.
#[allow(clippy::similar_names)] #[allow(clippy::similar_names)]
#[allow(clippy::must_use_candidate)] // nobody uses that return code... #[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 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(); let argv: Vec<*const u8> = args.iter().map(|x| x.as_bytes().as_ptr()).collect();
assert!(argv.len() < i32::MAX as usize); 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 /// 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. /// 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)] #[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()) } 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`. /// Initialize the sancov `8-bit-counters` - usually called by `llvm`.
///
/// # Safety
/// Start and stop are being dereferenced.
#[no_mangle] #[no_mangle]
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
#[allow(clippy::not_unsafe_ptr_arg_deref)] #[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 { unsafe {
let counter_maps = &mut *addr_of_mut!(COUNTERS_MAPS); let counter_maps = &mut *addr_of_mut!(COUNTERS_MAPS);
for existing in counter_maps { for existing in counter_maps {

View File

@ -3,7 +3,11 @@
#[rustversion::nightly] #[rustversion::nightly]
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
use core::simd::num::SimdUint; 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( #[cfg(any(
feature = "sancov_ngram4", feature = "sancov_ngram4",
@ -186,7 +190,7 @@ unsafe fn update_ngram(pos: usize) -> usize {
let mut reduced = pos; let mut reduced = pos;
#[cfg(feature = "sancov_ngram4")] #[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 = prev_array_4.rotate_elements_right::<1>();
prev_array_4.shl_assign(SHR_4); prev_array_4.shl_assign(SHR_4);
prev_array_4.as_mut_array()[0] = pos as u32; 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")] #[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 = prev_array_8.rotate_elements_right::<1>();
prev_array_8.shl_assign(SHR_8); prev_array_8.shl_assign(SHR_8);
prev_array_8.as_mut_array()[0] = pos as u32; 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"))] #[cfg(not(feature = "pointer_maps"))]
{ {
let edges_map = &mut *addr_of_mut!(EDGES_MAP);
#[cfg(feature = "sancov_pcguard_edges")] #[cfg(feature = "sancov_pcguard_edges")]
{ {
*EDGES_MAP.get_unchecked_mut(pos) = 1; *(edges_map).get_unchecked_mut(pos) = 1;
} }
#[cfg(feature = "sancov_pcguard_hitcounts")] #[cfg(feature = "sancov_pcguard_hitcounts")]
{ {
let val = (*EDGES_MAP.get_unchecked(pos)).wrapping_add(1); let val = (*edges_map.get_unchecked(pos)).wrapping_add(1);
*EDGES_MAP.get_unchecked_mut(pos) = val; *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) { pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
#[cfg(feature = "pointer_maps")] #[cfg(feature = "pointer_maps")]
if EDGES_MAP_PTR.is_null() { 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 { 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"))] #[cfg(not(feature = "pointer_maps"))]
{ {
let edges_map_len = (*addr_of!(EDGES_MAP)).len();
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1); 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?}" "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)); 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 // SAFETY: Once PCS_BEG and PCS_END have been initialized, will not be written to again. So
// there's no TOCTOU issue. // there's no TOCTOU issue.
unsafe { unsafe {
let pc_tables = &*core::ptr::addr_of!(PC_TABLES); let pc_tables = &*addr_of!(PC_TABLES);
pc_tables.iter().copied() pc_tables.iter().copied()
} }
} }