Change fuzzbench_qemu fuzzer (#2520)

* change fuzzbench_qemu

* real test

* fix qemu crash hook

* update bindings

* fix fork executor, reduce trait bound overhead

* make EdgeModule depend on observer to get ptrs.

* do not make EdgeCoverageModule::new public

* map observer as builder call

* adapt examples with new edge coverage module builder.

* TMP: everyone is a variable length map observer

* reuse profile path script

* fix absolute paths

* remove some dependencies to make pipeline faster

* compile-time builder initialization check

---------

Co-authored-by: Romain Malmain <romain.malmain@pm.me>
This commit is contained in:
Dongjia "toka" Zhang 2024-10-08 15:18:13 +02:00 committed by GitHub
parent 7344fdf059
commit c12c6f31e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 733 additions and 574 deletions

View File

@ -66,28 +66,6 @@ jobs:
- name: Test libafl_targets no_std - name: Test libafl_targets no_std
run: cd libafl_targets && cargo test --no-default-features run: cd libafl_targets && cargo test --no-default-features
llvm-tester:
runs-on: ubuntu-24.04
continue-on-error: true
strategy:
matrix:
llvm-version: [ "16", "17" ] # Add 18 when KyleMayes/install-llvm-action enables it
steps:
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- name: Install curl
run: sudo apt-get install clang
- uses: dtolnay/rust-toolchain@stable
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{matrix.llvm-version}}"
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
with: { shared-key: "llvm-tester" }
- name: Build and test with llvm-${{ matrix.llvm-version }}
run: pwd && ls & cd libafl_cc && cargo build --release
ubuntu-doc-build: ubuntu-doc-build:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
@ -246,9 +224,7 @@ jobs:
fuzzers: fuzzers:
needs: needs:
- ubuntu
- fuzzers-preflight - fuzzers-preflight
- common
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
@ -355,7 +331,6 @@ jobs:
fuzzers-qemu: fuzzers-qemu:
needs: needs:
- common
- changes - changes
if: ${{ needs.changes.outputs.qemu == 'true' }} if: ${{ needs.changes.outputs.qemu == 'true' }}
strategy: strategy:

View File

@ -20,7 +20,7 @@ Try running the fuzzer with the `introspection` feature of the `libafl`. This wi
``` ```
let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len()); let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len());
``` ```
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_SIZE_IN_USE`. You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_DEFAULT_SIZE`.
## Q. I still have problems with my fuzzer. ## Q. I still have problems with my fuzzer.
Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord. Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord.

View File

@ -57,7 +57,7 @@ On your fuzzer side, you can allocate a shared memory region and make the `EDGES
```rust,ignore ```rust,ignore
let mut shmem; let mut shmem;
unsafe{ unsafe{
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap(); shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
} }
let shmem_buf = shmem.as_slice_mut(); let shmem_buf = shmem.as_slice_mut();
unsafe{ unsafe{

View File

@ -169,7 +169,7 @@ from libafl_target's `EDGES_MAP`.
In the future, instead of using: In the future, instead of using:
```rust,ignore ```rust,ignore
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_SIZE_IN_USE] }; let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_DEFAULT_SIZE] };
let edges_observer = StdMapObserver::new("edges", edges); let edges_observer = StdMapObserver::new("edges", edges);
``` ```

View File

@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
"x86_64", "x86_64",
"usermode", "usermode",
] } ] }
libafl_targets = { path = "../../../libafl_targets" }
log = { version = "0.4.22", features = ["release_max_level_info"] } log = { version = "0.4.22", features = ["release_max_level_info"] }
clap = { version = "4.5.18", features = ["default"] } clap = { version = "4.5.18", features = ["default"] }

View File

@ -1,11 +1,28 @@
env_scripts = ['''
#!@duckscript
profile = get_env PROFILE
if eq ${profile} "dev"
set_env PROFILE_DIR debug
else
set_env PROFILE_DIR ${profile}
end
''', '''
#!@duckscript
runs_on_ci = get_env RUN_ON_CI
if ${runs_on_ci}
cargo_target_dir = get_env CARGO_MAKE_CRATE_TARGET_DIRECTORY
set_env TARGET_DIR ${cargo_target_dir}
end
''']
# Variables # Variables
[env] [env]
FUZZER_NAME = 'libpng_harness' FUZZER_NAME = 'harness'
PROJECT_DIR = { script = ["pwd"] } PROJECT_DIR = { script = ["pwd"] }
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } } PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
PROFILE_DIR = { value = "release", condition = { env_not_set = [ TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"
"PROFILE_DIR",
] } }
[tasks.unsupported] [tasks.unsupported]
script_runner = "@shell" script_runner = "@shell"
@ -13,20 +30,6 @@ script = '''
echo "Qemu fuzzer not supported on windows" echo "Qemu fuzzer not supported on windows"
''' '''
# libpng
[tasks.libpng]
linux_alias = "libpng_unix"
mac_alias = "libpng_unix"
windows_alias = "unsupported"
[tasks.libpng_unix]
condition = { files_not_exist = ["./libpng-1.6.37"] }
script_runner = "@shell"
script = '''
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf v1.6.37.tar.gz
'''
# fuzzer # fuzzer
[tasks.fuzzer] [tasks.fuzzer]
linux_alias = "fuzzer_unix" linux_alias = "fuzzer_unix"
@ -46,20 +49,13 @@ windows_alias = "unsupported"
[tasks.harness_unix] [tasks.harness_unix]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd "${PROJECT_DIR}"
make -C libpng-1.6.37
cc -c "${PROJECT_DIR}/libfuzzer_main.c" cc -c "${PROJECT_DIR}/libfuzzer_main.c"
# Build the libpng harness cc \
c++ \ ./fuzz.c \
../../inprocess/libfuzzer_libpng/harness.cc \
./libpng-1.6.37/.libs/libpng16.a \
./libfuzzer_main.o \ ./libfuzzer_main.o \
-I./libpng-1.6.37/ \
-o ${FUZZER_NAME} \ -o ${FUZZER_NAME} \
-lm -lz -lm -lz
''' '''
dependencies = ["libpng"]
# Run the fuzzer # Run the fuzzer
[tasks.run] [tasks.run]
@ -72,16 +68,16 @@ command = "cargo"
args = [ args = [
"run", "run",
"--profile", "--profile",
"${PROFILE_DIR}", "${PROFILE}",
"./${FUZZER_NAME}", "./${FUZZER_NAME}",
"--", "--",
"--libafl-in", "--libafl-in",
"../libfuzzer_libpng/corpus", "./corpus",
"--libafl-out", "--libafl-out",
"./out", "./out",
"./${FUZZER_NAME}", "./${FUZZER_NAME}",
] ]
dependencies = ["harness", "fuzzer"] dependencies = ["harness"]
# Run the fuzzer # Run the fuzzer
[tasks.test] [tasks.test]
@ -93,7 +89,13 @@ windows_alias = "unsupported"
[tasks.test_unix] [tasks.test_unix]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
echo "This test is skipped. QEMU-based fuzzer doesn't work on Github runners" timeout 15s ${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_fork_qemu ${PROJECT_DIR}/harness -- --libafl-in ${PROJECT_DIR}/../../inprocess/libfuzzer_libpng/corpus --libafl-out ${PROJECT_DIR}/out ${PROJECT_DIR}/harness | tee fuzz_stdout.log
if grep -qa "objectives: 1" fuzz_stdout.log; then
echo "Fuzzer is working"
else
echo "Fuzzer does not generate any testcases or any crashes"
exit 1
fi
''' '''
dependencies = ["harness", "fuzzer"] dependencies = ["harness", "fuzzer"]
@ -108,7 +110,6 @@ windows_alias = "unsupported"
clear = true clear = true
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
rm -f ./${FUZZER_NAME} libfuzzer_main.o rm -f ./${FUZZER_NAME}
make -C libpng-1.6.37 clean
cargo clean cargo clean
''' '''

View File

@ -0,0 +1,19 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
char buf[8] = {'a', 'b', 'c', 'd'};
if (memcmp(Data, buf, 4) == 0) { abort(); }
return 0;
}
/*
int main() {
char buf [10] = {0};
LLVMFuzzerTestOneInput(buf, 10);
}*/

View File

@ -39,7 +39,7 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_time, current_time,
os::{dup2, unix_signals::Signal}, os::dup2,
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
@ -50,11 +50,12 @@ use libafl_qemu::{
filter_qemu_args, filter_qemu_args,
modules::{ modules::{
cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver}, cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver},
edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE}, edges::StdEdgeCoverageChildModule,
}, },
Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor, Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor,
QemuShutdownCause, Regs, QemuShutdownCause, Regs,
}; };
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
#[cfg(unix)] #[cfg(unix)]
use nix::unistd::dup; use nix::unistd::dup;
@ -148,10 +149,26 @@ fn fuzz(
env::remove_var("LD_LIBRARY_PATH"); env::remove_var("LD_LIBRARY_PATH");
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let env: Vec<(String, String)> = env::vars().collect();
let mut shmem_provider = StdShMemProvider::new()?;
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
let edges = edges_shmem.as_slice_mut();
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
// Create an observation channel using the coverage map
let mut edges_observer = unsafe {
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_DEFAULT_SIZE>::from_mut_ptr(
"edges",
edges.as_mut_ptr(),
))
.track_indices()
};
let emulator_modules = tuple_list!( let emulator_modules = tuple_list!(
StdEdgeCoverageChildModule::builder().build(), StdEdgeCoverageChildModule::builder()
.map_observer(edges_observer.as_mut())
.build()?,
CmpLogChildModule::default(), CmpLogChildModule::default(),
); );
@ -218,12 +235,6 @@ fn fuzz(
writeln!(log.borrow_mut(), "{:?} {s}", current_time()).unwrap(); writeln!(log.borrow_mut(), "{:?} {s}", current_time()).unwrap();
}); });
let mut shmem_provider = StdShMemProvider::new()?;
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
let edges = edges_shmem.as_slice_mut();
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap(); let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap();
let cmplog = cmp_shmem.as_slice_mut(); let cmplog = cmp_shmem.as_slice_mut();
@ -247,15 +258,6 @@ fn fuzz(
}, },
}; };
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr(
"edges",
edges.as_mut_ptr(),
))
.track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -321,7 +323,7 @@ fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// The wrapped harness function, calling out to the LLVM-style harness // The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| { let mut harness = |emulator: &mut Emulator<_, _, _, _, _>, input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let mut buf = target.as_slice(); let mut buf = target.as_slice();
let mut len = buf.len(); let mut len = buf.len();
@ -339,16 +341,17 @@ fn fuzz(
qemu.write_reg(Regs::Rsp, stack_ptr).unwrap(); qemu.write_reg(Regs::Rsp, stack_ptr).unwrap();
match qemu.run() { match qemu.run() {
Ok(QemuExitReason::Breakpoint(_)) => {} Ok(QemuExitReason::Breakpoint(_)) => ExitKind::Ok,
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => { Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => {
process::exit(0) signal.handle();
panic!("Unexpected signal: {signal:?}");
}
Err(QemuExitError::UnexpectedExit) => ExitKind::Crash,
_ => {
panic!("Unexpected QEMU exit.")
} }
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
_ => panic!("Unexpected QEMU exit."),
} }
} }
ExitKind::Ok
}; };
let executor = QemuForkExecutor::new( let executor = QemuForkExecutor::new(
@ -391,8 +394,8 @@ fn fuzz(
#[cfg(unix)] #[cfg(unix)]
{ {
let null_fd = file_null.as_raw_fd(); let null_fd = file_null.as_raw_fd();
dup2(null_fd, io::stdout().as_raw_fd())?; // dup2(null_fd, io::stdout().as_raw_fd())?;
dup2(null_fd, io::stderr().as_raw_fd())?; // dup2(null_fd, io::stderr().as_raw_fd())?;
} }
// reopen file to make sure we're at the end // reopen file to make sure we're at the end
log.replace( log.replace(

View File

@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
"x86_64", "x86_64",
"usermode", "usermode",
] } ] }
libafl_targets = { path = "../../../libafl_targets", version = "0.13.2" }
log = { version = "0.4.22", features = ["release_max_level_info"] } log = { version = "0.4.22", features = ["release_max_level_info"] }
clap = { version = "4.5.18", features = ["default"] } clap = { version = "4.5.18", features = ["default"] }

View File

@ -1,11 +1,12 @@
# Variables # Variables
[env] [env]
FUZZER_NAME = 'libpng_harness' FUZZER_NAME = 'harness'
PROJECT_DIR = { script = ["pwd"] } PROJECT_DIR = { script = ["pwd"] }
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } } PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
PROFILE_DIR = { value = "release", condition = { env_not_set = [ PROFILE_DIR = { value = "release", condition = { env_not_set = [
"PROFILE_DIR", "PROFILE_DIR",
] } } ] } }
TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"
[tasks.unsupported] [tasks.unsupported]
script_runner = "@shell" script_runner = "@shell"
@ -13,20 +14,6 @@ script = '''
echo "Qemu fuzzer not supported on windows" echo "Qemu fuzzer not supported on windows"
''' '''
# libpng
[tasks.libpng]
linux_alias = "libpng_unix"
mac_alias = "libpng_unix"
windows_alias = "unsupported"
[tasks.libpng_unix]
condition = { files_not_exist = ["./libpng-1.6.37"] }
script_runner = "@shell"
script = '''
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf v1.6.37.tar.gz
'''
# fuzzer # fuzzer
[tasks.fuzzer] [tasks.fuzzer]
linux_alias = "fuzzer_unix" linux_alias = "fuzzer_unix"
@ -46,20 +33,13 @@ windows_alias = "unsupported"
[tasks.harness_unix] [tasks.harness_unix]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd "${PROJECT_DIR}"
make -C libpng-1.6.37
cc -c "${PROJECT_DIR}/libfuzzer_main.c" cc -c "${PROJECT_DIR}/libfuzzer_main.c"
# Build the libpng harness cc \
c++ \ ./fuzz.c \
../../inprocess/libfuzzer_libpng/harness.cc \
./libpng-1.6.37/.libs/libpng16.a \
./libfuzzer_main.o \ ./libfuzzer_main.o \
-I./libpng-1.6.37/ \
-o ${FUZZER_NAME} \ -o ${FUZZER_NAME} \
-lm -lz -lm -lz
''' '''
dependencies = ["libpng"]
# Run the fuzzer # Run the fuzzer
[tasks.run] [tasks.run]
@ -81,7 +61,7 @@ args = [
"./out", "./out",
"./${FUZZER_NAME}", "./${FUZZER_NAME}",
] ]
dependencies = ["harness", "fuzzer"] dependencies = ["harness"]
# Run the fuzzer # Run the fuzzer
[tasks.test] [tasks.test]
@ -93,7 +73,13 @@ windows_alias = "unsupported"
[tasks.test_unix] [tasks.test_unix]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
echo "This test is skipped. QEMU-based fuzzer doesn't work on Github runners" timeout 15s ${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_qemu ${PROJECT_DIR}/harness -- --libafl-in ${PROJECT_DIR}/../../inprocess/libfuzzer_libpng/corpus --libafl-out ${PROJECT_DIR}/out ${PROJECT_DIR}/harness | tee fuzz_stdout.log
if grep -qa "objectives: 1" fuzz_stdout.log; then
echo "Fuzzer is working"
else
echo "Fuzzer does not generate any testcases or any crashes"
exit 1
fi
''' '''
dependencies = ["harness", "fuzzer"] dependencies = ["harness", "fuzzer"]
@ -108,7 +94,6 @@ windows_alias = "unsupported"
clear = true clear = true
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
rm -f ./${FUZZER_NAME} libfuzzer_main.o rm -f ./${FUZZER_NAME}
make -C libpng-1.6.37 clean
cargo clean cargo clean
''' '''

View File

@ -0,0 +1,19 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
char buf[8] = {'a', 'b', 'c', 'd'};
if (memcmp(Data, buf, 4) == 0) { abort(); }
return 0;
}
/*
int main() {
char buf [10] = {0};
LLVMFuzzerTestOneInput(buf, 10);
}*/

View File

@ -38,7 +38,7 @@ use libafl::{
}; };
use libafl_bolts::{ use libafl_bolts::{
current_time, current_time,
os::{dup2, unix_signals::Signal}, os::dup2,
ownedref::OwnedMutSlice, ownedref::OwnedMutSlice,
rands::StdRand, rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
@ -50,9 +50,7 @@ use libafl_qemu::{
filter_qemu_args, filter_qemu_args,
// asan::{init_with_asan, QemuAsanHelper}, // asan::{init_with_asan, QemuAsanHelper},
modules::cmplog::{CmpLogModule, CmpLogObserver}, modules::cmplog::{CmpLogModule, CmpLogObserver},
modules::edges::{ modules::edges::StdEdgeCoverageModule,
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
Emulator, Emulator,
GuestReg, GuestReg,
//snapshot::QemuSnapshotHelper, //snapshot::QemuSnapshotHelper,
@ -64,6 +62,7 @@ use libafl_qemu::{
QemuShutdownCause, QemuShutdownCause,
Regs, Regs,
}; };
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_ALLOCATED_SIZE, MAX_EDGES_FOUND};
#[cfg(unix)] #[cfg(unix)]
use nix::unistd::dup; use nix::unistd::dup;
@ -253,10 +252,10 @@ fn fuzz(
}; };
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = unsafe { let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
addr_of_mut!(MAX_EDGES_FOUND), addr_of_mut!(MAX_EDGES_FOUND),
)) ))
.track_indices() .track_indices()
@ -347,9 +346,9 @@ fn fuzz(
match qemu.run() { match qemu.run() {
Ok(QemuExitReason::Breakpoint(_)) => {} Ok(QemuExitReason::Breakpoint(_)) => {}
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal( Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => {
Signal::SigInterrupt, signal.handle();
))) => process::exit(0), }
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash, Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
_ => panic!("Unexpected QEMU exit."), _ => panic!("Unexpected QEMU exit."),
} }
@ -359,7 +358,10 @@ fn fuzz(
}; };
let modules = tuple_list!( let modules = tuple_list!(
StdEdgeCoverageModule::builder().build(), StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
.unwrap(),
CmpLogModule::default(), CmpLogModule::default(),
// QemuAsanHelper::default(asan), // QemuAsanHelper::default(asan),
//QemuSnapshotHelper::new() //QemuSnapshotHelper::new()

View File

@ -34,5 +34,6 @@ clap = { version = "4.5.18", features = ["derive", "string"] }
libafl = { path = "../../../libafl" } libafl = { path = "../../../libafl" }
libafl_bolts = { path = "../../../libafl_bolts" } libafl_bolts = { path = "../../../libafl_bolts" }
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] } libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
libafl_targets = { path = "../../../libafl_targets" }
log = { version = "0.4.22", features = ["release_max_level_info"] } log = { version = "0.4.22", features = ["release_max_level_info"] }
rangemap = { version = "1.5.1" } rangemap = { version = "1.5.1" }

View File

@ -27,11 +27,11 @@ use libafl_bolts::{
AsSlice, AsSliceMut, AsSlice, AsSliceMut,
}; };
use libafl_qemu::{ use libafl_qemu::{
elf::EasyElf, elf::EasyElf, modules::edges::StdEdgeCoverageChildModule, ArchExtras, CallingConvention,
modules::edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE}, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuExitReason,
ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuForkExecutor, QemuShutdownCause, Regs,
QemuExitReason, QemuForkExecutor, QemuShutdownCause, Regs,
}; };
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
#[derive(Default)] #[derive(Default)]
pub struct Version; pub struct Version;
@ -155,12 +155,12 @@ pub fn fuzz() -> Result<(), Error> {
}, },
}; };
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap(); let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
let edges = edges_shmem.as_slice_mut(); let edges = edges_shmem.as_slice_mut();
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() }; unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
let edges_observer = unsafe { let mut edges_observer = unsafe {
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr( HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_DEFAULT_SIZE>::from_mut_ptr(
"edges", "edges",
edges.as_mut_ptr(), edges.as_mut_ptr(),
)) ))
@ -185,7 +185,7 @@ pub fn fuzz() -> Result<(), Error> {
let scheduler = QueueScheduler::new(); let scheduler = QueueScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut harness = |input: &BytesInput| { let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>, input: &BytesInput| {
let target = input.target_bytes(); let target = input.target_bytes();
let mut buf = target.as_slice(); let mut buf = target.as_slice();
let mut len = buf.len(); let mut len = buf.len();
@ -218,7 +218,9 @@ pub fn fuzz() -> Result<(), Error> {
ExitKind::Ok ExitKind::Ok
}; };
let modules = tuple_list!(StdEdgeCoverageChildModule::builder().build()); let modules = tuple_list!(StdEdgeCoverageChildModule::builder()
.map_observer(edges_observer.as_mut())
.build()?);
let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?; let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?;

View File

@ -47,6 +47,7 @@ libafl_bolts = { path = "../../../libafl_bolts", features = [
"errors_backtrace", "errors_backtrace",
] } ] }
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] } libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
libafl_targets = { path = "../../../libafl_targets" }
log = { version = "0.4.22", features = ["release_max_level_info"] } log = { version = "0.4.22", features = ["release_max_level_info"] }
nix = { version = "0.29.0", features = ["fs"] } nix = { version = "0.29.0", features = ["fs"] }
rangemap = { version = "1.5.1" } rangemap = { version = "1.5.1" }

View File

@ -1,4 +1,4 @@
use std::{env, ops::Range}; use std::env;
use libafl::{ use libafl::{
corpus::{InMemoryOnDiskCorpus, OnDiskCorpus}, corpus::{InMemoryOnDiskCorpus, OnDiskCorpus},
@ -16,8 +16,6 @@ use libafl_qemu::{
asan::{init_qemu_with_asan, AsanModule}, asan::{init_qemu_with_asan, AsanModule},
asan_guest::{init_qemu_with_asan_guest, AsanGuestModule}, asan_guest::{init_qemu_with_asan_guest, AsanGuestModule},
cmplog::CmpLogModule, cmplog::CmpLogModule,
edges::StdEdgeCoverageModule,
StdAddressFilter,
}, },
ArchExtras, GuestAddr, Qemu, ArchExtras, GuestAddr, Qemu,
}; };
@ -57,7 +55,7 @@ impl<'a> Client<'a> {
.collect::<Vec<(String, String)>>() .collect::<Vec<(String, String)>>()
} }
fn start_pc(qemu: &Qemu) -> Result<GuestAddr, Error> { fn start_pc(qemu: Qemu) -> Result<GuestAddr, Error> {
let mut elf_buffer = Vec::new(); let mut elf_buffer = Vec::new();
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?; let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
@ -67,39 +65,6 @@ impl<'a> Client<'a> {
Ok(start_pc) Ok(start_pc)
} }
#[allow(clippy::similar_names)] // elf != self
fn coverage_filter(&self, qemu: &Qemu) -> Result<StdAddressFilter, Error> {
/* Conversion is required on 32-bit targets, but not on 64-bit ones */
if let Some(includes) = &self.options.include {
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
let rules = includes
.iter()
.map(|x| Range {
start: x.start.into(),
end: x.end.into(),
})
.collect::<Vec<Range<GuestAddr>>>();
Ok(StdAddressFilter::allow_list(rules))
} else if let Some(excludes) = &self.options.exclude {
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
let rules = excludes
.iter()
.map(|x| Range {
start: x.start.into(),
end: x.end.into(),
})
.collect::<Vec<Range<GuestAddr>>>();
Ok(StdAddressFilter::deny_list(rules))
} else {
let mut elf_buffer = Vec::new();
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
let range = elf
.get_section(".text", qemu.load_addr())
.ok_or_else(|| Error::key_not_found("Failed to find .text section"))?;
Ok(StdAddressFilter::allow_list(vec![range]))
}
}
pub fn run<M: Monitor>( pub fn run<M: Monitor>(
&self, &self,
state: Option<ClientState>, state: Option<ClientState>,
@ -131,7 +96,7 @@ impl<'a> Client<'a> {
} }
}; };
let start_pc = Self::start_pc(&qemu)?; let start_pc = Self::start_pc(qemu)?;
log::debug!("start_pc @ {start_pc:#x}"); log::debug!("start_pc @ {start_pc:#x}");
#[cfg(not(feature = "injections"))] #[cfg(not(feature = "injections"))]
@ -163,10 +128,6 @@ impl<'a> Client<'a> {
let is_cmplog = self.options.is_cmplog_core(core_id); let is_cmplog = self.options.is_cmplog_core(core_id);
let edge_coverage_module = StdEdgeCoverageModule::builder()
.address_filter(self.coverage_filter(&qemu)?)
.build();
let extra_tokens = injection_module let extra_tokens = injection_module
.as_ref() .as_ref()
.map(|h| h.tokens.clone()) .map(|h| h.tokens.clone())
@ -174,7 +135,7 @@ impl<'a> Client<'a> {
let instance_builder = Instance::builder() let instance_builder = Instance::builder()
.options(self.options) .options(self.options)
.qemu(&qemu) .qemu(qemu)
.mgr(mgr) .mgr(mgr)
.core_id(core_id) .core_id(core_id)
.extra_tokens(extra_tokens); .extra_tokens(extra_tokens);
@ -183,7 +144,6 @@ impl<'a> Client<'a> {
if let Some(injection_module) = injection_module { if let Some(injection_module) = injection_module {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(
edge_coverage_module,
CmpLogModule::default(), CmpLogModule::default(),
AsanModule::default(asan.take().unwrap()), AsanModule::default(asan.take().unwrap()),
injection_module, injection_module,
@ -193,7 +153,6 @@ impl<'a> Client<'a> {
} else { } else {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(
edge_coverage_module,
CmpLogModule::default(), CmpLogModule::default(),
AsanModule::default(asan.take().unwrap()), AsanModule::default(asan.take().unwrap()),
), ),
@ -204,9 +163,8 @@ impl<'a> Client<'a> {
if let Some(injection_module) = injection_module { if let Some(injection_module) = injection_module {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(
edge_coverage_module,
CmpLogModule::default(), CmpLogModule::default(),
AsanGuestModule::default(&qemu, asan_lib.take().unwrap()), AsanGuestModule::default(qemu, asan_lib.take().unwrap()),
injection_module injection_module
), ),
state, state,
@ -214,9 +172,8 @@ impl<'a> Client<'a> {
} else { } else {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(
edge_coverage_module,
CmpLogModule::default(), CmpLogModule::default(),
AsanGuestModule::default(&qemu, asan_lib.take().unwrap()), AsanGuestModule::default(qemu, asan_lib.take().unwrap()),
), ),
state, state,
) )
@ -224,52 +181,35 @@ impl<'a> Client<'a> {
} else if is_asan { } else if is_asan {
if let Some(injection_module) = injection_module { if let Some(injection_module) = injection_module {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(AsanModule::default(asan.take().unwrap()), injection_module),
edge_coverage_module,
AsanModule::default(asan.take().unwrap()),
injection_module
),
state, state,
) )
} else { } else {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(AsanModule::default(asan.take().unwrap()),),
edge_coverage_module,
AsanModule::default(asan.take().unwrap()),
),
state, state,
) )
} }
} else if is_asan_guest { } else if is_asan_guest {
let modules = tuple_list!( let modules = tuple_list!(AsanGuestModule::default(qemu, asan_lib.take().unwrap()));
edge_coverage_module,
AsanGuestModule::default(&qemu, asan_lib.take().unwrap())
);
instance_builder.build().run(modules, state) instance_builder.build().run(modules, state)
} else if is_cmplog { } else if is_cmplog {
if let Some(injection_module) = injection_module { if let Some(injection_module) = injection_module {
instance_builder.build().run( instance_builder.build().run(
tuple_list!( tuple_list!(CmpLogModule::default(), injection_module),
edge_coverage_module,
CmpLogModule::default(),
injection_module
),
state, state,
) )
} else { } else {
instance_builder.build().run( instance_builder
tuple_list!(edge_coverage_module, CmpLogModule::default()), .build()
state, .run(tuple_list!(CmpLogModule::default()), state)
)
} }
} else if let Some(injection_module) = injection_module { } else if let Some(injection_module) = injection_module {
instance_builder instance_builder
.build() .build()
.run(tuple_list!(edge_coverage_module, injection_module), state) .run(tuple_list!(injection_module), state)
} else { } else {
instance_builder instance_builder.build().run(tuple_list!(), state)
.build()
.run(tuple_list!(edge_coverage_module), state)
} }
} }
} }

View File

@ -6,8 +6,8 @@ use libafl::{
use libafl_bolts::AsSlice; use libafl_bolts::AsSlice;
use libafl_qemu::{ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, Regs}; use libafl_qemu::{ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, Regs};
pub struct Harness<'a> { pub struct Harness {
qemu: &'a Qemu, qemu: Qemu,
input_addr: GuestAddr, input_addr: GuestAddr,
pc: GuestAddr, pc: GuestAddr,
stack_ptr: GuestAddr, stack_ptr: GuestAddr,
@ -16,8 +16,8 @@ pub struct Harness<'a> {
pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB
impl<'a> Harness<'a> { impl Harness {
pub fn new(qemu: &Qemu) -> Result<Harness, Error> { pub fn new(qemu: Qemu) -> Result<Harness, Error> {
let input_addr = qemu let input_addr = qemu
.map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite) .map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite)
.map_err(|e| Error::unknown(format!("Failed to map input buffer: {e:}")))?; .map_err(|e| Error::unknown(format!("Failed to map input buffer: {e:}")))?;

View File

@ -1,5 +1,5 @@
use core::{fmt::Debug, ptr::addr_of_mut}; use core::{fmt::Debug, ptr::addr_of_mut};
use std::{marker::PhantomData, process}; use std::{marker::PhantomData, ops::Range, process};
#[cfg(feature = "simplemgr")] #[cfg(feature = "simplemgr")]
use libafl::events::SimpleEventManager; use libafl::events::SimpleEventManager;
@ -35,16 +35,16 @@ use libafl_bolts::{
core_affinity::CoreId, core_affinity::CoreId,
ownedref::OwnedMutSlice, ownedref::OwnedMutSlice,
rands::StdRand, rands::StdRand,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge, Prepend},
}; };
use libafl_qemu::{ use libafl_qemu::{
elf::EasyElf,
modules::{ modules::{
cmplog::CmpLogObserver, cmplog::CmpLogObserver, EmulatorModuleTuple, StdAddressFilter, StdEdgeCoverageModule,
edges::{edges_map_mut_ptr, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND},
EmulatorModuleTuple,
}, },
Emulator, Qemu, QemuExecutor, Emulator, GuestAddr, Qemu, QemuExecutor,
}; };
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{harness::Harness, options::FuzzerOptions}; use crate::{harness::Harness, options::FuzzerOptions};
@ -61,7 +61,7 @@ pub type ClientMgr<M> =
#[derive(TypedBuilder)] #[derive(TypedBuilder)]
pub struct Instance<'a, M: Monitor> { pub struct Instance<'a, M: Monitor> {
options: &'a FuzzerOptions, options: &'a FuzzerOptions,
qemu: &'a Qemu, qemu: Qemu,
mgr: ClientMgr<M>, mgr: ClientMgr<M>,
core_id: CoreId, core_id: CoreId,
#[builder(default)] #[builder(default)]
@ -71,20 +71,60 @@ pub struct Instance<'a, M: Monitor> {
} }
impl<'a, M: Monitor> Instance<'a, M> { impl<'a, M: Monitor> Instance<'a, M> {
#[allow(clippy::similar_names)] // elf != self
fn coverage_filter(&self, qemu: Qemu) -> Result<StdAddressFilter, Error> {
/* Conversion is required on 32-bit targets, but not on 64-bit ones */
if let Some(includes) = &self.options.include {
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
let rules = includes
.iter()
.map(|x| Range {
start: x.start.into(),
end: x.end.into(),
})
.collect::<Vec<Range<GuestAddr>>>();
Ok(StdAddressFilter::allow_list(rules))
} else if let Some(excludes) = &self.options.exclude {
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
let rules = excludes
.iter()
.map(|x| Range {
start: x.start.into(),
end: x.end.into(),
})
.collect::<Vec<Range<GuestAddr>>>();
Ok(StdAddressFilter::deny_list(rules))
} else {
let mut elf_buffer = Vec::new();
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
let range = elf
.get_section(".text", qemu.load_addr())
.ok_or_else(|| Error::key_not_found("Failed to find .text section"))?;
Ok(StdAddressFilter::allow_list(vec![range]))
}
}
pub fn run<ET>(&mut self, modules: ET, state: Option<ClientState>) -> Result<(), Error> pub fn run<ET>(&mut self, modules: ET, state: Option<ClientState>) -> Result<(), Error>
where where
ET: EmulatorModuleTuple<ClientState> + Debug, ET: EmulatorModuleTuple<ClientState> + Debug,
{ {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = unsafe { let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
addr_of_mut!(MAX_EDGES_FOUND), addr_of_mut!(MAX_EDGES_FOUND),
)) ))
.track_indices() .track_indices()
}; };
let edge_coverage_module = StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.address_filter(self.coverage_filter(self.qemu)?)
.build()?;
let modules = modules.prepend(edge_coverage_module);
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -154,10 +194,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let emulator = Emulator::empty() let emulator = Emulator::empty().qemu(self.qemu).modules(modules).build()?;
.qemu(*self.qemu)
.modules(modules)
.build()?;
if self.options.is_cmplog_core(self.core_id) { if self.options.is_cmplog_core(self.core_id) {
// Create a QEMU in-process executor // Create a QEMU in-process executor

View File

@ -24,7 +24,7 @@ use libafl_bolts::{
tuples::{tuple_list, Handled, MatchNameRef, Merge}, tuples::{tuple_list, Handled, MatchNameRef, Merge},
AsSliceMut, Truncate, AsSliceMut, Truncate,
}; };
use libafl_targets::EDGES_MAP_SIZE_IN_USE; use libafl_targets::EDGES_MAP_DEFAULT_SIZE;
use nix::sys::signal::Signal; use nix::sys::signal::Signal;
/// The commandline args this fuzzer accepts /// The commandline args this fuzzer accepts
@ -87,7 +87,7 @@ struct Opt {
pub fn main() { pub fn main() {
env_logger::init(); env_logger::init();
const MAP_SIZE: usize = EDGES_MAP_SIZE_IN_USE; //65536; const MAP_SIZE: usize = EDGES_MAP_DEFAULT_SIZE; //65536;
let opt = Opt::parse(); let opt = Opt::parse();
let corpus_dirs: Vec<PathBuf> = [opt.in_dir].to_vec(); let corpus_dirs: Vec<PathBuf> = [opt.in_dir].to_vec();

View File

@ -28,6 +28,7 @@ codegen-units = 1
[dependencies] [dependencies]
libafl = { path = "../../../libafl" } libafl = { path = "../../../libafl" }
libafl_bolts = { path = "../../../libafl_bolts" } libafl_bolts = { path = "../../../libafl_bolts" }
libafl_targets = { path = "../../../libafl_targets" }
libafl_qemu = { path = "../../../libafl_qemu", features = [ libafl_qemu = { path = "../../../libafl_qemu", features = [
"arm", "arm",
"systemmode", "systemmode",

View File

@ -33,11 +33,11 @@ use libafl_qemu::{
elf::EasyElf, elf::EasyElf,
emu::Emulator, emu::Emulator,
executor::QemuExecutor, executor::QemuExecutor,
modules::edges::{ modules::edges::StdEdgeCoverageModule,
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
GuestPhysAddr, GuestReg, QemuMemoryChunk, GuestPhysAddr, GuestReg, QemuMemoryChunk,
}; };
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
// use libafl_qemu::QemuSnapshotBuilder; // for normal qemu snapshot // use libafl_qemu::QemuSnapshotBuilder; // for normal qemu snapshot
pub static mut MAX_INPUT_SIZE: usize = 50; pub static mut MAX_INPUT_SIZE: usize = 50;
@ -86,10 +86,33 @@ pub fn fuzz() {
let mut run_client = |state: Option<_>, mut mgr, _core_id| { let mut run_client = |state: Option<_>, mut mgr, _core_id| {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
emulator.run(state, input).unwrap().try_into().unwrap()
};
// Create an observation channel using the coverage map
let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Initialize QEMU Emulator // Initialize QEMU Emulator
let emu = Emulator::builder() let emu = Emulator::builder()
.qemu_cli(args) .qemu_cli(args)
.add_module(StdEdgeCoverageModule::builder().build()) .add_module(
StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()?,
)
.build() .build()
.unwrap(); .unwrap();
@ -119,25 +142,6 @@ pub fn fuzz() {
let devices = emu.list_devices(); let devices = emu.list_devices();
println!("Devices = {:?}", devices); println!("Devices = {:?}", devices);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
emulator.run(state, input).unwrap().try_into().unwrap()
};
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(

View File

@ -29,15 +29,11 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_qemu::{ use libafl_qemu::{
config, config, elf::EasyElf, executor::QemuExecutor, modules::edges::StdEdgeCoverageModuleBuilder,
elf::EasyElf,
executor::QemuExecutor,
modules::edges::{
edges_map_mut_ptr, StdEdgeCoverageModuleBuilder, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
Emulator, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, Regs, Emulator, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, Regs,
}; };
use libafl_qemu_sys::GuestPhysAddr; use libafl_qemu_sys::GuestPhysAddr;
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
pub static mut MAX_INPUT_SIZE: usize = 50; pub static mut MAX_INPUT_SIZE: usize = 50;
@ -86,6 +82,17 @@ pub fn fuzz() {
let mut run_client = |state: Option<_>, mut mgr, _core_id| { let mut run_client = |state: Option<_>, mut mgr, _core_id| {
let target_dir = env::var("TARGET_DIR").expect("TARGET_DIR env not set"); let target_dir = env::var("TARGET_DIR").expect("TARGET_DIR env not set");
// Create an observation channel using the coverage map
let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Initialize QEMU // Initialize QEMU
let qemu = Qemu::builder() let qemu = Qemu::builder()
.machine("mps2-an385") .machine("mps2-an385")
@ -103,7 +110,9 @@ pub fn fuzz() {
.build() .build()
.expect("Failed to initialized QEMU"); .expect("Failed to initialized QEMU");
let emulator_modules = tuple_list!(StdEdgeCoverageModuleBuilder::default().build()); let emulator_modules = tuple_list!(StdEdgeCoverageModuleBuilder::default()
.map_observer(edges_observer.as_mut())
.build()?);
let emulator = Emulator::empty() let emulator = Emulator::empty()
.qemu(qemu) .qemu(qemu)
@ -186,16 +195,6 @@ pub fn fuzz() {
} }
}; };
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");

View File

@ -26,13 +26,8 @@ use libafl_bolts::{
shmem::{ShMemProvider, StdShMemProvider}, shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list, tuples::tuple_list,
}; };
use libafl_qemu::{ use libafl_qemu::{emu::Emulator, executor::QemuExecutor, modules::edges::StdEdgeCoverageModule};
emu::Emulator, use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
executor::QemuExecutor,
modules::edges::{
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
};
// use libafl_qemu::QemuSnapshotBuilder; for normal qemu snapshot // use libafl_qemu::QemuSnapshotBuilder; for normal qemu snapshot
pub fn fuzz() { pub fn fuzz() {
@ -52,8 +47,20 @@ pub fn fuzz() {
// Initialize QEMU // Initialize QEMU
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
// Create an observation channel using the coverage map
let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Choose modules to use // Choose modules to use
let modules = tuple_list!(StdEdgeCoverageModule::builder().build()); let modules = tuple_list!(StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()?);
let emu = Emulator::builder() let emu = Emulator::builder()
.qemu_cli(args) .qemu_cli(args)
@ -69,16 +76,6 @@ pub fn fuzz() {
emulator.run(state, input).unwrap().try_into().unwrap() emulator.run(state, input).unwrap().try_into().unwrap()
}; };
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
addr_of_mut!(MAX_EDGES_FOUND),
))
.track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");

View File

@ -2,6 +2,12 @@
This folder contains an example linux kernel fuzzer using qemu systemmode. This folder contains an example linux kernel fuzzer using qemu systemmode.
## Warning
For now, only the fuzzer is public. We plan to release the auto-builder for linux
images in the near future.
If you wish to experiment now, you will need to build the linux image manually.
## Prerequisite ## Prerequisite
TODO TODO

View File

@ -36,7 +36,8 @@ use libafl_qemu::{
modules::{ modules::{
cmplog::CmpLogObserver, cmplog::CmpLogObserver,
edges::{ edges::{
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_SIZE_MAX, MAX_EDGES_FOUND, edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_ALLOCATED_SIZE,
MAX_EDGES_FOUND,
}, },
CmpLogModule, CmpLogModule,
}, },
@ -89,7 +90,7 @@ pub fn fuzz() {
let edges_observer = unsafe { let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_MAX), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
addr_of_mut!(MAX_EDGES_FOUND), addr_of_mut!(MAX_EDGES_FOUND),
)) ))
.track_indices() .track_indices()

View File

@ -3,6 +3,12 @@
This folder contains an example linux process fuzzer using qemu systemmode. This folder contains an example linux process fuzzer using qemu systemmode.
This is demo, most of the time for classic linux process fuzzing, it is better to use a more conventional method. This is demo, most of the time for classic linux process fuzzing, it is better to use a more conventional method.
## Warning
For now, only the fuzzer is public. We plan to release the auto-builder for linux
images in the near future.
If you wish to experiment now, you will need to build the linux image manually.
## Prerequisite ## Prerequisite
TODO TODO

View File

@ -36,7 +36,8 @@ use libafl_qemu::{
modules::{ modules::{
cmplog::CmpLogObserver, cmplog::CmpLogObserver,
edges::{ edges::{
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_SIZE_MAX, MAX_EDGES_FOUND, edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_ALLOCATED_SIZE,
MAX_EDGES_FOUND,
}, },
CmpLogModule, CmpLogModule,
}, },
@ -91,7 +92,7 @@ pub fn fuzz() {
let edges_observer = unsafe { let edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_MAX), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
addr_of_mut!(MAX_EDGES_FOUND), addr_of_mut!(MAX_EDGES_FOUND),
)) ))
.track_indices() .track_indices()

View File

@ -55,7 +55,7 @@ use libafl_bolts::{
use libafl_targets::autotokens; use libafl_targets::autotokens;
use libafl_targets::{ use libafl_targets::{
edges_map_mut_ptr, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CtxHook, edges_map_mut_ptr, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CtxHook,
EDGES_MAP_SIZE_IN_USE, EDGES_MAP_DEFAULT_SIZE,
}; };
#[cfg(unix)] #[cfg(unix)]
use nix::unistd::dup; use nix::unistd::dup;
@ -252,7 +252,7 @@ fn fuzz(
let edges_observer = HitcountsMapObserver::new(unsafe { let edges_observer = HitcountsMapObserver::new(unsafe {
StdMapObserver::from_mut_slice( StdMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
) )
}) })
.track_indices(); .track_indices();

View File

@ -40,10 +40,7 @@ use crate::{
/// The inmem executor's handlers. /// The inmem executor's handlers.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct InProcessHooks<S> pub struct InProcessHooks<S> {
where
S: UsesInput,
{
/// On crash C function pointer /// On crash C function pointer
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub crash_handler: *const c_void, pub crash_handler: *const c_void,

View File

@ -35,12 +35,7 @@ use crate::{
}; };
/// The internal state of `GenericInProcessExecutor`. /// The internal state of `GenericInProcessExecutor`.
pub struct GenericInProcessExecutorInner<HT, OT, S> pub struct GenericInProcessExecutorInner<HT, OT, S> {
where
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>,
S: State,
{
/// The observers, observing each run /// The observers, observing each run
pub(super) observers: OT, pub(super) observers: OT,
// Crash and timeout hah // Crash and timeout hah
@ -50,9 +45,7 @@ where
impl<HT, OT, S> Debug for GenericInProcessExecutorInner<HT, OT, S> impl<HT, OT, S> Debug for GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>, OT: Debug,
OT: ObserversTuple<S::Input, S> + Debug,
S: State,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("GenericInProcessExecutorState") f.debug_struct("GenericInProcessExecutorState")
@ -63,8 +56,6 @@ where
impl<HT, OT, S> UsesState for GenericInProcessExecutorInner<HT, OT, S> impl<HT, OT, S> UsesState for GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>,
S: State, S: State,
{ {
type State = S; type State = S;
@ -72,7 +63,6 @@ where
impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S> impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: State, S: State,
{ {
@ -92,7 +82,6 @@ where
impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S> impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>, HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>,
S: State, S: State,
{ {
/// This function marks the boundary between the fuzzer and the target /// This function marks the boundary between the fuzzer and the target
@ -156,7 +145,7 @@ impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>, HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: HasExecutions + HasSolutions + HasCorpus + State, S: HasCorpus + HasExecutions + HasSolutions + UsesInput,
{ {
/// Create a new in mem executor with the default timeout (5 sec) /// Create a new in mem executor with the default timeout (5 sec)
pub fn generic<E, EM, OF, Z>( pub fn generic<E, EM, OF, Z>(
@ -288,9 +277,7 @@ where
impl<HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutorInner<HT, OT, S> impl<HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutorInner<HT, OT, S>
where where
HT: ExecutorHooksTuple<S>, S: UsesInput,
OT: ObserversTuple<S::Input, S>,
S: State + HasExecutions + HasSolutions + HasCorpus,
{ {
/// the timeout handler /// the timeout handler
#[inline] #[inline]

View File

@ -35,15 +35,7 @@ use crate::{
}; };
/// Inner state of GenericInProcessExecutor-like structures. /// Inner state of GenericInProcessExecutor-like structures.
pub struct GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> pub struct GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> {
where
OT: ObserversTuple<S::Input, S>,
S: UsesInput,
SP: ShMemProvider,
HT: ExecutorHooksTuple<S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{
pub(super) hooks: (InChildProcessHooks<S>, HT), pub(super) hooks: (InChildProcessHooks<S>, HT),
pub(super) shmem_provider: SP, pub(super) shmem_provider: SP,
pub(super) observers: OT, pub(super) observers: OT,
@ -56,12 +48,9 @@ where
impl<HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> impl<HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
where where
OT: ObserversTuple<S::Input, S> + Debug, HT: Debug,
S: UsesInput, OT: Debug,
SP: ShMemProvider, SP: Debug,
HT: ExecutorHooksTuple<S> + Debug,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -86,12 +75,7 @@ where
impl<HT, OT, S, SP, EM, Z> UsesState for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> impl<HT, OT, S, SP, EM, Z> UsesState for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
where where
OT: ObserversTuple<S::Input, S>,
S: State, S: State,
SP: ShMemProvider,
HT: ExecutorHooksTuple<S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
type State = S; type State = S;
} }
@ -195,9 +179,6 @@ where
HT: ExecutorHooksTuple<S>, HT: ExecutorHooksTuple<S>,
S: State, S: State,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
SP: ShMemProvider,
EM: EventFirer<State = S> + EventRestarter<State = S>,
Z: UsesState<State = S>,
{ {
#[inline] #[inline]
/// This function marks the boundary between the fuzzer and the target. /// This function marks the boundary between the fuzzer and the target.
@ -319,12 +300,8 @@ where
impl<HT, OT, S, SP, EM, Z> HasObservers for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> impl<HT, OT, S, SP, EM, Z> HasObservers for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
where where
HT: ExecutorHooksTuple<S>,
S: State,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
SP: ShMemProvider, S: State,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
type Observers = OT; type Observers = OT;

View File

@ -24,7 +24,7 @@ use crate::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
observers::ObserversTuple, observers::ObserversTuple,
state::{HasExecutions, HasSolutions, State, UsesState}, state::{HasExecutions, State, UsesState},
Error, Error,
}; };
@ -32,15 +32,11 @@ use crate::{
pub type StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> = pub type StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> =
StatefulGenericInProcessForkExecutor<'a, H, (), OT, S, SP, ES, EM, Z>; StatefulGenericInProcessForkExecutor<'a, H, (), OT, S, SP, ES, EM, Z>;
impl<'a, H, OT, S, SP, ES, EM, Z, OF> StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> impl<'a, H, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
SP: ShMemProvider, S: State,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, S::Input, OT, S>,
S: State + HasSolutions,
Z: HasObjective<Objective = OF, State = S>,
{ {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
/// The constructor for `InProcessForkExecutor` /// The constructor for `InProcessForkExecutor`
@ -71,30 +67,26 @@ where
/// [`StatefulGenericInProcessForkExecutor`] is an executor that forks the current process before each execution. Harness can access some internal state. /// [`StatefulGenericInProcessForkExecutor`] is an executor that forks the current process before each execution. Harness can access some internal state.
pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z> pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>,
S: UsesInput, S: UsesInput,
SP: ShMemProvider,
HT: ExecutorHooksTuple<S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
/// The harness function, being executed for each fuzzing loop execution
harness_fn: &'a mut H, harness_fn: &'a mut H,
exposed_executor_state: ES, /// The state used as argument of the harness
inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>, pub exposed_executor_state: ES,
/// Inner state of the executor
pub inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>,
phantom: PhantomData<ES>, phantom: PhantomData<ES>,
} }
impl<H, HT, OT, S, SP, ES, EM, Z> Debug impl<H, HT, OT, S, SP, ES, EM, Z> Debug
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S> + Debug, HT: Debug,
OT: Debug,
S: UsesInput, S: UsesInput,
SP: ShMemProvider, SP: Debug,
HT: ExecutorHooksTuple<S> + Debug,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
@ -116,13 +108,8 @@ where
impl<H, HT, OT, S, SP, ES, EM, Z> UsesState impl<H, HT, OT, S, SP, ES, EM, Z> UsesState
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>,
S: State, S: State,
SP: ShMemProvider,
HT: ExecutorHooksTuple<S>,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
type State = S; type State = S;
} }
@ -130,14 +117,14 @@ where
impl<EM, H, HT, OT, S, SP, Z, ES, OF> Executor<EM, Z> impl<EM, H, HT, OT, S, SP, Z, ES, OF> Executor<EM, Z>
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, EM: EventFirer<State = S> + EventRestarter<State = S>,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HT: ExecutorHooksTuple<S>,
OF: Feedback<EM, S::Input, OT, S>,
OT: ObserversTuple<S::Input, S> + Debug, OT: ObserversTuple<S::Input, S> + Debug,
S: State + HasExecutions, S: State + HasExecutions,
SP: ShMemProvider, SP: ShMemProvider,
HT: ExecutorHooksTuple<S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
Z: HasObjective<Objective = OF, State = S>, Z: HasObjective<Objective = OF, State = S>,
OF: Feedback<EM, S::Input, OT, S>,
{ {
#[allow(unreachable_code)] #[allow(unreachable_code)]
#[inline] #[inline]
@ -156,7 +143,7 @@ where
Ok(ForkResult::Child) => { Ok(ForkResult::Child) => {
// Child // Child
self.inner.pre_run_target_child(fuzzer, state, mgr, input)?; self.inner.pre_run_target_child(fuzzer, state, mgr, input)?;
(self.harness_fn)(input, &mut self.exposed_executor_state); (self.harness_fn)(&mut self.exposed_executor_state, input);
self.inner.post_run_target_child(fuzzer, state, mgr, input); self.inner.post_run_target_child(fuzzer, state, mgr, input);
Ok(ExitKind::Ok) Ok(ExitKind::Ok)
} }
@ -170,18 +157,13 @@ where
} }
} }
impl<'a, H, HT, OT, S, SP, ES, EM, Z, OF> impl<'a, H, HT, OT, S, SP, ES, EM, Z>
StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z> StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HT: ExecutorHooksTuple<S>, HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
SP: ShMemProvider, S: State,
Z: UsesState<State = S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, S::Input, OT, S>,
S: State + HasSolutions,
Z: HasObjective<Objective = OF, State = S>,
{ {
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks /// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -228,15 +210,12 @@ where
impl<H, HT, OT, S, SP, ES, EM, Z> HasObservers impl<H, HT, OT, S, SP, ES, EM, Z> HasObservers
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
where where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HT: ExecutorHooksTuple<S>,
S: State,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
SP: ShMemProvider, S: State,
EM: UsesState<State = S>,
Z: UsesState<State = S>,
{ {
type Observers = OT; type Observers = OT;
#[inline] #[inline]
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> { fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers() self.inner.observers()

View File

@ -12,10 +12,12 @@ use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut, HasLen, Named};
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
observers::{map::MapObserver, Observer}, observers::{map::MapObserver, Observer, VariableLengthMapObserver},
Error, Error,
}; };
// TODO: remove the size field and implement ConstantLengthMapObserver
/// Use a const size to speedup `Feedback::is_interesting` when the user can /// Use a const size to speedup `Feedback::is_interesting` when the user can
/// know the size of the map at compile time. /// know the size of the map at compile time.
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -24,6 +26,7 @@ pub struct ConstMapObserver<'a, T, const N: usize> {
map: OwnedMutSlice<'a, T>, map: OwnedMutSlice<'a, T>,
initial: T, initial: T,
name: Cow<'static, str>, name: Cow<'static, str>,
size: usize,
} }
impl<I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'_, T, N> impl<I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'_, T, N>
@ -147,6 +150,27 @@ where
} }
} }
impl<T, const N: usize> VariableLengthMapObserver for ConstMapObserver<'_, T, N>
where
T: PartialEq + Copy + Hash + Serialize + DeserializeOwned + Debug + 'static,
{
fn map_slice(&mut self) -> &[Self::Entry] {
self.map.as_slice()
}
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
self.map.as_slice_mut()
}
fn size(&mut self) -> &usize {
&N
}
fn size_mut(&mut self) -> &mut usize {
&mut self.size
}
}
impl<T, const N: usize> Deref for ConstMapObserver<'_, T, N> { impl<T, const N: usize> Deref for ConstMapObserver<'_, T, N> {
type Target = [T]; type Target = [T];
fn deref(&self) -> &[T] { fn deref(&self) -> &[T] {
@ -176,6 +200,7 @@ where
map: OwnedMutSlice::from(map), map: OwnedMutSlice::from(map),
name: Cow::from(name), name: Cow::from(name),
initial: T::default(), initial: T::default(),
size: N,
} }
} }
@ -188,6 +213,7 @@ where
map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N), map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N),
name: Cow::from(name), name: Cow::from(name),
initial: T::default(), initial: T::default(),
size: N,
} }
} }
} }
@ -209,6 +235,7 @@ where
map: OwnedMutSlice::from(map), map: OwnedMutSlice::from(map),
name: Cow::from(name), name: Cow::from(name),
initial, initial,
size: N,
} }
} }
} }

View File

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
executors::ExitKind, executors::ExitKind,
observers::{map::MapObserver, DifferentialObserver, Observer}, observers::{map::MapObserver, DifferentialObserver, Observer, VariableLengthMapObserver},
Error, Error,
}; };
@ -220,6 +220,7 @@ where
fn hash_simple(&self) -> u64 { fn hash_simple(&self) -> u64 {
self.base.hash_simple() self.base.hash_simple()
} }
fn to_vec(&self) -> Vec<u8> { fn to_vec(&self) -> Vec<u8> {
self.base.to_vec() self.base.to_vec()
} }
@ -229,6 +230,27 @@ where
} }
} }
impl<M> VariableLengthMapObserver for HitcountsMapObserver<M>
where
M: VariableLengthMapObserver + MapObserver<Entry = u8>,
{
fn map_slice(&mut self) -> &[Self::Entry] {
self.base.map_slice()
}
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
self.base.map_slice_mut()
}
fn size(&mut self) -> &usize {
self.base.size()
}
fn size_mut(&mut self) -> &mut usize {
self.base.size_mut()
}
}
impl<M> Truncate for HitcountsMapObserver<M> impl<M> Truncate for HitcountsMapObserver<M>
where where
M: Named + Serialize + serde::de::DeserializeOwned + Truncate, M: Named + Serialize + serde::de::DeserializeOwned + Truncate,

View File

@ -385,6 +385,33 @@ pub trait MapObserver:
fn how_many_set(&self, indexes: &[usize]) -> usize; fn how_many_set(&self, indexes: &[usize]) -> usize;
} }
/// The "real" length of the underlying map could change at any point in time.
/// Thus, the size of the map should be fetched each time it is used.
pub trait VariableLengthMapObserver: MapObserver {
/// A mutable slice reference to the map.
/// The length of the map gives the maximum allocatable size.
fn map_slice(&mut self) -> &[Self::Entry];
/// A slice reference to the map.
/// The length of the map gives the maximum allocatable size.
fn map_slice_mut(&mut self) -> &mut [Self::Entry];
/// A reference to the size of the map.
fn size(&mut self) -> &usize;
/// A mutable reference to the size of the map.
fn size_mut(&mut self) -> &mut usize;
}
/// Implementors guarantee the size of the map is constant at any point in time and equals N.
pub trait ConstantLengthMapObserver<const N: usize>: MapObserver {
/// The size of the map
const LENGTH: usize = N;
/// A mutable slice reference to the map
fn map_slice_mut(&mut self) -> &mut [Self::Entry; N];
}
impl<M> CanTrack for M impl<M> CanTrack for M
where where
M: MapObserver, M: MapObserver,

View File

@ -15,7 +15,7 @@ use libafl_bolts::{
use serde::{de::DeserializeOwned, Deserialize, Serialize}; use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
observers::{map::MapObserver, Observer}, observers::{map::MapObserver, Observer, VariableLengthMapObserver},
Error, Error,
}; };
@ -149,6 +149,27 @@ where
} }
} }
impl<T> VariableLengthMapObserver for VariableMapObserver<'_, T>
where
T: PartialEq + Copy + Hash + Serialize + DeserializeOwned + Debug,
{
fn map_slice(&mut self) -> &[Self::Entry] {
self.map.as_ref()
}
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
self.map.as_mut()
}
fn size(&mut self) -> &usize {
self.size.as_ref()
}
fn size_mut(&mut self) -> &mut usize {
self.size.as_mut()
}
}
impl<T> Deref for VariableMapObserver<'_, T> { impl<T> Deref for VariableMapObserver<'_, T> {
type Target = [T]; type Target = [T];
fn deref(&self) -> &[T] { fn deref(&self) -> &[T] {

View File

@ -905,6 +905,24 @@ impl<T: Sized> OwnedMutPtr<T> {
pub unsafe fn from_raw_mut(ptr: *mut T) -> Self { pub unsafe fn from_raw_mut(ptr: *mut T) -> Self {
Self::Ptr(ptr) Self::Ptr(ptr)
} }
/// Get a pointer to the inner object
#[must_use]
pub fn as_ptr(&self) -> *const T {
match self {
OwnedMutPtr::Ptr(ptr) => *ptr,
OwnedMutPtr::Owned(owned) => &**owned,
}
}
/// Get a mutable pointer to the inner object
#[must_use]
pub fn as_mut_ptr(&mut self) -> *mut T {
match self {
OwnedMutPtr::Ptr(ptr) => *ptr,
OwnedMutPtr::Owned(owned) => &mut **owned,
}
}
} }
impl<T: Sized + Serialize> Serialize for OwnedMutPtr<T> { impl<T: Sized + Serialize> Serialize for OwnedMutPtr<T> {

View File

@ -239,7 +239,7 @@ fn main() {
println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS"); println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS");
println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS"); println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS");
println!("cargo:rerun-if-env-changed=LLVM_VERSION"); println!("cargo:rerun-if-env-changed=LLVM_VERSION");
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE_IN_USE"); println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE"); println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_DDG_MAP_SIZE"); println!("cargo:rerun-if-env-changed=LIBAFL_DDG_MAP_SIZE");
println!("cargo:rerun-if-changed=src/common-llvm.h"); println!("cargo:rerun-if-changed=src/common-llvm.h");
@ -312,13 +312,13 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
}; };
let mut cxxflags: Vec<String> = cxxflags.split_whitespace().map(String::from).collect(); let mut cxxflags: Vec<String> = cxxflags.split_whitespace().map(String::from).collect();
let edges_map_size_in_use: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE") let edge_map_default_size: usize = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
.map_or(Ok(65_536), str::parse) .map_or(Ok(65_536), str::parse)
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
let edges_map_size_max: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_MAX") let edge_map_allocated_size: usize = option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")
.map_or(Ok(2_621_440), str::parse) .map_or(Ok(2_621_440), str::parse)
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
cxxflags.push(format!("-DEDGES_MAP_SIZE_IN_USE={edges_map_size_in_use}")); cxxflags.push(format!("-DEDGES_MAP_DEFAULT_SIZE={edge_map_default_size}"));
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE") let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
.map_or(Ok(65_536), str::parse) .map_or(Ok(65_536), str::parse)
@ -348,9 +348,9 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
pub const CLANGXX_PATH: &str = {clangcpp:?}; pub const CLANGXX_PATH: &str = {clangcpp:?};
/// The default size of the edges map the fuzzer uses /// The default size of the edges map the fuzzer uses
pub const EDGES_MAP_SIZE_IN_USE: usize = {edges_map_size_in_use}; pub const EDGES_MAP_DEFAULT_SIZE: usize = {edge_map_default_size};
/// The real allocated size of the edges map /// The real allocated size of the edges map
pub const EDGES_MAP_SIZE_MAX: usize = {edges_map_size_max}; pub const EDGES_MAP_ALLOCATED_SIZE: usize = {edge_map_allocated_size};
/// The size of the accounting maps /// The size of the accounting maps
pub const ACCOUNTING_MAP_SIZE: usize = {acc_map_size}; pub const ACCOUNTING_MAP_SIZE: usize = {acc_map_size};

View File

@ -95,9 +95,9 @@ where
/// Inserts an edge into CFG. /// Inserts an edge into CFG.
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
let map_size = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE") let map_size = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
.map_or(Ok(65536), str::parse) .map_or(Ok(65536), str::parse)
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
Self { Self {
edges: (0..map_size).map(|_| None).collect(), edges: (0..map_size).map(|_| None).collect(),
func_to_entry_bb: HashMap::default(), func_to_entry_bb: HashMap::default(),

View File

@ -64,7 +64,7 @@
using namespace llvm; using namespace llvm;
#define MAP_SIZE EDGES_MAP_SIZE_IN_USE #define MAP_SIZE EDGES_MAP_DEFAULT_SIZE
namespace { namespace {

View File

@ -64,7 +64,7 @@
using namespace llvm; using namespace llvm;
#define MAP_SIZE EDGES_MAP_SIZE_IN_USE #define MAP_SIZE EDGES_MAP_DEFAULT_SIZE
namespace { namespace {

View File

@ -133,6 +133,11 @@ pub fn generate(
}) })
.header(wrapper_h.display().to_string()) .header(wrapper_h.display().to_string())
.clang_args(clang_args) .clang_args(clang_args)
.allowlist_var("libafl_dump_core_hook")
.allowlist_var("libafl_force_dfl")
.allowlist_var("mmap_next_start")
.allowlist_var("guest_base")
.allowlist_var("exec_path")
.allowlist_type("target_ulong") .allowlist_type("target_ulong")
.allowlist_type("target_long") .allowlist_type("target_long")
.allowlist_type("CPUState") .allowlist_type("CPUState")

View File

@ -2,21 +2,11 @@ use core::{slice::from_raw_parts, str::from_utf8_unchecked};
use libc::{c_char, strlen}; use libc::{c_char, strlen};
use num_enum::{IntoPrimitive, TryFromPrimitive}; use num_enum::{IntoPrimitive, TryFromPrimitive};
use paste::paste;
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python}; use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python};
use strum_macros::EnumIter; use strum_macros::EnumIter;
use crate::{extern_c_checked, libafl_mapinfo, GuestAddr, MmapPerms}; use crate::{libafl_mapinfo, GuestAddr, MmapPerms};
extern_c_checked! {
pub static exec_path: *const u8;
pub static guest_base: usize;
pub static mut mmap_next_start: GuestAddr;
pub static mut libafl_dump_core_hook: unsafe extern "C" fn(i32);
pub static mut libafl_force_dfl: i32;
}
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)] #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)]
#[repr(i32)] #[repr(i32)]

View File

@ -12525,6 +12525,9 @@ impl Default for IntervalTreeNode {
pub type IntervalTreeRoot = RBRootLeftCached; pub type IntervalTreeRoot = RBRootLeftCached;
pub type abi_ulong = target_ulong; pub type abi_ulong = target_ulong;
pub type abi_long = target_long; pub type abi_long = target_long;
extern "C" {
pub static mut guest_base: usize;
}
extern "C" { extern "C" {
#[doc = " --- Begin LibAFL code ---"] #[doc = " --- Begin LibAFL code ---"]
pub fn pageflags_get_root() -> *mut IntervalTreeRoot; pub fn pageflags_get_root() -> *mut IntervalTreeRoot;
@ -13274,6 +13277,12 @@ impl Default for TranslationBlock {
} }
} }
} }
extern "C" {
pub static mut exec_path: *mut ::std::os::raw::c_char;
}
extern "C" {
pub static mut mmap_next_start: abi_ulong;
}
extern "C" { extern "C" {
pub fn target_mprotect( pub fn target_mprotect(
start: abi_ulong, start: abi_ulong,
@ -13757,6 +13766,13 @@ impl Default for libafl_mapinfo {
} }
} }
} }
extern "C" {
pub static mut libafl_dump_core_hook:
::std::option::Option<unsafe extern "C" fn(host_sig: ::std::os::raw::c_int)>;
}
extern "C" {
pub static mut libafl_force_dfl: ::std::os::raw::c_int;
}
extern "C" { extern "C" {
pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int); pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int);
} }

View File

@ -15,8 +15,8 @@ use crate::qemu::{
}; };
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
use crate::qemu::{ use crate::qemu::{
CrashHookClosure, PostSyscallHookClosure, PostSyscallHookFn, PreSyscallHookClosure, CrashHookClosure, CrashHookFn, PostSyscallHookClosure, PostSyscallHookFn,
PreSyscallHookFn, PreSyscallHookClosure, PreSyscallHookFn,
}; };
use crate::{ use crate::{
cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper, cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper,
@ -68,9 +68,6 @@ macro_rules! hook_to_repr {
static mut EMULATOR_TOOLS: *mut () = ptr::null_mut(); static mut EMULATOR_TOOLS: *mut () = ptr::null_mut();
#[cfg(emulation_mode = "usermode")]
static mut CRASH_HOOKS: Vec<HookRepr> = vec![];
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
pub extern "C" fn crash_hook_wrapper<ET, S>(target_sig: i32) pub extern "C" fn crash_hook_wrapper<ET, S>(target_sig: i32)
where where
@ -78,17 +75,17 @@ where
S: Unpin + UsesInput, S: Unpin + UsesInput,
{ {
unsafe { unsafe {
let hooks = Qemu::get().unwrap().hooks(); let emulator_modules = EmulatorModules::<ET, S>::emulator_modules_mut().unwrap();
for crash_hook in &mut (*addr_of_mut!(CRASH_HOOKS)) { for crash_hook in &mut (*addr_of_mut!(emulator_modules.hooks.crash_hooks)) {
match crash_hook { match crash_hook {
HookRepr::Function(ptr) => { HookRepr::Function(ptr) => {
let func: fn(QemuHooks, i32) = transmute(*ptr); let func: CrashHookFn<ET, S> = transmute(*ptr);
func(hooks, target_sig); func(emulator_modules, target_sig);
} }
HookRepr::Closure(ptr) => { HookRepr::Closure(ptr) => {
let func: &mut Box<dyn FnMut(QemuHooks, i32)> = transmute(ptr); let func: &mut CrashHookClosure<ET, S> = transmute(ptr);
func(hooks, target_sig); func(emulator_modules, target_sig);
} }
HookRepr::Empty => (), HookRepr::Empty => (),
} }

View File

@ -15,6 +15,7 @@ use libafl::{
executors::{ executors::{
hooks::inprocess::InProcessExecutorHandlerData, hooks::inprocess::InProcessExecutorHandlerData,
inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks}, inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks},
inprocess_fork::stateful::StatefulInProcessForkExecutor,
Executor, ExitKind, HasObservers, Executor, ExitKind, HasObservers,
}, },
feedbacks::Feedback, feedbacks::Feedback,
@ -25,10 +26,6 @@ use libafl::{
Error, ExecutionProcessor, HasScheduler, Error, ExecutionProcessor, HasScheduler,
}; };
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
use libafl::{
events::EventManager, executors::InProcessForkExecutor, state::HasLastReportTime, HasMetadata,
};
#[cfg(feature = "fork")]
use libafl_bolts::shmem::ShMemProvider; use libafl_bolts::shmem::ShMemProvider;
use libafl_bolts::{ use libafl_bolts::{
os::unix_signals::{ucontext_t, Signal}, os::unix_signals::{ucontext_t, Signal},
@ -278,20 +275,21 @@ where
} }
} }
pub type QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> =
StatefulInProcessForkExecutor<'a, H, OT, S, SP, Emulator<CM, ED, ET, S, SM>, EM, Z>;
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
where where
CM: CommandManager<ED, ET, S, SM>, CM: CommandManager<ED, ET, S, SM>,
EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: UsesInput, S: UsesInput,
SP: ShMemProvider, SP: ShMemProvider,
Z: UsesState<State = S>, Z: UsesState<State = S>,
{ {
inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, inner: QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>,
emulator: Emulator<CM, ED, ET, S, SM>,
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
@ -302,7 +300,7 @@ where
EM: UsesState<State = S>, EM: UsesState<State = S>,
ED: Debug, ED: Debug,
ET: EmulatorModuleTuple<S> + Debug, ET: EmulatorModuleTuple<S> + Debug,
H: FnMut(&S::Input) -> ExitKind + ?Sized, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S> + Debug, OT: ObserversTuple<S::Input, S> + Debug,
S: UsesInput + Debug, S: UsesInput + Debug,
SM: Debug, SM: Debug,
@ -312,7 +310,7 @@ where
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuForkExecutor") f.debug_struct("QemuForkExecutor")
.field("inner", &self.inner) .field("inner", &self.inner)
.field("emulator", &self.emulator) .field("emulator", &self.inner.exposed_executor_state)
.finish() .finish()
} }
} }
@ -324,7 +322,7 @@ where
CM: CommandManager<ED, ET, S, SM>, CM: CommandManager<ED, ET, S, SM>,
EM: EventFirer<State = S> + EventRestarter<State = S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: State + HasSolutions, S: State + HasSolutions,
SP: ShMemProvider, SP: ShMemProvider,
@ -344,8 +342,9 @@ where
assert!(!ET::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded"); assert!(!ET::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded");
Ok(Self { Ok(Self {
inner: InProcessForkExecutor::new( inner: StatefulInProcessForkExecutor::new(
harness_fn, harness_fn,
emulator,
observers, observers,
fuzzer, fuzzer,
state, state,
@ -353,39 +352,41 @@ where
timeout, timeout,
shmem_provider, shmem_provider,
)?, )?,
emulator,
}) })
} }
pub fn inner(&self) -> &InProcessForkExecutor<'a, H, OT, S, SP, EM, Z> { pub fn inner(&self) -> &QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
&self.inner &self.inner
} }
pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, OT, S, SP, EM, Z> { pub fn inner_mut(
&mut self,
) -> &mut QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
&mut self.inner &mut self.inner
} }
pub fn emulator(&self) -> &Emulator<CM, ED, ET, S, SM> { pub fn emulator(&self) -> &Emulator<CM, ED, ET, S, SM> {
&self.emulator &self.inner.exposed_executor_state
} }
pub fn emulator_mut(&mut self) -> &Emulator<CM, ED, ET, S, SM> { pub fn emulator_mut(&mut self) -> &Emulator<CM, ED, ET, S, SM> {
&mut self.emulator &mut self.inner.exposed_executor_state
} }
} }
#[cfg(feature = "fork")] #[cfg(feature = "fork")]
impl<'a, CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor<EM, Z> impl<CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor<EM, Z>
for QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
where where
CM: CommandManager<ED, ET, S, SM>, CM: CommandManager<ED, ET, S, SM>,
EM: EventManager<InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, Z, State = S>, ED: EmulatorDriver<CM, ET, S, SM>,
H: FnMut(&S::Input) -> ExitKind, EM: EventFirer<State = S> + EventRestarter<State = S>,
S: Unpin + State + HasMetadata + HasExecutions + HasLastReportTime + HasCorpus + HasSolutions,
OT: ObserversTuple<S::Input, S> + Debug,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
SP: ShMemProvider, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind,
OF: Feedback<EM, S::Input, OT, S>, OF: Feedback<EM, S::Input, OT, S>,
OT: ObserversTuple<S::Input, S> + Debug,
S: State + HasExecutions + Unpin,
SP: ShMemProvider,
Z: HasObjective<Objective = OF, State = S>, Z: HasObjective<Objective = OF, State = S>,
{ {
fn run_target( fn run_target(
@ -395,7 +396,20 @@ where
mgr: &mut EM, mgr: &mut EM,
input: &Self::Input, input: &Self::Input,
) -> Result<ExitKind, Error> { ) -> Result<ExitKind, Error> {
self.inner.run_target(fuzzer, state, mgr, input) self.inner.exposed_executor_state.first_exec(state);
self.inner.exposed_executor_state.pre_exec(state, input);
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
self.inner.exposed_executor_state.post_exec(
input,
&mut *self.inner.inner.observers_mut(),
state,
&mut exit_kind,
);
Ok(exit_kind)
} }
} }
@ -404,9 +418,8 @@ impl<CM, ED, EM, ET, H, OT, S, SM, SP, Z> UsesState
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z> for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
where where
CM: CommandManager<ED, ET, S, SM>, CM: CommandManager<ED, ET, S, SM>,
EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: State, S: State,
SP: ShMemProvider, SP: ShMemProvider,
@ -422,7 +435,7 @@ where
CM: CommandManager<ED, ET, S, SM>, CM: CommandManager<ED, ET, S, SM>,
EM: UsesState<State = S>, EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>, ET: EmulatorModuleTuple<S>,
H: FnMut(&S::Input) -> ExitKind + ?Sized, H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S::Input, S>, OT: ObserversTuple<S::Input, S>,
S: State, S: State,
SP: ShMemProvider, SP: ShMemProvider,

View File

@ -1,14 +1,12 @@
use std::{cell::UnsafeCell, cmp::max, fmt::Debug}; use std::{cell::UnsafeCell, cmp::max, fmt::Debug, ptr, ptr::addr_of};
use hashbrown::{hash_map::Entry, HashMap}; use hashbrown::{hash_map::Entry, HashMap};
use libafl::{inputs::UsesInput, HasMetadata}; use libafl::{inputs::UsesInput, observers::VariableLengthMapObserver, HasMetadata};
use libafl_bolts::Error;
use libafl_qemu_sys::GuestAddr; use libafl_qemu_sys::GuestAddr;
#[cfg(emulation_mode = "systemmode")] #[cfg(emulation_mode = "systemmode")]
use libafl_qemu_sys::GuestPhysAddr; use libafl_qemu_sys::GuestPhysAddr;
pub use libafl_targets::{ use libafl_targets::EDGES_MAP;
edges_map_mut_ptr, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_SIZE_MAX,
MAX_EDGES_FOUND,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -20,6 +18,18 @@ use crate::{
qemu::Hook, qemu::Hook,
}; };
#[no_mangle]
static mut LIBAFL_QEMU_EDGES_MAP_PTR: *mut u8 = ptr::null_mut();
#[no_mangle]
static mut LIBAFL_QEMU_EDGES_MAP_SIZE_PTR: *mut usize = ptr::null_mut();
#[no_mangle]
static mut LIBAFL_QEMU_EDGES_MAP_ALLOCATED_SIZE: usize = 0;
#[no_mangle]
static mut LIBAFL_QEMU_EDGES_MAP_MASK_MAX: usize = 0;
#[cfg_attr( #[cfg_attr(
any(not(feature = "serdeany_autoreg"), miri), any(not(feature = "serdeany_autoreg"), miri),
allow(clippy::unsafe_derive_deserialize) allow(clippy::unsafe_derive_deserialize)
@ -100,7 +110,7 @@ pub struct EdgeCoverageFullVariant;
pub type StdEdgeCoverageFullModule = pub type StdEdgeCoverageFullModule =
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>; EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>;
pub type StdEdgeCoverageFullModuleBuilder = pub type StdEdgeCoverageFullModuleBuilder =
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>; EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant, false>;
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageFullVariant { impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageFullVariant {
fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>) fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
@ -193,7 +203,7 @@ pub struct EdgeCoverageClassicVariant;
pub type StdEdgeCoverageClassicModule = pub type StdEdgeCoverageClassicModule =
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>; EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>;
pub type StdEdgeCoverageClassicModuleBuilder = pub type StdEdgeCoverageClassicModuleBuilder =
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>; EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant, false>;
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageClassicVariant { impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageClassicVariant {
const DO_SIDE_EFFECTS: bool = false; const DO_SIDE_EFFECTS: bool = false;
@ -293,7 +303,7 @@ pub struct EdgeCoverageChildVariant;
pub type StdEdgeCoverageChildModule = pub type StdEdgeCoverageChildModule =
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>; EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>;
pub type StdEdgeCoverageChildModuleBuilder = pub type StdEdgeCoverageChildModuleBuilder =
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>; EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant, false>;
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageChildVariant { impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageChildVariant {
const DO_SIDE_EFFECTS: bool = false; const DO_SIDE_EFFECTS: bool = false;
@ -339,13 +349,13 @@ impl Default for StdEdgeCoverageChildModuleBuilder {
impl StdEdgeCoverageChildModule { impl StdEdgeCoverageChildModule {
#[must_use] #[must_use]
pub fn builder() -> StdEdgeCoverageClassicModuleBuilder { pub fn builder() -> StdEdgeCoverageChildModuleBuilder {
EdgeCoverageModuleBuilder::default() EdgeCoverageModuleBuilder::default().jit(false)
} }
} }
#[derive(Debug)] #[derive(Debug)]
pub struct EdgeCoverageModuleBuilder<AF, PF, V> { pub struct EdgeCoverageModuleBuilder<AF, PF, V, const IS_INITIALIZED: bool> {
variant: V, variant: V,
address_filter: AF, address_filter: AF,
page_filter: PF, page_filter: PF,
@ -364,8 +374,20 @@ pub struct EdgeCoverageModule<AF, PF, V> {
use_jit: bool, use_jit: bool,
} }
impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> { impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V, true> {
pub fn new( pub fn build(self) -> Result<EdgeCoverageModule<AF, PF, V>, Error> {
Ok(EdgeCoverageModule::new(
self.address_filter,
self.page_filter,
self.variant,
self.use_hitcounts,
self.use_jit,
))
}
}
impl<AF, PF, V, const IS_INITIALIZED: bool> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
fn new(
variant: V, variant: V,
address_filter: AF, address_filter: AF,
page_filter: PF, page_filter: PF,
@ -381,17 +403,32 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
} }
} }
pub fn build(self) -> EdgeCoverageModule<AF, PF, V> { #[must_use]
EdgeCoverageModule::new( pub fn map_observer<O>(self, map_observer: &mut O) -> EdgeCoverageModuleBuilder<AF, PF, V, true>
where
O: VariableLengthMapObserver,
{
let map_ptr = map_observer.map_slice_mut().as_mut_ptr() as *mut u8;
let map_max_size = map_observer.map_slice_mut().len();
let size_ptr = map_observer.as_mut().size_mut() as *mut usize;
unsafe {
LIBAFL_QEMU_EDGES_MAP_PTR = map_ptr;
LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = size_ptr;
LIBAFL_QEMU_EDGES_MAP_ALLOCATED_SIZE = map_max_size;
LIBAFL_QEMU_EDGES_MAP_MASK_MAX = map_max_size - 1;
}
EdgeCoverageModuleBuilder::<AF, PF, V, true>::new(
self.variant,
self.address_filter, self.address_filter,
self.page_filter, self.page_filter,
self.variant,
self.use_hitcounts, self.use_hitcounts,
self.use_jit, self.use_jit,
) )
} }
pub fn variant<V2>(self, variant: V2) -> EdgeCoverageModuleBuilder<AF, PF, V2> { pub fn variant<V2>(self, variant: V2) -> EdgeCoverageModuleBuilder<AF, PF, V2, IS_INITIALIZED> {
EdgeCoverageModuleBuilder::new( EdgeCoverageModuleBuilder::new(
variant, variant,
self.address_filter, self.address_filter,
@ -401,7 +438,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
) )
} }
pub fn address_filter<AF2>(self, address_filter: AF2) -> EdgeCoverageModuleBuilder<AF2, PF, V> { pub fn address_filter<AF2>(
self,
address_filter: AF2,
) -> EdgeCoverageModuleBuilder<AF2, PF, V, IS_INITIALIZED> {
EdgeCoverageModuleBuilder::new( EdgeCoverageModuleBuilder::new(
self.variant, self.variant,
address_filter, address_filter,
@ -411,7 +451,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
) )
} }
pub fn page_filter<PF2>(self, page_filter: PF2) -> EdgeCoverageModuleBuilder<AF, PF2, V> { pub fn page_filter<PF2>(
self,
page_filter: PF2,
) -> EdgeCoverageModuleBuilder<AF, PF2, V, IS_INITIALIZED> {
EdgeCoverageModuleBuilder::new( EdgeCoverageModuleBuilder::new(
self.variant, self.variant,
self.address_filter, self.address_filter,
@ -422,7 +465,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
} }
#[must_use] #[must_use]
pub fn hitcounts(self, use_hitcounts: bool) -> EdgeCoverageModuleBuilder<AF, PF, V> { pub fn hitcounts(
self,
use_hitcounts: bool,
) -> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
EdgeCoverageModuleBuilder::new( EdgeCoverageModuleBuilder::new(
self.variant, self.variant,
self.address_filter, self.address_filter,
@ -433,7 +479,7 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
} }
#[must_use] #[must_use]
pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder<AF, PF, V> { pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
EdgeCoverageModuleBuilder::new( EdgeCoverageModuleBuilder::new(
self.variant, self.variant,
self.address_filter, self.address_filter,
@ -548,10 +594,15 @@ where
S: Unpin + UsesInput + HasMetadata, S: Unpin + UsesInput + HasMetadata,
V: EdgeCoverageVariant<AF, PF>, V: EdgeCoverageVariant<AF, PF>,
{ {
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() { if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
unsafe {
assert!(LIBAFL_QEMU_EDGES_MAP_MASK_MAX > 0);
assert_ne!(*addr_of!(LIBAFL_QEMU_EDGES_MAP_SIZE_PTR), ptr::null_mut());
}
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
{ {
if !h.must_instrument(src) && !h.must_instrument(dest) { if !module.must_instrument(src) && !module.must_instrument(dest) {
return None; return None;
} }
} }
@ -563,29 +614,30 @@ where
.current_cpu() .current_cpu()
.and_then(|cpu| cpu.current_paging_id()); .and_then(|cpu| cpu.current_paging_id());
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) { if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) {
return None; return None;
} }
} }
} }
let state = state.expect("The gen_unique_edge_ids hook works only for in-process fuzzing"); let state = state.expect("The gen_unique_edge_ids hook works only for in-process fuzzing");
let meta = state.metadata_or_insert_with(QemuEdgesMapMetadata::new); let meta = state.metadata_or_insert_with(QemuEdgesMapMetadata::new);
match meta.map.entry((src, dest)) { match meta.map.entry((src, dest)) {
Entry::Occupied(e) => { Entry::Occupied(e) => {
let id = *e.get(); let id = *e.get();
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
unsafe { unsafe {
MAX_EDGES_FOUND = max(MAX_EDGES_FOUND, nxt); let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = max(*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR, nxt);
} }
Some(id) Some(id)
} }
Entry::Vacant(e) => { Entry::Vacant(e) => {
let id = meta.current_id; let id = meta.current_id;
e.insert(id); e.insert(id);
meta.current_id = (id + 1) & (EDGES_MAP_SIZE_MAX as u64 - 1);
unsafe { unsafe {
MAX_EDGES_FOUND = meta.current_id as usize; meta.current_id = (id + 1) & (LIBAFL_QEMU_EDGES_MAP_MASK_MAX as u64);
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = meta.current_id as usize;
} }
// GuestAddress is u32 for 32 bit guests // GuestAddress is u32 for 32 bit guests
#[allow(clippy::unnecessary_cast)] #[allow(clippy::unnecessary_cast)]
@ -624,9 +676,9 @@ where
S: Unpin + UsesInput + HasMetadata, S: Unpin + UsesInput + HasMetadata,
V: EdgeCoverageVariant<AF, PF>, V: EdgeCoverageVariant<AF, PF>,
{ {
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() { if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
if !h.must_instrument(src) && !h.must_instrument(dest) { if !module.must_instrument(src) && !module.must_instrument(dest) {
return None; return None;
} }
@ -637,29 +689,31 @@ where
.current_cpu() .current_cpu()
.and_then(|cpu| cpu.current_paging_id()); .and_then(|cpu| cpu.current_paging_id());
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) { if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) {
return None; return None;
} }
} }
let id = hash_me(src as u64) ^ hash_me(dest as u64);
unsafe {
let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = nxt;
}
// GuestAddress is u32 for 32 bit guests
#[allow(clippy::unnecessary_cast)]
Some(id)
} else {
None
} }
let id = hash_me(src as u64) ^ hash_me(dest as u64);
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
unsafe {
MAX_EDGES_FOUND = nxt;
}
// GuestAddress is u32 for 32 bit guests
#[allow(clippy::unnecessary_cast)]
Some(id)
} }
/// # Safety /// # Safety
/// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently. /// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently.
pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) { 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 = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize);
*ptr = (*ptr).wrapping_add(1); *ptr = (*ptr).wrapping_add(1);
} }
} }
@ -669,7 +723,7 @@ pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
/// Worst case we set the byte to 1 multiple times. /// Worst case we set the byte to 1 multiple times.
pub unsafe extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) { 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 = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize);
*ptr = 1; *ptr = 1;
} }
} }
@ -687,10 +741,11 @@ where
S: Unpin + UsesInput + HasMetadata, S: Unpin + UsesInput + HasMetadata,
V: EdgeCoverageVariant<AF, PF>, V: EdgeCoverageVariant<AF, PF>,
{ {
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() { // first check if we should filter
if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
{ {
if !h.must_instrument(pc) { if !module.must_instrument(pc) {
return None; return None;
} }
} }
@ -701,17 +756,17 @@ where
.current_cpu() .current_cpu()
.and_then(|cpu| cpu.current_paging_id()); .and_then(|cpu| cpu.current_paging_id());
if !h.must_instrument(pc, page_id) { if !module.must_instrument(pc, page_id) {
return None; return None;
} }
} }
} }
let id = hash_me(pc as u64); let id = hash_me(pc as u64);
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
unsafe { unsafe {
MAX_EDGES_FOUND = nxt; let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = nxt;
} }
// GuestAddress is u32 for 32 bit guests // GuestAddress is u32 for 32 bit guests
@ -724,8 +779,8 @@ where
pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) { 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) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
let entry = EDGES_MAP_PTR.add(x); let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x);
*entry = (*entry).wrapping_add(1); *entry = (*entry).wrapping_add(1);
*prev_loc.get() = id.overflowing_shr(1).0; *prev_loc.get() = id.overflowing_shr(1).0;
}); });
@ -737,8 +792,8 @@ pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64)
pub unsafe extern "C" fn trace_block_transition_single(_: *const (), id: u64) { 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) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
let entry = EDGES_MAP_PTR.add(x); let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x);
*entry = 1; *entry = 1;
*prev_loc.get() = id.overflowing_shr(1).0; *prev_loc.get() = id.overflowing_shr(1).0;
}); });

View File

@ -146,8 +146,8 @@ impl<F> AsanGuestModule<F> {
impl AsanGuestModule<StdAddressFilter> { impl AsanGuestModule<StdAddressFilter> {
#[must_use] #[must_use]
pub fn default(emu: &Qemu, asan: String) -> Self { pub fn default(qemu: Qemu, asan: String) -> Self {
Self::new(emu, asan, StdAddressFilter::default()) Self::new(qemu, asan, StdAddressFilter::default())
} }
} }
@ -156,12 +156,12 @@ where
F: AddressFilter, F: AddressFilter,
{ {
#[must_use] #[must_use]
pub fn new(emu: &Qemu, asan: String, filter: F) -> Self { pub fn new(qemu: Qemu, asan: String, filter: F) -> Self {
for mapping in emu.mappings() { for mapping in qemu.mappings() {
println!("mapping: {mapping:#?}"); println!("mapping: {mapping:#?}");
} }
let mappings = emu let mappings = qemu
.mappings() .mappings()
.map(|m| QemuAsanGuestMapping::from(&m)) .map(|m| QemuAsanGuestMapping::from(&m))
.collect::<Vec<QemuAsanGuestMapping>>(); .collect::<Vec<QemuAsanGuestMapping>>();

View File

@ -34,7 +34,7 @@ use crate::{
pub const SNAPSHOT_PAGE_SIZE: usize = 4096; pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1); pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
pub type StopExecutionCallback = Box<dyn FnMut(&mut SnapshotModule, &Qemu)>; pub type StopExecutionCallback = Box<dyn FnMut(&mut SnapshotModule, Qemu)>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct SnapshotPageInfo { pub struct SnapshotPageInfo {
@ -510,7 +510,7 @@ impl SnapshotModule {
if self.mmap_limit != 0 && total_size > self.mmap_limit { if self.mmap_limit != 0 && total_size > self.mmap_limit {
let mut cb = self.stop_execution.take().unwrap(); let mut cb = self.stop_execution.take().unwrap();
let qemu = Qemu::get().unwrap(); let qemu = Qemu::get().unwrap();
cb(self, &qemu); cb(self, qemu);
self.stop_execution = Some(cb); self.stop_execution = Some(cb);
} }
} }

View File

@ -712,6 +712,8 @@ create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId);
// Crash hook wrappers // Crash hook wrappers
#[cfg(emulation_mode = "usermode")] #[cfg(emulation_mode = "usermode")]
pub type CrashHookFn<ET, S> = fn(&mut EmulatorModules<ET, S>, i32);
#[cfg(emulation_mode = "usermode")]
pub type CrashHookClosure<ET, S> = Box<dyn FnMut(&mut EmulatorModules<ET, S>, i32)>; pub type CrashHookClosure<ET, S> = Box<dyn FnMut(&mut EmulatorModules<ET, S>, i32)>;
/// The thin wrapper around QEMU hooks. /// The thin wrapper around QEMU hooks.
@ -1035,7 +1037,7 @@ impl QemuHooks {
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) { pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) {
unsafe { unsafe {
libafl_dump_core_hook = callback; libafl_dump_core_hook = Some(callback);
} }
} }
} }

View File

@ -155,10 +155,10 @@ static mut GDB_COMMANDS: Vec<Box<FatPtr>> = Vec::new();
unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool {
unsafe { unsafe {
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Qemu, &'r str) -> bool>); let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(Qemu, &'r str) -> bool>);
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
let qemu = Qemu::get_unchecked(); let qemu = Qemu::get_unchecked();
closure(&qemu, cmd) closure(qemu, cmd)
} }
} }

View File

@ -1,6 +1,6 @@
use std::{ use std::{
intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts, intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts_mut,
str::from_utf8_unchecked, str::from_utf8_unchecked_mut,
}; };
use libafl_qemu_sys::{ use libafl_qemu_sys::{
@ -9,7 +9,7 @@ use libafl_qemu_sys::{
pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot, pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot,
MapInfo, MmapPerms, VerifyAccess, MapInfo, MmapPerms, VerifyAccess,
}; };
use libc::{c_char, c_int, strlen}; use libc::{c_char, c_int, c_uchar, strlen};
#[cfg(feature = "python")] #[cfg(feature = "python")]
use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python}; use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python};
@ -139,8 +139,8 @@ impl Qemu {
#[must_use] #[must_use]
pub fn binary_path<'a>(&self) -> &'a str { pub fn binary_path<'a>(&self) -> &'a str {
unsafe { unsafe {
from_utf8_unchecked(from_raw_parts( from_utf8_unchecked_mut(from_raw_parts_mut(
exec_path, exec_path as *mut c_uchar,
strlen(exec_path as *const c_char), strlen(exec_path as *const c_char),
)) ))
} }

View File

@ -39,11 +39,8 @@ use libafl_bolts::{
#[cfg(not(any(feature = "mips", feature = "hexagon")))] #[cfg(not(any(feature = "mips", feature = "hexagon")))]
use libafl_qemu::modules::CmpLogModule; use libafl_qemu::modules::CmpLogModule;
pub use libafl_qemu::qemu::Qemu; pub use libafl_qemu::qemu::Qemu;
use libafl_qemu::{ use libafl_qemu::{modules::edges::StdEdgeCoverageModule, Emulator, QemuExecutor};
modules::{edges, edges::StdEdgeCoverageModule}, use libafl_targets::{edges_map_mut_ptr, CmpLogObserver, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
Emulator, QemuExecutor,
};
use libafl_targets::{edges_map_mut_ptr, CmpLogObserver};
use typed_builder::TypedBuilder; use typed_builder::TypedBuilder;
use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS}; use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS};
@ -160,14 +157,11 @@ where
let time_observer = time_observer.clone(); let time_observer = time_observer.clone();
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = unsafe { let mut edges_observer = unsafe {
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut( OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
edges_map_mut_ptr(), addr_of_mut!(MAX_EDGES_FOUND),
edges::EDGES_MAP_SIZE_IN_USE,
),
addr_of_mut!(edges::MAX_EDGES_FOUND),
)) ))
.track_indices() .track_indices()
}; };
@ -223,13 +217,19 @@ where
#[cfg(not(any(feature = "mips", feature = "hexagon")))] #[cfg(not(any(feature = "mips", feature = "hexagon")))]
{ {
tuple_list!( tuple_list!(
StdEdgeCoverageModule::builder().build(), StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
.unwrap(),
CmpLogModule::default(), CmpLogModule::default(),
) )
} }
#[cfg(any(feature = "mips", feature = "hexagon"))] #[cfg(any(feature = "mips", feature = "hexagon"))]
{ {
tuple_list!(StdEdgeCoverageModule::builder().build()) tuple_list!(StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
.unwrap())
} }
}; };
@ -345,7 +345,10 @@ where
} }
} }
} else { } else {
let modules = tuple_list!(StdEdgeCoverageModule::builder().build()); let modules = tuple_list!(StdEdgeCoverageModule::builder()
.map_observer(edges_observer.as_mut())
.build()
.unwrap());
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>, let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
_state: &mut _, _state: &mut _,

View File

@ -26,36 +26,47 @@ fn main() {
let dest_path = Path::new(&out_dir).join("constants.rs"); let dest_path = Path::new(&out_dir).join("constants.rs");
let mut constants_file = File::create(dest_path).expect("Could not create file"); let mut constants_file = File::create(dest_path).expect("Could not create file");
let edges_map_size_max: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_MAX") let edges_map_allocated_size: usize = option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")
.or(option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")) // keep old env for retrocompatibility
.map_or(Ok(TWO_MB), str::parse) .map_or(Ok(TWO_MB), str::parse)
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_MAX"); .expect("Could not parse LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
let edges_map_size_in_use: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE")
let edges_map_default_size: usize = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
.or(option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")) // keep old env for retrocompatibility
.map_or(Ok(SIXTY_FIVE_KB), str::parse) .map_or(Ok(SIXTY_FIVE_KB), str::parse)
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
let cmp_map_size: usize = option_env!("LIBAFL_CMP_MAP_SIZE") let cmp_map_size: usize = option_env!("LIBAFL_CMP_MAP_SIZE")
.map_or(Ok(SIXTY_FIVE_KB), str::parse) .map_or(Ok(SIXTY_FIVE_KB), str::parse)
.expect("Could not parse LIBAFL_CMP_MAP_SIZE"); .expect("Could not parse LIBAFL_CMP_MAP_SIZE");
let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W") let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W")
.map_or(Ok(SIXTY_FIVE_KB), str::parse) .map_or(Ok(SIXTY_FIVE_KB), str::parse)
.expect("Could not parse LIBAFL_CMPLOG_MAP_W"); .expect("Could not parse LIBAFL_CMPLOG_MAP_W");
let cmplog_map_h: usize = option_env!("LIBAFL_CMPLOG_MAP_H") let cmplog_map_h: usize = option_env!("LIBAFL_CMPLOG_MAP_H")
.map_or(Ok(32), str::parse) .map_or(Ok(32), str::parse)
.expect("Could not parse LIBAFL_CMPLOG_MAP_H"); .expect("Could not parse LIBAFL_CMPLOG_MAP_H");
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE") let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
.map_or(Ok(SIXTY_FIVE_KB), str::parse) .map_or(Ok(SIXTY_FIVE_KB), str::parse)
.expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE"); .expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE");
let ddg_map_size: usize = option_env!("LIBAFL_DDG_MAP_SIZE") let ddg_map_size: usize = option_env!("LIBAFL_DDG_MAP_SIZE")
.map_or(Ok(SIXTY_FIVE_KB), str::parse) .map_or(Ok(SIXTY_FIVE_KB), str::parse)
.expect("Could not parse LIBAFL_DDG_MAP_SIZE"); .expect("Could not parse LIBAFL_DDG_MAP_SIZE");
assert!(edges_map_default_size <= edges_map_allocated_size);
assert!(edges_map_default_size.is_power_of_two());
write!( write!(
constants_file, constants_file,
"// These constants are autogenerated by build.rs "// These constants are autogenerated by build.rs
/// The default size of the edges map the fuzzer uses /// The default size of the edges map the fuzzer uses
pub const EDGES_MAP_SIZE_IN_USE: usize = {edges_map_size_in_use}; pub const EDGES_MAP_DEFAULT_SIZE: usize = {edges_map_default_size};
/// The real allocated size of the edges map /// The real allocated size of the edges map
pub const EDGES_MAP_SIZE_MAX: usize = {edges_map_size_max}; pub const EDGES_MAP_ALLOCATED_SIZE: usize = {edges_map_allocated_size};
/// The size of the cmps map /// The size of the cmps map
pub const CMP_MAP_SIZE: usize = {cmp_map_size}; pub const CMP_MAP_SIZE: usize = {cmp_map_size};
/// The width of the `CmpLog` map /// The width of the `CmpLog` map
@ -70,7 +81,10 @@ fn main() {
) )
.expect("Could not write file"); .expect("Could not write file");
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE_IN_USE"); println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_CMP_MAP_SIZE"); println!("cargo:rerun-if-env-changed=LIBAFL_CMP_MAP_SIZE");
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_W"); println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_W");
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H"); println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H");
@ -160,8 +174,8 @@ fn main() {
cc::Build::new() cc::Build::new()
.file(src_dir.join("coverage.c")) .file(src_dir.join("coverage.c"))
.define( .define(
"EDGES_MAP_SIZE_MAX", "EDGES_MAP_ALLOCATED_SIZE",
Some(&*format!("{edges_map_size_max}")), Some(&*format!("{edges_map_allocated_size}")),
) )
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}"))) .define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}")))
.define("DDG_MAP_SIZE", Some(&*format!("{ddg_map_size}"))) .define("DDG_MAP_SIZE", Some(&*format!("{ddg_map_size}")))

View File

@ -8,7 +8,7 @@ typedef uint32_t prev_loc_t;
/* Maximum K for top-K context sensitivity */ /* Maximum K for top-K context sensitivity */
#define CTX_MAX_K 32U #define CTX_MAX_K 32U
extern uint8_t __afl_area_ptr_local[EDGES_MAP_SIZE_MAX]; extern uint8_t __afl_area_ptr_local[EDGES_MAP_ALLOCATED_SIZE];
uint8_t *__afl_area_ptr = __afl_area_ptr_local; uint8_t *__afl_area_ptr = __afl_area_ptr_local;
extern uint8_t __ddg_area_ptr_local[DDG_MAP_SIZE]; extern uint8_t __ddg_area_ptr_local[DDG_MAP_SIZE];

View File

@ -20,12 +20,12 @@ use core::ptr::addr_of_mut;
#[cfg(any(target_os = "linux", target_vendor = "apple"))] #[cfg(any(target_os = "linux", target_vendor = "apple"))]
use libafl::{mutators::Tokens, Error}; use libafl::{mutators::Tokens, Error};
use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_SIZE_MAX}; use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_ALLOCATED_SIZE, EDGES_MAP_DEFAULT_SIZE};
/// The map for edges. /// The map for edges.
#[no_mangle] #[no_mangle]
#[allow(non_upper_case_globals)] #[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_ALLOCATED_SIZE] = [0; EDGES_MAP_ALLOCATED_SIZE];
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
@ -85,9 +85,9 @@ 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]
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE; #[no_mangle]
pub static mut __afl_map_size: usize = EDGES_MAP_DEFAULT_SIZE;
#[cfg(any( #[cfg(any(
feature = "sancov_pcguard_edges", feature = "sancov_pcguard_edges",
@ -127,11 +127,11 @@ pub unsafe fn edges_map_mut_slice<'a>() -> OwnedMutSlice<'a, u8> {
/// ///
/// ```rust,ignore /// ```rust,ignore
/// use libafl::observers::StdMapObserver; /// use libafl::observers::StdMapObserver;
/// use libafl_targets::{EDGES_MAP, EDGES_MAP_SIZE_IN_USE}; /// use libafl_targets::{EDGES_MAP, EDGES_MAP_DEFAULT_SIZE};
/// ///
/// #[cfg(not(feature = "pointer_maps"))] /// #[cfg(not(feature = "pointer_maps"))]
/// let observer = unsafe { /// let observer = unsafe {
/// StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP_SIZE_IN_USE) /// StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP_DEFAULT_SIZE)
/// }; /// };
/// ``` /// ```
/// ///
@ -192,7 +192,7 @@ pub fn edges_max_num() -> usize {
} else { } else {
#[cfg(feature = "pointer_maps")] #[cfg(feature = "pointer_maps")]
{ {
EDGES_MAP_SIZE_MAX // the upper bound EDGES_MAP_ALLOCATED_SIZE // the upper bound
} }
#[cfg(not(feature = "pointer_maps"))] #[cfg(not(feature = "pointer_maps"))]
{ {

View File

@ -27,9 +27,9 @@ use crate::coverage::EDGES_MAP;
use crate::coverage::MAX_EDGES_FOUND; use crate::coverage::MAX_EDGES_FOUND;
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
#[allow(unused)] #[allow(unused)]
use crate::EDGES_MAP_SIZE_IN_USE; use crate::EDGES_MAP_DEFAULT_SIZE;
#[cfg(feature = "pointer_maps")] #[cfg(feature = "pointer_maps")]
use crate::{coverage::EDGES_MAP_PTR, EDGES_MAP_SIZE_MAX}; use crate::{coverage::EDGES_MAP_PTR, EDGES_MAP_ALLOCATED_SIZE};
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))] #[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
#[cfg(not(any(doc, feature = "clippy")))] #[cfg(not(any(doc, feature = "clippy")))]
@ -204,7 +204,7 @@ unsafe fn update_ngram(pos: usize) -> usize {
prev_array_8.as_mut_array()[0] = pos as u32; prev_array_8.as_mut_array()[0] = pos as u32;
reduced = prev_array_8.reduce_xor() as usize; reduced = prev_array_8.reduce_xor() as usize;
} }
reduced %= EDGES_MAP_SIZE_IN_USE; reduced %= EDGES_MAP_DEFAULT_SIZE;
reduced reduced
} }
@ -233,13 +233,13 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
{ {
pos = update_ngram(pos); pos = update_ngram(pos);
// println!("Wrinting to {} {}", pos, EDGES_MAP_SIZE_IN_USE); // println!("Wrinting to {} {}", pos, EDGES_MAP_DEFAULT_SIZE);
} }
#[cfg(feature = "sancov_ctx")] #[cfg(feature = "sancov_ctx")]
{ {
pos ^= __afl_prev_ctx as usize; pos ^= __afl_prev_ctx as usize;
// println!("Wrinting to {} {}", pos, EDGES_MAP_SIZE_IN_USE); // println!("Wrinting to {} {}", pos, EDGES_MAP_DEFAULT_SIZE);
} }
#[cfg(feature = "pointer_maps")] #[cfg(feature = "pointer_maps")]
@ -291,13 +291,13 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32
#[cfg(feature = "pointer_maps")] #[cfg(feature = "pointer_maps")]
{ {
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1) % EDGES_MAP_SIZE_MAX; MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1) % EDGES_MAP_ALLOCATED_SIZE;
} }
#[cfg(not(feature = "pointer_maps"))] #[cfg(not(feature = "pointer_maps"))]
{ {
let edges_map_len = (*addr_of!(EDGES_MAP)).len(); 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 ({edges_map_len}). Use the LIBAFL_EDGES_MAP_SIZE_IN_USE env to increase it at compile time."); 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_DEFAULT_SIZE env to increase it at compile time.");
} }
} }
} }

View File

@ -95,12 +95,15 @@ fn is_workspace_toml(path: &Path) -> bool {
false false
} }
async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Result<()> { async fn run_cargo_fmt(cargo_file_path: PathBuf, is_check: bool, verbose: bool) -> io::Result<()> {
// Make sure we parse the correct file // Make sure we parse the correct file
assert_eq!(path.file_name().unwrap().to_str().unwrap(), "Cargo.toml"); assert_eq!(
cargo_file_path.file_name().unwrap().to_str().unwrap(),
"Cargo.toml"
);
if is_workspace_toml(path.as_path()) { if is_workspace_toml(cargo_file_path.as_path()) {
println!("[*] Skipping {}...", path.as_path().display()); println!("[*] Skipping {}...", cargo_file_path.as_path().display());
return Ok(()); return Ok(());
} }
@ -112,14 +115,18 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
.arg("+nightly") .arg("+nightly")
.arg("fmt") .arg("fmt")
.arg("--manifest-path") .arg("--manifest-path")
.arg(path.as_path()); .arg(cargo_file_path.as_path());
if is_check { if is_check {
fmt_command.arg("--check"); fmt_command.arg("--check");
} }
if verbose { if verbose {
println!("[*] {} {}...", task_str, path.as_path().display()); println!(
"[*] {} {}...",
task_str,
cargo_file_path.as_path().display()
);
} }
let res = fmt_command.output().await?; let res = fmt_command.output().await?;
@ -130,7 +137,7 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
return Err(io::Error::new( return Err(io::Error::new(
ErrorKind::Other, ErrorKind::Other,
format!( format!(
"Cargo fmt failed. Run cargo fmt for {path:#?}.\nstdout: {stdout}\nstderr: {stderr}"), "Cargo fmt failed. Run cargo fmt for {cargo_file_path:#?}.\nstdout: {stdout}\nstderr: {stderr}\ncommand: {fmt_command:?}"),
)); ));
} }
@ -138,7 +145,7 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
} }
async fn run_clang_fmt( async fn run_clang_fmt(
path: PathBuf, c_file_path: PathBuf,
clang: String, clang: String,
is_check: bool, is_check: bool,
verbose: bool, verbose: bool,
@ -151,16 +158,16 @@ async fn run_clang_fmt(
.arg("-i") .arg("-i")
.arg("--style") .arg("--style")
.arg("file") .arg("file")
.arg(path.as_path()); .arg(c_file_path.as_path());
if is_check { if is_check {
fmt_command.arg("-Werror").arg("--dry-run"); fmt_command.arg("-Werror").arg("--dry-run");
} }
fmt_command.arg(path.as_path()); fmt_command.arg(c_file_path.as_path());
if verbose { if verbose {
println!("[*] {} {}...", task_str, path.as_path().display()); println!("[*] {} {}...", task_str, c_file_path.as_path().display());
} }
let res = fmt_command.output().await?; let res = fmt_command.output().await?;