From c12c6f31e203f3b004c7a690357d04d6194b7927 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Tue, 8 Oct 2024 15:18:13 +0200 Subject: [PATCH] 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 --- .github/workflows/build_and_test.yml | 25 --- docs/src/DEBUGGING.md | 2 +- docs/src/core_concepts/executor.md | 2 +- docs/src/design/migration-0.9.md | 2 +- .../fuzzbench_fork_qemu/Cargo.toml | 1 + .../fuzzbench_fork_qemu/Makefile.toml | 67 ++++---- .../binary_only/fuzzbench_fork_qemu/fuzz.c | 19 +++ .../fuzzbench_fork_qemu/src/fuzzer.rs | 61 +++---- fuzzers/binary_only/fuzzbench_qemu/Cargo.toml | 1 + .../binary_only/fuzzbench_qemu/Makefile.toml | 41 ++--- fuzzers/binary_only/fuzzbench_qemu/fuzz.c | 19 +++ .../binary_only/fuzzbench_qemu/src/fuzzer.rs | 22 +-- fuzzers/binary_only/qemu_cmin/Cargo.toml | 1 + fuzzers/binary_only/qemu_cmin/src/fuzzer.rs | 20 ++- fuzzers/binary_only/qemu_launcher/Cargo.toml | 1 + .../binary_only/qemu_launcher/src/client.rs | 90 ++-------- .../binary_only/qemu_launcher/src/harness.rs | 8 +- .../binary_only/qemu_launcher/src/instance.rs | 63 +++++-- .../forkserver_libafl_cc/src/main.rs | 4 +- fuzzers/full_system/qemu_baremetal/Cargo.toml | 1 + .../qemu_baremetal/src/fuzzer_breakpoint.rs | 50 +++--- .../qemu_baremetal/src/fuzzer_low_level.rs | 33 ++-- .../qemu_baremetal/src/fuzzer_sync_exit.rs | 33 ++-- .../full_system/qemu_linux_kernel/README.md | 6 + .../qemu_linux_kernel/src/fuzzer.rs | 5 +- .../full_system/qemu_linux_process/README.md | 6 + .../qemu_linux_process/src/fuzzer.rs | 5 +- fuzzers/inprocess/fuzzbench_ctx/src/lib.rs | 4 +- libafl/src/executors/hooks/inprocess.rs | 5 +- libafl/src/executors/inprocess/inner.rs | 21 +-- libafl/src/executors/inprocess_fork/inner.rs | 33 +--- .../src/executors/inprocess_fork/stateful.rs | 73 +++----- libafl/src/observers/map/const_map.rs | 29 +++- libafl/src/observers/map/hitcount_map.rs | 24 ++- libafl/src/observers/map/mod.rs | 27 +++ libafl/src/observers/map/variable_map.rs | 23 ++- libafl_bolts/src/ownedref.rs | 18 ++ libafl_cc/build.rs | 16 +- libafl_cc/src/cfg.rs | 4 +- libafl_cc/src/ctx-pass.cc | 2 +- libafl_cc/src/function-logging.cc | 2 +- libafl_qemu/libafl_qemu_build/src/bindings.rs | 5 + libafl_qemu/libafl_qemu_sys/src/usermode.rs | 12 +- .../src/x86_64_stub_bindings.rs | 16 ++ libafl_qemu/src/emu/hooks.rs | 19 +-- libafl_qemu/src/executor.rs | 69 +++++--- libafl_qemu/src/modules/edges.rs | 159 ++++++++++++------ .../src/modules/usermode/asan_guest.rs | 10 +- libafl_qemu/src/modules/usermode/snapshot.rs | 4 +- libafl_qemu/src/qemu/hooks.rs | 4 +- libafl_qemu/src/qemu/mod.rs | 4 +- libafl_qemu/src/qemu/usermode.rs | 10 +- libafl_sugar/src/qemu.rs | 31 ++-- libafl_targets/build.rs | 32 +++- libafl_targets/src/coverage.c | 2 +- libafl_targets/src/coverage.rs | 14 +- libafl_targets/src/sancov_pcguard.rs | 14 +- utils/libafl_fmt/src/main.rs | 29 ++-- 58 files changed, 731 insertions(+), 572 deletions(-) create mode 100644 fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c create mode 100644 fuzzers/binary_only/fuzzbench_qemu/fuzz.c diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 9c992899a7..f3c784b4f4 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -66,28 +66,6 @@ jobs: - name: Test libafl_targets no_std 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: runs-on: ubuntu-24.04 steps: @@ -246,9 +224,7 @@ jobs: fuzzers: needs: - - ubuntu - fuzzers-preflight - - common strategy: fail-fast: true matrix: @@ -355,7 +331,6 @@ jobs: fuzzers-qemu: needs: - - common - changes if: ${{ needs.changes.outputs.qemu == 'true' }} strategy: diff --git a/docs/src/DEBUGGING.md b/docs/src/DEBUGGING.md index d6063f968b..1485e7f7b4 100644 --- a/docs/src/DEBUGGING.md +++ b/docs/src/DEBUGGING.md @@ -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()); ``` -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. 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. diff --git a/docs/src/core_concepts/executor.md b/docs/src/core_concepts/executor.md index 1a677b6ef9..85ee0fff46 100644 --- a/docs/src/core_concepts/executor.md +++ b/docs/src/core_concepts/executor.md @@ -57,7 +57,7 @@ On your fuzzer side, you can allocate a shared memory region and make the `EDGES ```rust,ignore let mut shmem; 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(); unsafe{ diff --git a/docs/src/design/migration-0.9.md b/docs/src/design/migration-0.9.md index b48c3e7711..1c8292f9a6 100644 --- a/docs/src/design/migration-0.9.md +++ b/docs/src/design/migration-0.9.md @@ -169,7 +169,7 @@ from libafl_target's `EDGES_MAP`. In the future, instead of using: ```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); ``` diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/Cargo.toml b/fuzzers/binary_only/fuzzbench_fork_qemu/Cargo.toml index 4f4d8043a4..86b53e1ab8 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/Cargo.toml +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/Cargo.toml @@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [ "x86_64", "usermode", ] } +libafl_targets = { path = "../../../libafl_targets" } log = { version = "0.4.22", features = ["release_max_level_info"] } clap = { version = "4.5.18", features = ["default"] } diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/Makefile.toml b/fuzzers/binary_only/fuzzbench_fork_qemu/Makefile.toml index 228e7bfca0..7636140bca 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/Makefile.toml +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/Makefile.toml @@ -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 [env] -FUZZER_NAME = 'libpng_harness' +FUZZER_NAME = 'harness' PROJECT_DIR = { script = ["pwd"] } PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } } -PROFILE_DIR = { value = "release", condition = { env_not_set = [ - "PROFILE_DIR", -] } } +TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}" [tasks.unsupported] script_runner = "@shell" @@ -13,20 +30,6 @@ script = ''' 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 [tasks.fuzzer] linux_alias = "fuzzer_unix" @@ -46,20 +49,13 @@ windows_alias = "unsupported" [tasks.harness_unix] script_runner = "@shell" 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" -# Build the libpng harness -c++ \ - ../../inprocess/libfuzzer_libpng/harness.cc \ - ./libpng-1.6.37/.libs/libpng16.a \ +cc \ + ./fuzz.c \ ./libfuzzer_main.o \ - -I./libpng-1.6.37/ \ -o ${FUZZER_NAME} \ -lm -lz ''' -dependencies = ["libpng"] # Run the fuzzer [tasks.run] @@ -72,16 +68,16 @@ command = "cargo" args = [ "run", "--profile", - "${PROFILE_DIR}", + "${PROFILE}", "./${FUZZER_NAME}", "--", "--libafl-in", - "../libfuzzer_libpng/corpus", + "./corpus", "--libafl-out", "./out", "./${FUZZER_NAME}", ] -dependencies = ["harness", "fuzzer"] +dependencies = ["harness"] # Run the fuzzer [tasks.test] @@ -93,7 +89,13 @@ windows_alias = "unsupported" [tasks.test_unix] script_runner = "@shell" 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"] @@ -108,7 +110,6 @@ windows_alias = "unsupported" clear = true script_runner = "@shell" script = ''' -rm -f ./${FUZZER_NAME} libfuzzer_main.o -make -C libpng-1.6.37 clean +rm -f ./${FUZZER_NAME} cargo clean ''' diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c b/fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c new file mode 100644 index 0000000000..0460dd63d2 --- /dev/null +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c @@ -0,0 +1,19 @@ +#include +#include +#include + +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); + +}*/ diff --git a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs index 84cf20dadf..cf56953dad 100644 --- a/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs @@ -39,7 +39,7 @@ use libafl::{ }; use libafl_bolts::{ current_time, - os::{dup2, unix_signals::Signal}, + os::dup2, rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, tuples::{tuple_list, Merge}, @@ -50,11 +50,12 @@ use libafl_qemu::{ filter_qemu_args, modules::{ cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver}, - edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE}, + edges::StdEdgeCoverageChildModule, }, Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor, QemuShutdownCause, Regs, }; +use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR}; #[cfg(unix)] use nix::unistd::dup; @@ -148,10 +149,26 @@ fn fuzz( env::remove_var("LD_LIBRARY_PATH"); let args: Vec = 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!( - StdEdgeCoverageChildModule::builder().build(), + StdEdgeCoverageChildModule::builder() + .map_observer(edges_observer.as_mut()) + .build()?, CmpLogChildModule::default(), ); @@ -218,12 +235,6 @@ fn fuzz( 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::().unwrap(); 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 let time_observer = TimeObserver::new("time"); @@ -321,7 +323,7 @@ fn fuzz( let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); // 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 mut buf = target.as_slice(); let mut len = buf.len(); @@ -339,16 +341,17 @@ fn fuzz( qemu.write_reg(Regs::Rsp, stack_ptr).unwrap(); match qemu.run() { - Ok(QemuExitReason::Breakpoint(_)) => {} - Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => { - process::exit(0) + Ok(QemuExitReason::Breakpoint(_)) => ExitKind::Ok, + Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => { + 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( @@ -391,8 +394,8 @@ fn fuzz( #[cfg(unix)] { let null_fd = file_null.as_raw_fd(); - dup2(null_fd, io::stdout().as_raw_fd())?; - dup2(null_fd, io::stderr().as_raw_fd())?; + // dup2(null_fd, io::stdout().as_raw_fd())?; + // dup2(null_fd, io::stderr().as_raw_fd())?; } // reopen file to make sure we're at the end log.replace( diff --git a/fuzzers/binary_only/fuzzbench_qemu/Cargo.toml b/fuzzers/binary_only/fuzzbench_qemu/Cargo.toml index c07aa71efa..778d81194d 100644 --- a/fuzzers/binary_only/fuzzbench_qemu/Cargo.toml +++ b/fuzzers/binary_only/fuzzbench_qemu/Cargo.toml @@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [ "x86_64", "usermode", ] } +libafl_targets = { path = "../../../libafl_targets", version = "0.13.2" } log = { version = "0.4.22", features = ["release_max_level_info"] } clap = { version = "4.5.18", features = ["default"] } diff --git a/fuzzers/binary_only/fuzzbench_qemu/Makefile.toml b/fuzzers/binary_only/fuzzbench_qemu/Makefile.toml index 20dc7fe165..4a53108b56 100644 --- a/fuzzers/binary_only/fuzzbench_qemu/Makefile.toml +++ b/fuzzers/binary_only/fuzzbench_qemu/Makefile.toml @@ -1,11 +1,12 @@ # Variables [env] -FUZZER_NAME = 'libpng_harness' +FUZZER_NAME = 'harness' PROJECT_DIR = { script = ["pwd"] } PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } } PROFILE_DIR = { value = "release", condition = { env_not_set = [ "PROFILE_DIR", ] } } +TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}" [tasks.unsupported] script_runner = "@shell" @@ -13,20 +14,6 @@ script = ''' 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 [tasks.fuzzer] linux_alias = "fuzzer_unix" @@ -46,20 +33,13 @@ windows_alias = "unsupported" [tasks.harness_unix] script_runner = "@shell" 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" -# Build the libpng harness -c++ \ - ../../inprocess/libfuzzer_libpng/harness.cc \ - ./libpng-1.6.37/.libs/libpng16.a \ +cc \ + ./fuzz.c \ ./libfuzzer_main.o \ - -I./libpng-1.6.37/ \ -o ${FUZZER_NAME} \ -lm -lz ''' -dependencies = ["libpng"] # Run the fuzzer [tasks.run] @@ -81,7 +61,7 @@ args = [ "./out", "./${FUZZER_NAME}", ] -dependencies = ["harness", "fuzzer"] +dependencies = ["harness"] # Run the fuzzer [tasks.test] @@ -93,7 +73,13 @@ windows_alias = "unsupported" [tasks.test_unix] script_runner = "@shell" 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"] @@ -108,7 +94,6 @@ windows_alias = "unsupported" clear = true script_runner = "@shell" script = ''' -rm -f ./${FUZZER_NAME} libfuzzer_main.o -make -C libpng-1.6.37 clean +rm -f ./${FUZZER_NAME} cargo clean ''' diff --git a/fuzzers/binary_only/fuzzbench_qemu/fuzz.c b/fuzzers/binary_only/fuzzbench_qemu/fuzz.c new file mode 100644 index 0000000000..0460dd63d2 --- /dev/null +++ b/fuzzers/binary_only/fuzzbench_qemu/fuzz.c @@ -0,0 +1,19 @@ +#include +#include +#include + +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); + +}*/ diff --git a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs index 33441cf6de..909a6511d0 100644 --- a/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/binary_only/fuzzbench_qemu/src/fuzzer.rs @@ -38,7 +38,7 @@ use libafl::{ }; use libafl_bolts::{ current_time, - os::{dup2, unix_signals::Signal}, + os::dup2, ownedref::OwnedMutSlice, rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, @@ -50,9 +50,7 @@ use libafl_qemu::{ filter_qemu_args, // asan::{init_with_asan, QemuAsanHelper}, modules::cmplog::{CmpLogModule, CmpLogObserver}, - modules::edges::{ - edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND, - }, + modules::edges::StdEdgeCoverageModule, Emulator, GuestReg, //snapshot::QemuSnapshotHelper, @@ -64,6 +62,7 @@ use libafl_qemu::{ QemuShutdownCause, Regs, }; +use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_ALLOCATED_SIZE, MAX_EDGES_FOUND}; #[cfg(unix)] use nix::unistd::dup; @@ -253,10 +252,10 @@ fn fuzz( }; // Create an observation channel using the coverage map - let edges_observer = unsafe { + let mut edges_observer = unsafe { HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( "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), )) .track_indices() @@ -347,9 +346,9 @@ fn fuzz( match qemu.run() { Ok(QemuExitReason::Breakpoint(_)) => {} - Ok(QemuExitReason::End(QemuShutdownCause::HostSignal( - Signal::SigInterrupt, - ))) => process::exit(0), + Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => { + signal.handle(); + } Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash, _ => panic!("Unexpected QEMU exit."), } @@ -359,7 +358,10 @@ fn fuzz( }; let modules = tuple_list!( - StdEdgeCoverageModule::builder().build(), + StdEdgeCoverageModule::builder() + .map_observer(edges_observer.as_mut()) + .build() + .unwrap(), CmpLogModule::default(), // QemuAsanHelper::default(asan), //QemuSnapshotHelper::new() diff --git a/fuzzers/binary_only/qemu_cmin/Cargo.toml b/fuzzers/binary_only/qemu_cmin/Cargo.toml index b2e7ff8557..082d45af50 100644 --- a/fuzzers/binary_only/qemu_cmin/Cargo.toml +++ b/fuzzers/binary_only/qemu_cmin/Cargo.toml @@ -34,5 +34,6 @@ clap = { version = "4.5.18", features = ["derive", "string"] } libafl = { path = "../../../libafl" } libafl_bolts = { path = "../../../libafl_bolts" } libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] } +libafl_targets = { path = "../../../libafl_targets" } log = { version = "0.4.22", features = ["release_max_level_info"] } rangemap = { version = "1.5.1" } diff --git a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs index 0928835c1e..ded0700df8 100644 --- a/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_cmin/src/fuzzer.rs @@ -27,11 +27,11 @@ use libafl_bolts::{ AsSlice, AsSliceMut, }; use libafl_qemu::{ - elf::EasyElf, - modules::edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE}, - ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, - QemuExitReason, QemuForkExecutor, QemuShutdownCause, Regs, + elf::EasyElf, modules::edges::StdEdgeCoverageChildModule, ArchExtras, CallingConvention, + Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuExitReason, + QemuForkExecutor, QemuShutdownCause, Regs, }; +use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR}; #[derive(Default)] 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(); unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() }; - let edges_observer = unsafe { - HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr( + let mut edges_observer = unsafe { + HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_DEFAULT_SIZE>::from_mut_ptr( "edges", edges.as_mut_ptr(), )) @@ -185,7 +185,7 @@ pub fn fuzz() -> Result<(), Error> { let scheduler = QueueScheduler::new(); 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 mut buf = target.as_slice(); let mut len = buf.len(); @@ -218,7 +218,9 @@ pub fn fuzz() -> Result<(), Error> { 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()?; diff --git a/fuzzers/binary_only/qemu_launcher/Cargo.toml b/fuzzers/binary_only/qemu_launcher/Cargo.toml index 5a04546dd3..e49f9d227a 100644 --- a/fuzzers/binary_only/qemu_launcher/Cargo.toml +++ b/fuzzers/binary_only/qemu_launcher/Cargo.toml @@ -47,6 +47,7 @@ libafl_bolts = { path = "../../../libafl_bolts", features = [ "errors_backtrace", ] } libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] } +libafl_targets = { path = "../../../libafl_targets" } log = { version = "0.4.22", features = ["release_max_level_info"] } nix = { version = "0.29.0", features = ["fs"] } rangemap = { version = "1.5.1" } diff --git a/fuzzers/binary_only/qemu_launcher/src/client.rs b/fuzzers/binary_only/qemu_launcher/src/client.rs index 1e77941084..044f216e5a 100644 --- a/fuzzers/binary_only/qemu_launcher/src/client.rs +++ b/fuzzers/binary_only/qemu_launcher/src/client.rs @@ -1,4 +1,4 @@ -use std::{env, ops::Range}; +use std::env; use libafl::{ corpus::{InMemoryOnDiskCorpus, OnDiskCorpus}, @@ -16,8 +16,6 @@ use libafl_qemu::{ asan::{init_qemu_with_asan, AsanModule}, asan_guest::{init_qemu_with_asan_guest, AsanGuestModule}, cmplog::CmpLogModule, - edges::StdEdgeCoverageModule, - StdAddressFilter, }, ArchExtras, GuestAddr, Qemu, }; @@ -57,7 +55,7 @@ impl<'a> Client<'a> { .collect::>() } - fn start_pc(qemu: &Qemu) -> Result { + fn start_pc(qemu: Qemu) -> Result { let mut elf_buffer = Vec::new(); let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?; @@ -67,39 +65,6 @@ impl<'a> Client<'a> { Ok(start_pc) } - #[allow(clippy::similar_names)] // elf != self - fn coverage_filter(&self, qemu: &Qemu) -> Result { - /* 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::>>(); - 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::>>(); - 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( &self, state: Option, @@ -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}"); #[cfg(not(feature = "injections"))] @@ -163,10 +128,6 @@ impl<'a> Client<'a> { 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 .as_ref() .map(|h| h.tokens.clone()) @@ -174,7 +135,7 @@ impl<'a> Client<'a> { let instance_builder = Instance::builder() .options(self.options) - .qemu(&qemu) + .qemu(qemu) .mgr(mgr) .core_id(core_id) .extra_tokens(extra_tokens); @@ -183,7 +144,6 @@ impl<'a> Client<'a> { if let Some(injection_module) = injection_module { instance_builder.build().run( tuple_list!( - edge_coverage_module, CmpLogModule::default(), AsanModule::default(asan.take().unwrap()), injection_module, @@ -193,7 +153,6 @@ impl<'a> Client<'a> { } else { instance_builder.build().run( tuple_list!( - edge_coverage_module, CmpLogModule::default(), AsanModule::default(asan.take().unwrap()), ), @@ -204,9 +163,8 @@ impl<'a> Client<'a> { if let Some(injection_module) = injection_module { instance_builder.build().run( tuple_list!( - edge_coverage_module, CmpLogModule::default(), - AsanGuestModule::default(&qemu, asan_lib.take().unwrap()), + AsanGuestModule::default(qemu, asan_lib.take().unwrap()), injection_module ), state, @@ -214,9 +172,8 @@ impl<'a> Client<'a> { } else { instance_builder.build().run( tuple_list!( - edge_coverage_module, CmpLogModule::default(), - AsanGuestModule::default(&qemu, asan_lib.take().unwrap()), + AsanGuestModule::default(qemu, asan_lib.take().unwrap()), ), state, ) @@ -224,52 +181,35 @@ impl<'a> Client<'a> { } else if is_asan { if let Some(injection_module) = injection_module { instance_builder.build().run( - tuple_list!( - edge_coverage_module, - AsanModule::default(asan.take().unwrap()), - injection_module - ), + tuple_list!(AsanModule::default(asan.take().unwrap()), injection_module), state, ) } else { instance_builder.build().run( - tuple_list!( - edge_coverage_module, - AsanModule::default(asan.take().unwrap()), - ), + tuple_list!(AsanModule::default(asan.take().unwrap()),), state, ) } } else if is_asan_guest { - let modules = tuple_list!( - edge_coverage_module, - AsanGuestModule::default(&qemu, asan_lib.take().unwrap()) - ); + let modules = tuple_list!(AsanGuestModule::default(qemu, asan_lib.take().unwrap())); instance_builder.build().run(modules, state) } else if is_cmplog { if let Some(injection_module) = injection_module { instance_builder.build().run( - tuple_list!( - edge_coverage_module, - CmpLogModule::default(), - injection_module - ), + tuple_list!(CmpLogModule::default(), injection_module), state, ) } else { - instance_builder.build().run( - tuple_list!(edge_coverage_module, CmpLogModule::default()), - state, - ) + instance_builder + .build() + .run(tuple_list!(CmpLogModule::default()), state) } } else if let Some(injection_module) = injection_module { instance_builder .build() - .run(tuple_list!(edge_coverage_module, injection_module), state) + .run(tuple_list!(injection_module), state) } else { - instance_builder - .build() - .run(tuple_list!(edge_coverage_module), state) + instance_builder.build().run(tuple_list!(), state) } } } diff --git a/fuzzers/binary_only/qemu_launcher/src/harness.rs b/fuzzers/binary_only/qemu_launcher/src/harness.rs index 946796be78..8a959ef6ea 100644 --- a/fuzzers/binary_only/qemu_launcher/src/harness.rs +++ b/fuzzers/binary_only/qemu_launcher/src/harness.rs @@ -6,8 +6,8 @@ use libafl::{ use libafl_bolts::AsSlice; use libafl_qemu::{ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, Regs}; -pub struct Harness<'a> { - qemu: &'a Qemu, +pub struct Harness { + qemu: Qemu, input_addr: GuestAddr, pc: GuestAddr, stack_ptr: GuestAddr, @@ -16,8 +16,8 @@ pub struct Harness<'a> { pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB -impl<'a> Harness<'a> { - pub fn new(qemu: &Qemu) -> Result { +impl Harness { + pub fn new(qemu: Qemu) -> Result { let input_addr = qemu .map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite) .map_err(|e| Error::unknown(format!("Failed to map input buffer: {e:}")))?; diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index 2de9d64026..7cd2bd2068 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -1,5 +1,5 @@ use core::{fmt::Debug, ptr::addr_of_mut}; -use std::{marker::PhantomData, process}; +use std::{marker::PhantomData, ops::Range, process}; #[cfg(feature = "simplemgr")] use libafl::events::SimpleEventManager; @@ -35,16 +35,16 @@ use libafl_bolts::{ core_affinity::CoreId, ownedref::OwnedMutSlice, rands::StdRand, - tuples::{tuple_list, Merge}, + tuples::{tuple_list, Merge, Prepend}, }; use libafl_qemu::{ + elf::EasyElf, modules::{ - cmplog::CmpLogObserver, - edges::{edges_map_mut_ptr, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND}, - EmulatorModuleTuple, + cmplog::CmpLogObserver, EmulatorModuleTuple, StdAddressFilter, StdEdgeCoverageModule, }, - 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 crate::{harness::Harness, options::FuzzerOptions}; @@ -61,7 +61,7 @@ pub type ClientMgr = #[derive(TypedBuilder)] pub struct Instance<'a, M: Monitor> { options: &'a FuzzerOptions, - qemu: &'a Qemu, + qemu: Qemu, mgr: ClientMgr, core_id: CoreId, #[builder(default)] @@ -71,20 +71,60 @@ pub struct Instance<'a, M: Monitor> { } impl<'a, M: Monitor> Instance<'a, M> { + #[allow(clippy::similar_names)] // elf != self + fn coverage_filter(&self, qemu: Qemu) -> Result { + /* 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::>>(); + 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::>>(); + 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(&mut self, modules: ET, state: Option) -> Result<(), Error> where ET: EmulatorModuleTuple + Debug, { // Create an observation channel using the coverage map - let edges_observer = unsafe { + let mut edges_observer = unsafe { HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( "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), )) .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 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 let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - let emulator = Emulator::empty() - .qemu(*self.qemu) - .modules(modules) - .build()?; + let emulator = Emulator::empty().qemu(self.qemu).modules(modules).build()?; if self.options.is_cmplog_core(self.core_id) { // Create a QEMU in-process executor diff --git a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs index a33c8893b0..7723143ff8 100644 --- a/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs +++ b/fuzzers/forkserver/forkserver_libafl_cc/src/main.rs @@ -24,7 +24,7 @@ use libafl_bolts::{ tuples::{tuple_list, Handled, MatchNameRef, Merge}, AsSliceMut, Truncate, }; -use libafl_targets::EDGES_MAP_SIZE_IN_USE; +use libafl_targets::EDGES_MAP_DEFAULT_SIZE; use nix::sys::signal::Signal; /// The commandline args this fuzzer accepts @@ -87,7 +87,7 @@ struct Opt { pub fn main() { 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 corpus_dirs: Vec = [opt.in_dir].to_vec(); diff --git a/fuzzers/full_system/qemu_baremetal/Cargo.toml b/fuzzers/full_system/qemu_baremetal/Cargo.toml index d86057ddfd..43ba706f35 100644 --- a/fuzzers/full_system/qemu_baremetal/Cargo.toml +++ b/fuzzers/full_system/qemu_baremetal/Cargo.toml @@ -28,6 +28,7 @@ codegen-units = 1 [dependencies] libafl = { path = "../../../libafl" } libafl_bolts = { path = "../../../libafl_bolts" } +libafl_targets = { path = "../../../libafl_targets" } libafl_qemu = { path = "../../../libafl_qemu", features = [ "arm", "systemmode", diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs index f377724459..d33aac5b5e 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_breakpoint.rs @@ -33,11 +33,11 @@ use libafl_qemu::{ elf::EasyElf, emu::Emulator, executor::QemuExecutor, - modules::edges::{ - edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND, - }, + modules::edges::StdEdgeCoverageModule, 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 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 args: Vec = 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 let emu = Emulator::builder() .qemu_cli(args) - .add_module(StdEdgeCoverageModule::builder().build()) + .add_module( + StdEdgeCoverageModule::builder() + .map_observer(edges_observer.as_mut()) + .build()?, + ) .build() .unwrap(); @@ -119,25 +142,6 @@ pub fn fuzz() { let devices = emu.list_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 // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs index ae90034b51..1137a1437c 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_low_level.rs @@ -29,15 +29,11 @@ use libafl_bolts::{ AsSlice, }; use libafl_qemu::{ - config, - elf::EasyElf, - executor::QemuExecutor, - modules::edges::{ - edges_map_mut_ptr, StdEdgeCoverageModuleBuilder, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND, - }, + config, elf::EasyElf, executor::QemuExecutor, modules::edges::StdEdgeCoverageModuleBuilder, Emulator, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, Regs, }; 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; @@ -86,6 +82,17 @@ pub fn fuzz() { let mut run_client = |state: Option<_>, mut mgr, _core_id| { 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 let qemu = Qemu::builder() .machine("mps2-an385") @@ -103,7 +110,9 @@ pub fn fuzz() { .build() .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() .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 let time_observer = TimeObserver::new("time"); diff --git a/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs b/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs index 6847e37f4f..082ce8d021 100644 --- a/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs +++ b/fuzzers/full_system/qemu_baremetal/src/fuzzer_sync_exit.rs @@ -26,13 +26,8 @@ use libafl_bolts::{ shmem::{ShMemProvider, StdShMemProvider}, tuples::tuple_list, }; -use libafl_qemu::{ - emu::Emulator, - executor::QemuExecutor, - modules::edges::{ - edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND, - }, -}; +use libafl_qemu::{emu::Emulator, executor::QemuExecutor, modules::edges::StdEdgeCoverageModule}; +use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND}; // use libafl_qemu::QemuSnapshotBuilder; for normal qemu snapshot pub fn fuzz() { @@ -52,8 +47,20 @@ pub fn fuzz() { // Initialize QEMU let args: Vec = 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 - let modules = tuple_list!(StdEdgeCoverageModule::builder().build()); + let modules = tuple_list!(StdEdgeCoverageModule::builder() + .map_observer(edges_observer.as_mut()) + .build()?); let emu = Emulator::builder() .qemu_cli(args) @@ -69,16 +76,6 @@ pub fn fuzz() { 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"); diff --git a/fuzzers/full_system/qemu_linux_kernel/README.md b/fuzzers/full_system/qemu_linux_kernel/README.md index 2ca2e61569..528a3d4414 100644 --- a/fuzzers/full_system/qemu_linux_kernel/README.md +++ b/fuzzers/full_system/qemu_linux_kernel/README.md @@ -2,6 +2,12 @@ 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 TODO diff --git a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs index 3e28852bed..786a3f33e6 100644 --- a/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_kernel/src/fuzzer.rs @@ -36,7 +36,8 @@ use libafl_qemu::{ modules::{ cmplog::CmpLogObserver, 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, }, @@ -89,7 +90,7 @@ pub fn fuzz() { let edges_observer = unsafe { HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( "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), )) .track_indices() diff --git a/fuzzers/full_system/qemu_linux_process/README.md b/fuzzers/full_system/qemu_linux_process/README.md index 204d73a3b1..08c9f01e82 100644 --- a/fuzzers/full_system/qemu_linux_process/README.md +++ b/fuzzers/full_system/qemu_linux_process/README.md @@ -3,6 +3,12 @@ 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. +## 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 TODO diff --git a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs index e2bb9284e8..b62e704fb6 100644 --- a/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs +++ b/fuzzers/full_system/qemu_linux_process/src/fuzzer.rs @@ -36,7 +36,8 @@ use libafl_qemu::{ modules::{ cmplog::CmpLogObserver, 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, }, @@ -91,7 +92,7 @@ pub fn fuzz() { let edges_observer = unsafe { HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( "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), )) .track_indices() diff --git a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs index 4a368ced85..8ccb70500b 100644 --- a/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs +++ b/fuzzers/inprocess/fuzzbench_ctx/src/lib.rs @@ -55,7 +55,7 @@ use libafl_bolts::{ use libafl_targets::autotokens; use libafl_targets::{ edges_map_mut_ptr, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CtxHook, - EDGES_MAP_SIZE_IN_USE, + EDGES_MAP_DEFAULT_SIZE, }; #[cfg(unix)] use nix::unistd::dup; @@ -252,7 +252,7 @@ fn fuzz( let edges_observer = HitcountsMapObserver::new(unsafe { StdMapObserver::from_mut_slice( "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(); diff --git a/libafl/src/executors/hooks/inprocess.rs b/libafl/src/executors/hooks/inprocess.rs index 993fefdeec..ab926794bb 100644 --- a/libafl/src/executors/hooks/inprocess.rs +++ b/libafl/src/executors/hooks/inprocess.rs @@ -40,10 +40,7 @@ use crate::{ /// The inmem executor's handlers. #[allow(missing_debug_implementations)] -pub struct InProcessHooks -where - S: UsesInput, -{ +pub struct InProcessHooks { /// On crash C function pointer #[cfg(feature = "std")] pub crash_handler: *const c_void, diff --git a/libafl/src/executors/inprocess/inner.rs b/libafl/src/executors/inprocess/inner.rs index a4f4202721..52598a574a 100644 --- a/libafl/src/executors/inprocess/inner.rs +++ b/libafl/src/executors/inprocess/inner.rs @@ -35,12 +35,7 @@ use crate::{ }; /// The internal state of `GenericInProcessExecutor`. -pub struct GenericInProcessExecutorInner -where - HT: ExecutorHooksTuple, - OT: ObserversTuple, - S: State, -{ +pub struct GenericInProcessExecutorInner { /// The observers, observing each run pub(super) observers: OT, // Crash and timeout hah @@ -50,9 +45,7 @@ where impl Debug for GenericInProcessExecutorInner where - HT: ExecutorHooksTuple, - OT: ObserversTuple + Debug, - S: State, + OT: Debug, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("GenericInProcessExecutorState") @@ -63,8 +56,6 @@ where impl UsesState for GenericInProcessExecutorInner where - HT: ExecutorHooksTuple, - OT: ObserversTuple, S: State, { type State = S; @@ -72,7 +63,6 @@ where impl HasObservers for GenericInProcessExecutorInner where - HT: ExecutorHooksTuple, OT: ObserversTuple, S: State, { @@ -92,7 +82,6 @@ where impl GenericInProcessExecutorInner where HT: ExecutorHooksTuple, - OT: ObserversTuple, S: State, { /// This function marks the boundary between the fuzzer and the target @@ -156,7 +145,7 @@ impl GenericInProcessExecutorInner where HT: ExecutorHooksTuple, OT: ObserversTuple, - S: HasExecutions + HasSolutions + HasCorpus + State, + S: HasCorpus + HasExecutions + HasSolutions + UsesInput, { /// Create a new in mem executor with the default timeout (5 sec) pub fn generic( @@ -288,9 +277,7 @@ where impl HasInProcessHooks for GenericInProcessExecutorInner where - HT: ExecutorHooksTuple, - OT: ObserversTuple, - S: State + HasExecutions + HasSolutions + HasCorpus, + S: UsesInput, { /// the timeout handler #[inline] diff --git a/libafl/src/executors/inprocess_fork/inner.rs b/libafl/src/executors/inprocess_fork/inner.rs index ec45b17132..d582336511 100644 --- a/libafl/src/executors/inprocess_fork/inner.rs +++ b/libafl/src/executors/inprocess_fork/inner.rs @@ -35,15 +35,7 @@ use crate::{ }; /// Inner state of GenericInProcessExecutor-like structures. -pub struct GenericInProcessForkExecutorInner -where - OT: ObserversTuple, - S: UsesInput, - SP: ShMemProvider, - HT: ExecutorHooksTuple, - EM: UsesState, - Z: UsesState, -{ +pub struct GenericInProcessForkExecutorInner { pub(super) hooks: (InChildProcessHooks, HT), pub(super) shmem_provider: SP, pub(super) observers: OT, @@ -56,12 +48,9 @@ where impl Debug for GenericInProcessForkExecutorInner where - OT: ObserversTuple + Debug, - S: UsesInput, - SP: ShMemProvider, - HT: ExecutorHooksTuple + Debug, - EM: UsesState, - Z: UsesState, + HT: Debug, + OT: Debug, + SP: Debug, { #[cfg(target_os = "linux")] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -86,12 +75,7 @@ where impl UsesState for GenericInProcessForkExecutorInner where - OT: ObserversTuple, S: State, - SP: ShMemProvider, - HT: ExecutorHooksTuple, - EM: UsesState, - Z: UsesState, { type State = S; } @@ -195,9 +179,6 @@ where HT: ExecutorHooksTuple, S: State, OT: ObserversTuple, - SP: ShMemProvider, - EM: EventFirer + EventRestarter, - Z: UsesState, { #[inline] /// This function marks the boundary between the fuzzer and the target. @@ -319,12 +300,8 @@ where impl HasObservers for GenericInProcessForkExecutorInner where - HT: ExecutorHooksTuple, - S: State, OT: ObserversTuple, - SP: ShMemProvider, - EM: UsesState, - Z: UsesState, + S: State, { type Observers = OT; diff --git a/libafl/src/executors/inprocess_fork/stateful.rs b/libafl/src/executors/inprocess_fork/stateful.rs index 2bff436020..f5a5d854c2 100644 --- a/libafl/src/executors/inprocess_fork/stateful.rs +++ b/libafl/src/executors/inprocess_fork/stateful.rs @@ -24,7 +24,7 @@ use crate::{ fuzzer::HasObjective, inputs::UsesInput, observers::ObserversTuple, - state::{HasExecutions, HasSolutions, State, UsesState}, + state::{HasExecutions, State, UsesState}, Error, }; @@ -32,15 +32,11 @@ use crate::{ pub type StatefulInProcessForkExecutor<'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 - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, - SP: ShMemProvider, - EM: EventFirer + EventRestarter, - OF: Feedback, - S: State + HasSolutions, - Z: HasObjective, + S: State, { #[allow(clippy::too_many_arguments)] /// 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. pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, - OT: ObserversTuple, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, S: UsesInput, - SP: ShMemProvider, - HT: ExecutorHooksTuple, - EM: UsesState, - Z: UsesState, { + /// The harness function, being executed for each fuzzing loop execution harness_fn: &'a mut H, - exposed_executor_state: ES, - inner: GenericInProcessForkExecutorInner, + /// The state used as argument of the harness + pub exposed_executor_state: ES, + /// Inner state of the executor + pub inner: GenericInProcessForkExecutorInner, phantom: PhantomData, } impl Debug for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, - OT: ObserversTuple + Debug, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, + HT: Debug, + OT: Debug, S: UsesInput, - SP: ShMemProvider, - HT: ExecutorHooksTuple + Debug, - EM: UsesState, - Z: UsesState, + SP: Debug, { #[cfg(target_os = "linux")] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -116,13 +108,8 @@ where impl UsesState for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, - OT: ObserversTuple, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, S: State, - SP: ShMemProvider, - HT: ExecutorHooksTuple, - EM: UsesState, - Z: UsesState, { type State = S; } @@ -130,14 +117,14 @@ where impl Executor for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, + EM: EventFirer + EventRestarter, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, + HT: ExecutorHooksTuple, + OF: Feedback, OT: ObserversTuple + Debug, S: State + HasExecutions, SP: ShMemProvider, - HT: ExecutorHooksTuple, - EM: EventFirer + EventRestarter, Z: HasObjective, - OF: Feedback, { #[allow(unreachable_code)] #[inline] @@ -156,7 +143,7 @@ where Ok(ForkResult::Child) => { // Child 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); 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> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, HT: ExecutorHooksTuple, OT: ObserversTuple, - SP: ShMemProvider, - Z: UsesState, - EM: EventFirer + EventRestarter, - OF: Feedback, - S: State + HasSolutions, - Z: HasObjective, + S: State, { /// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks #[allow(clippy::too_many_arguments)] @@ -228,15 +210,12 @@ where impl HasObservers for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z> where - H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized, - HT: ExecutorHooksTuple, - S: State, + H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, - SP: ShMemProvider, - EM: UsesState, - Z: UsesState, + S: State, { type Observers = OT; + #[inline] fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> { self.inner.observers() diff --git a/libafl/src/observers/map/const_map.rs b/libafl/src/observers/map/const_map.rs index 109f615864..0e244ce407 100644 --- a/libafl/src/observers/map/const_map.rs +++ b/libafl/src/observers/map/const_map.rs @@ -12,10 +12,12 @@ use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut, HasLen, Named}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - observers::{map::MapObserver, Observer}, + observers::{map::MapObserver, Observer, VariableLengthMapObserver}, Error, }; +// TODO: remove the size field and implement ConstantLengthMapObserver + /// Use a const size to speedup `Feedback::is_interesting` when the user can /// know the size of the map at compile time. #[derive(Serialize, Deserialize, Debug)] @@ -24,6 +26,7 @@ pub struct ConstMapObserver<'a, T, const N: usize> { map: OwnedMutSlice<'a, T>, initial: T, name: Cow<'static, str>, + size: usize, } impl Observer for ConstMapObserver<'_, T, N> @@ -147,6 +150,27 @@ where } } +impl 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 Deref for ConstMapObserver<'_, T, N> { type Target = [T]; fn deref(&self) -> &[T] { @@ -176,6 +200,7 @@ where map: OwnedMutSlice::from(map), name: Cow::from(name), initial: T::default(), + size: N, } } @@ -188,6 +213,7 @@ where map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N), name: Cow::from(name), initial: T::default(), + size: N, } } } @@ -209,6 +235,7 @@ where map: OwnedMutSlice::from(map), name: Cow::from(name), initial, + size: N, } } } diff --git a/libafl/src/observers/map/hitcount_map.rs b/libafl/src/observers/map/hitcount_map.rs index 6e4ce5543b..38e6879723 100644 --- a/libafl/src/observers/map/hitcount_map.rs +++ b/libafl/src/observers/map/hitcount_map.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ executors::ExitKind, - observers::{map::MapObserver, DifferentialObserver, Observer}, + observers::{map::MapObserver, DifferentialObserver, Observer, VariableLengthMapObserver}, Error, }; @@ -220,6 +220,7 @@ where fn hash_simple(&self) -> u64 { self.base.hash_simple() } + fn to_vec(&self) -> Vec { self.base.to_vec() } @@ -229,6 +230,27 @@ where } } +impl VariableLengthMapObserver for HitcountsMapObserver +where + M: VariableLengthMapObserver + MapObserver, +{ + 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 Truncate for HitcountsMapObserver where M: Named + Serialize + serde::de::DeserializeOwned + Truncate, diff --git a/libafl/src/observers/map/mod.rs b/libafl/src/observers/map/mod.rs index d6d21c7bc8..0415f10a44 100644 --- a/libafl/src/observers/map/mod.rs +++ b/libafl/src/observers/map/mod.rs @@ -385,6 +385,33 @@ pub trait MapObserver: 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: 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 CanTrack for M where M: MapObserver, diff --git a/libafl/src/observers/map/variable_map.rs b/libafl/src/observers/map/variable_map.rs index c94a1b54b7..b5b4e56305 100644 --- a/libafl/src/observers/map/variable_map.rs +++ b/libafl/src/observers/map/variable_map.rs @@ -15,7 +15,7 @@ use libafl_bolts::{ use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - observers::{map::MapObserver, Observer}, + observers::{map::MapObserver, Observer, VariableLengthMapObserver}, Error, }; @@ -149,6 +149,27 @@ where } } +impl 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 Deref for VariableMapObserver<'_, T> { type Target = [T]; fn deref(&self) -> &[T] { diff --git a/libafl_bolts/src/ownedref.rs b/libafl_bolts/src/ownedref.rs index ecd1cc99f9..023e2b860c 100644 --- a/libafl_bolts/src/ownedref.rs +++ b/libafl_bolts/src/ownedref.rs @@ -905,6 +905,24 @@ impl OwnedMutPtr { pub unsafe fn from_raw_mut(ptr: *mut T) -> Self { 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 Serialize for OwnedMutPtr { diff --git a/libafl_cc/build.rs b/libafl_cc/build.rs index 73999f9e34..15f1403ec0 100644 --- a/libafl_cc/build.rs +++ b/libafl_cc/build.rs @@ -239,7 +239,7 @@ fn main() { println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS"); println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS"); 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_DDG_MAP_SIZE"); println!("cargo:rerun-if-changed=src/common-llvm.h"); @@ -312,13 +312,13 @@ pub const LIBAFL_CC_LLVM_VERSION: Option = None; }; let mut cxxflags: Vec = 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) - .expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); - let edges_map_size_max: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_MAX") + .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE"); + let edge_map_allocated_size: usize = option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE") .map_or(Ok(2_621_440), str::parse) - .expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); - cxxflags.push(format!("-DEDGES_MAP_SIZE_IN_USE={edges_map_size_in_use}")); + .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE"); + cxxflags.push(format!("-DEDGES_MAP_DEFAULT_SIZE={edge_map_default_size}")); let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE") .map_or(Ok(65_536), str::parse) @@ -348,9 +348,9 @@ pub const LIBAFL_CC_LLVM_VERSION: Option = None; pub const CLANGXX_PATH: &str = {clangcpp:?}; /// 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 - 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 pub const ACCOUNTING_MAP_SIZE: usize = {acc_map_size}; diff --git a/libafl_cc/src/cfg.rs b/libafl_cc/src/cfg.rs index 9c353ffa52..0551bb8b97 100644 --- a/libafl_cc/src/cfg.rs +++ b/libafl_cc/src/cfg.rs @@ -95,9 +95,9 @@ where /// Inserts an edge into CFG. #[must_use] 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) - .expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE"); + .expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE"); Self { edges: (0..map_size).map(|_| None).collect(), func_to_entry_bb: HashMap::default(), diff --git a/libafl_cc/src/ctx-pass.cc b/libafl_cc/src/ctx-pass.cc index 9f70445e2f..527c0cddac 100644 --- a/libafl_cc/src/ctx-pass.cc +++ b/libafl_cc/src/ctx-pass.cc @@ -64,7 +64,7 @@ using namespace llvm; -#define MAP_SIZE EDGES_MAP_SIZE_IN_USE +#define MAP_SIZE EDGES_MAP_DEFAULT_SIZE namespace { diff --git a/libafl_cc/src/function-logging.cc b/libafl_cc/src/function-logging.cc index b67641f5b6..f96c2f4b2f 100644 --- a/libafl_cc/src/function-logging.cc +++ b/libafl_cc/src/function-logging.cc @@ -64,7 +64,7 @@ using namespace llvm; -#define MAP_SIZE EDGES_MAP_SIZE_IN_USE +#define MAP_SIZE EDGES_MAP_DEFAULT_SIZE namespace { diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index 25f78886c5..8a8318ea12 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -133,6 +133,11 @@ pub fn generate( }) .header(wrapper_h.display().to_string()) .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_long") .allowlist_type("CPUState") diff --git a/libafl_qemu/libafl_qemu_sys/src/usermode.rs b/libafl_qemu/libafl_qemu_sys/src/usermode.rs index ee4c4155e7..f2892ccf18 100644 --- a/libafl_qemu/libafl_qemu_sys/src/usermode.rs +++ b/libafl_qemu/libafl_qemu_sys/src/usermode.rs @@ -2,21 +2,11 @@ use core::{slice::from_raw_parts, str::from_utf8_unchecked}; use libc::{c_char, strlen}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use paste::paste; #[cfg(feature = "python")] use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python}; use strum_macros::EnumIter; -use crate::{extern_c_checked, 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; -} +use crate::{libafl_mapinfo, GuestAddr, MmapPerms}; #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)] #[repr(i32)] diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index dd6a3d4010..175527eb42 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -12525,6 +12525,9 @@ impl Default for IntervalTreeNode { pub type IntervalTreeRoot = RBRootLeftCached; pub type abi_ulong = target_ulong; pub type abi_long = target_long; +extern "C" { + pub static mut guest_base: usize; +} extern "C" { #[doc = " --- Begin LibAFL code ---"] 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" { pub fn target_mprotect( start: abi_ulong, @@ -13757,6 +13766,13 @@ impl Default for libafl_mapinfo { } } } +extern "C" { + pub static mut libafl_dump_core_hook: + ::std::option::Option; +} +extern "C" { + pub static mut libafl_force_dfl: ::std::os::raw::c_int; +} extern "C" { pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int); } diff --git a/libafl_qemu/src/emu/hooks.rs b/libafl_qemu/src/emu/hooks.rs index fe836b19bc..55338d94ac 100644 --- a/libafl_qemu/src/emu/hooks.rs +++ b/libafl_qemu/src/emu/hooks.rs @@ -15,8 +15,8 @@ use crate::qemu::{ }; #[cfg(emulation_mode = "usermode")] use crate::qemu::{ - CrashHookClosure, PostSyscallHookClosure, PostSyscallHookFn, PreSyscallHookClosure, - PreSyscallHookFn, + CrashHookClosure, CrashHookFn, PostSyscallHookClosure, PostSyscallHookFn, + PreSyscallHookClosure, PreSyscallHookFn, }; use crate::{ 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(); -#[cfg(emulation_mode = "usermode")] -static mut CRASH_HOOKS: Vec = vec![]; - #[cfg(emulation_mode = "usermode")] pub extern "C" fn crash_hook_wrapper(target_sig: i32) where @@ -78,17 +75,17 @@ where S: Unpin + UsesInput, { unsafe { - let hooks = Qemu::get().unwrap().hooks(); + let emulator_modules = EmulatorModules::::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 { HookRepr::Function(ptr) => { - let func: fn(QemuHooks, i32) = transmute(*ptr); - func(hooks, target_sig); + let func: CrashHookFn = transmute(*ptr); + func(emulator_modules, target_sig); } HookRepr::Closure(ptr) => { - let func: &mut Box = transmute(ptr); - func(hooks, target_sig); + let func: &mut CrashHookClosure = transmute(ptr); + func(emulator_modules, target_sig); } HookRepr::Empty => (), } diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 3eb7adb5ed..0cb5d12b1f 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -15,6 +15,7 @@ use libafl::{ executors::{ hooks::inprocess::InProcessExecutorHandlerData, inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks}, + inprocess_fork::stateful::StatefulInProcessForkExecutor, Executor, ExitKind, HasObservers, }, feedbacks::Feedback, @@ -25,10 +26,6 @@ use libafl::{ Error, ExecutionProcessor, HasScheduler, }; #[cfg(feature = "fork")] -use libafl::{ - events::EventManager, executors::InProcessForkExecutor, state::HasLastReportTime, HasMetadata, -}; -#[cfg(feature = "fork")] use libafl_bolts::shmem::ShMemProvider; use libafl_bolts::{ 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, EM, Z>; + #[cfg(feature = "fork")] pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> where CM: CommandManager, - EM: UsesState, ET: EmulatorModuleTuple, - H: FnMut(&S::Input) -> ExitKind + ?Sized, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, S: UsesInput, SP: ShMemProvider, Z: UsesState, { - inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, - emulator: Emulator, + inner: QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>, } #[cfg(feature = "fork")] @@ -302,7 +300,7 @@ where EM: UsesState, ED: Debug, ET: EmulatorModuleTuple + Debug, - H: FnMut(&S::Input) -> ExitKind + ?Sized, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple + Debug, S: UsesInput + Debug, SM: Debug, @@ -312,7 +310,7 @@ where fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("QemuForkExecutor") .field("inner", &self.inner) - .field("emulator", &self.emulator) + .field("emulator", &self.inner.exposed_executor_state) .finish() } } @@ -324,7 +322,7 @@ where CM: CommandManager, EM: EventFirer + EventRestarter, ET: EmulatorModuleTuple, - H: FnMut(&S::Input) -> ExitKind + ?Sized, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, S: State + HasSolutions, 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"); Ok(Self { - inner: InProcessForkExecutor::new( + inner: StatefulInProcessForkExecutor::new( harness_fn, + emulator, observers, fuzzer, state, @@ -353,39 +352,41 @@ where timeout, 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 } - 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 } pub fn emulator(&self) -> &Emulator { - &self.emulator + &self.inner.exposed_executor_state } pub fn emulator_mut(&mut self) -> &Emulator { - &mut self.emulator + &mut self.inner.exposed_executor_state } } #[cfg(feature = "fork")] -impl<'a, CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor - for QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> +impl Executor + for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z> where CM: CommandManager, - EM: EventManager, Z, State = S>, - H: FnMut(&S::Input) -> ExitKind, - S: Unpin + State + HasMetadata + HasExecutions + HasLastReportTime + HasCorpus + HasSolutions, - OT: ObserversTuple + Debug, + ED: EmulatorDriver, + EM: EventFirer + EventRestarter, ET: EmulatorModuleTuple, - SP: ShMemProvider, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind, OF: Feedback, + OT: ObserversTuple + Debug, + S: State + HasExecutions + Unpin, + SP: ShMemProvider, Z: HasObjective, { fn run_target( @@ -395,7 +396,20 @@ where mgr: &mut EM, input: &Self::Input, ) -> Result { - 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 UsesState for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z> where CM: CommandManager, - EM: UsesState, ET: EmulatorModuleTuple, - H: FnMut(&S::Input) -> ExitKind + ?Sized, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, S: State, SP: ShMemProvider, @@ -422,7 +435,7 @@ where CM: CommandManager, EM: UsesState, ET: EmulatorModuleTuple, - H: FnMut(&S::Input) -> ExitKind + ?Sized, + H: FnMut(&mut Emulator, &S::Input) -> ExitKind + ?Sized, OT: ObserversTuple, S: State, SP: ShMemProvider, diff --git a/libafl_qemu/src/modules/edges.rs b/libafl_qemu/src/modules/edges.rs index 2560653f01..2152570bfd 100644 --- a/libafl_qemu/src/modules/edges.rs +++ b/libafl_qemu/src/modules/edges.rs @@ -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 libafl::{inputs::UsesInput, HasMetadata}; +use libafl::{inputs::UsesInput, observers::VariableLengthMapObserver, HasMetadata}; +use libafl_bolts::Error; use libafl_qemu_sys::GuestAddr; #[cfg(emulation_mode = "systemmode")] use libafl_qemu_sys::GuestPhysAddr; -pub use libafl_targets::{ - edges_map_mut_ptr, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_SIZE_MAX, - MAX_EDGES_FOUND, -}; +use libafl_targets::EDGES_MAP; use serde::{Deserialize, Serialize}; use crate::{ @@ -20,6 +18,18 @@ use crate::{ 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( any(not(feature = "serdeany_autoreg"), miri), allow(clippy::unsafe_derive_deserialize) @@ -100,7 +110,7 @@ pub struct EdgeCoverageFullVariant; pub type StdEdgeCoverageFullModule = EdgeCoverageModule; pub type StdEdgeCoverageFullModuleBuilder = - EdgeCoverageModuleBuilder; + EdgeCoverageModuleBuilder; impl EdgeCoverageVariant for EdgeCoverageFullVariant { fn jit_hitcount(&mut self, emulator_modules: &mut EmulatorModules) @@ -193,7 +203,7 @@ pub struct EdgeCoverageClassicVariant; pub type StdEdgeCoverageClassicModule = EdgeCoverageModule; pub type StdEdgeCoverageClassicModuleBuilder = - EdgeCoverageModuleBuilder; + EdgeCoverageModuleBuilder; impl EdgeCoverageVariant for EdgeCoverageClassicVariant { const DO_SIDE_EFFECTS: bool = false; @@ -293,7 +303,7 @@ pub struct EdgeCoverageChildVariant; pub type StdEdgeCoverageChildModule = EdgeCoverageModule; pub type StdEdgeCoverageChildModuleBuilder = - EdgeCoverageModuleBuilder; + EdgeCoverageModuleBuilder; impl EdgeCoverageVariant for EdgeCoverageChildVariant { const DO_SIDE_EFFECTS: bool = false; @@ -339,13 +349,13 @@ impl Default for StdEdgeCoverageChildModuleBuilder { impl StdEdgeCoverageChildModule { #[must_use] - pub fn builder() -> StdEdgeCoverageClassicModuleBuilder { - EdgeCoverageModuleBuilder::default() + pub fn builder() -> StdEdgeCoverageChildModuleBuilder { + EdgeCoverageModuleBuilder::default().jit(false) } } #[derive(Debug)] -pub struct EdgeCoverageModuleBuilder { +pub struct EdgeCoverageModuleBuilder { variant: V, address_filter: AF, page_filter: PF, @@ -364,8 +374,20 @@ pub struct EdgeCoverageModule { use_jit: bool, } -impl EdgeCoverageModuleBuilder { - pub fn new( +impl EdgeCoverageModuleBuilder { + pub fn build(self) -> Result, Error> { + Ok(EdgeCoverageModule::new( + self.address_filter, + self.page_filter, + self.variant, + self.use_hitcounts, + self.use_jit, + )) + } +} + +impl EdgeCoverageModuleBuilder { + fn new( variant: V, address_filter: AF, page_filter: PF, @@ -381,17 +403,32 @@ impl EdgeCoverageModuleBuilder { } } - pub fn build(self) -> EdgeCoverageModule { - EdgeCoverageModule::new( + #[must_use] + pub fn map_observer(self, map_observer: &mut O) -> EdgeCoverageModuleBuilder + 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::::new( + self.variant, self.address_filter, self.page_filter, - self.variant, self.use_hitcounts, self.use_jit, ) } - pub fn variant(self, variant: V2) -> EdgeCoverageModuleBuilder { + pub fn variant(self, variant: V2) -> EdgeCoverageModuleBuilder { EdgeCoverageModuleBuilder::new( variant, self.address_filter, @@ -401,7 +438,10 @@ impl EdgeCoverageModuleBuilder { ) } - pub fn address_filter(self, address_filter: AF2) -> EdgeCoverageModuleBuilder { + pub fn address_filter( + self, + address_filter: AF2, + ) -> EdgeCoverageModuleBuilder { EdgeCoverageModuleBuilder::new( self.variant, address_filter, @@ -411,7 +451,10 @@ impl EdgeCoverageModuleBuilder { ) } - pub fn page_filter(self, page_filter: PF2) -> EdgeCoverageModuleBuilder { + pub fn page_filter( + self, + page_filter: PF2, + ) -> EdgeCoverageModuleBuilder { EdgeCoverageModuleBuilder::new( self.variant, self.address_filter, @@ -422,7 +465,10 @@ impl EdgeCoverageModuleBuilder { } #[must_use] - pub fn hitcounts(self, use_hitcounts: bool) -> EdgeCoverageModuleBuilder { + pub fn hitcounts( + self, + use_hitcounts: bool, + ) -> EdgeCoverageModuleBuilder { EdgeCoverageModuleBuilder::new( self.variant, self.address_filter, @@ -433,7 +479,7 @@ impl EdgeCoverageModuleBuilder { } #[must_use] - pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder { + pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder { EdgeCoverageModuleBuilder::new( self.variant, self.address_filter, @@ -548,10 +594,15 @@ where S: Unpin + UsesInput + HasMetadata, V: EdgeCoverageVariant, { - if let Some(h) = emulator_modules.get::>() { + if let Some(module) = emulator_modules.get::>() { + 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")] { - if !h.must_instrument(src) && !h.must_instrument(dest) { + if !module.must_instrument(src) && !module.must_instrument(dest) { return None; } } @@ -563,29 +614,30 @@ where .current_cpu() .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; } } } + 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); match meta.map.entry((src, dest)) { Entry::Occupied(e) => { let id = *e.get(); - let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1); 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) } Entry::Vacant(e) => { let id = meta.current_id; e.insert(id); - meta.current_id = (id + 1) & (EDGES_MAP_SIZE_MAX as u64 - 1); 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 #[allow(clippy::unnecessary_cast)] @@ -624,9 +676,9 @@ where S: Unpin + UsesInput + HasMetadata, V: EdgeCoverageVariant, { - if let Some(h) = emulator_modules.get::>() { + if let Some(module) = emulator_modules.get::>() { #[cfg(emulation_mode = "usermode")] - if !h.must_instrument(src) && !h.must_instrument(dest) { + if !module.must_instrument(src) && !module.must_instrument(dest) { return None; } @@ -637,29 +689,31 @@ where .current_cpu() .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; } } - } - let id = hash_me(src as u64) ^ hash_me(dest as u64); - let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1); + let id = hash_me(src as u64) ^ hash_me(dest as u64); - unsafe { - MAX_EDGES_FOUND = nxt; - } + 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) + // GuestAddress is u32 for 32 bit guests + #[allow(clippy::unnecessary_cast)] + Some(id) + } else { + None + } } /// # Safety /// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently. pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) { unsafe { - let ptr = EDGES_MAP_PTR.add(id as usize); + let ptr = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize); *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. pub unsafe extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) { unsafe { - let ptr = EDGES_MAP_PTR.add(id as usize); + let ptr = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize); *ptr = 1; } } @@ -687,10 +741,11 @@ where S: Unpin + UsesInput + HasMetadata, V: EdgeCoverageVariant, { - if let Some(h) = emulator_modules.get::>() { + // first check if we should filter + if let Some(module) = emulator_modules.get::>() { #[cfg(emulation_mode = "usermode")] { - if !h.must_instrument(pc) { + if !module.must_instrument(pc) { return None; } } @@ -701,17 +756,17 @@ where .current_cpu() .and_then(|cpu| cpu.current_paging_id()); - if !h.must_instrument(pc, page_id) { + if !module.must_instrument(pc, page_id) { return None; } } } let id = hash_me(pc as u64); - let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1); 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 @@ -724,8 +779,8 @@ where pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) { unsafe { PREV_LOC.with(|prev_loc| { - let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1); - let entry = EDGES_MAP_PTR.add(x); + let x = ((*prev_loc.get() ^ id) as usize) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX; + let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x); *entry = (*entry).wrapping_add(1); *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) { unsafe { PREV_LOC.with(|prev_loc| { - let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1); - let entry = EDGES_MAP_PTR.add(x); + let x = ((*prev_loc.get() ^ id) as usize) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX; + let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x); *entry = 1; *prev_loc.get() = id.overflowing_shr(1).0; }); diff --git a/libafl_qemu/src/modules/usermode/asan_guest.rs b/libafl_qemu/src/modules/usermode/asan_guest.rs index 5665e93e2c..16d231cfff 100644 --- a/libafl_qemu/src/modules/usermode/asan_guest.rs +++ b/libafl_qemu/src/modules/usermode/asan_guest.rs @@ -146,8 +146,8 @@ impl AsanGuestModule { impl AsanGuestModule { #[must_use] - pub fn default(emu: &Qemu, asan: String) -> Self { - Self::new(emu, asan, StdAddressFilter::default()) + pub fn default(qemu: Qemu, asan: String) -> Self { + Self::new(qemu, asan, StdAddressFilter::default()) } } @@ -156,12 +156,12 @@ where F: AddressFilter, { #[must_use] - pub fn new(emu: &Qemu, asan: String, filter: F) -> Self { - for mapping in emu.mappings() { + pub fn new(qemu: Qemu, asan: String, filter: F) -> Self { + for mapping in qemu.mappings() { println!("mapping: {mapping:#?}"); } - let mappings = emu + let mappings = qemu .mappings() .map(|m| QemuAsanGuestMapping::from(&m)) .collect::>(); diff --git a/libafl_qemu/src/modules/usermode/snapshot.rs b/libafl_qemu/src/modules/usermode/snapshot.rs index ab03f173fb..f18f1dca8e 100644 --- a/libafl_qemu/src/modules/usermode/snapshot.rs +++ b/libafl_qemu/src/modules/usermode/snapshot.rs @@ -34,7 +34,7 @@ use crate::{ pub const SNAPSHOT_PAGE_SIZE: usize = 4096; pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1); -pub type StopExecutionCallback = Box; +pub type StopExecutionCallback = Box; #[derive(Clone, Debug)] pub struct SnapshotPageInfo { @@ -510,7 +510,7 @@ impl SnapshotModule { if self.mmap_limit != 0 && total_size > self.mmap_limit { let mut cb = self.stop_execution.take().unwrap(); let qemu = Qemu::get().unwrap(); - cb(self, &qemu); + cb(self, qemu); self.stop_execution = Some(cb); } } diff --git a/libafl_qemu/src/qemu/hooks.rs b/libafl_qemu/src/qemu/hooks.rs index fe55e75a52..0515ebbcc3 100644 --- a/libafl_qemu/src/qemu/hooks.rs +++ b/libafl_qemu/src/qemu/hooks.rs @@ -712,6 +712,8 @@ create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId); // Crash hook wrappers #[cfg(emulation_mode = "usermode")] +pub type CrashHookFn = fn(&mut EmulatorModules, i32); +#[cfg(emulation_mode = "usermode")] pub type CrashHookClosure = Box, i32)>; /// The thin wrapper around QEMU hooks. @@ -1035,7 +1037,7 @@ impl QemuHooks { #[allow(clippy::unused_self)] pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) { unsafe { - libafl_dump_core_hook = callback; + libafl_dump_core_hook = Some(callback); } } } diff --git a/libafl_qemu/src/qemu/mod.rs b/libafl_qemu/src/qemu/mod.rs index 4205c461aa..1e450bdc4b 100644 --- a/libafl_qemu/src/qemu/mod.rs +++ b/libafl_qemu/src/qemu/mod.rs @@ -155,10 +155,10 @@ static mut GDB_COMMANDS: Vec> = Vec::new(); unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool { unsafe { - let closure = &mut *(data as *mut Box FnMut(&Qemu, &'r str) -> bool>); + let closure = &mut *(data as *mut Box FnMut(Qemu, &'r str) -> bool>); let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len)); let qemu = Qemu::get_unchecked(); - closure(&qemu, cmd) + closure(qemu, cmd) } } diff --git a/libafl_qemu/src/qemu/usermode.rs b/libafl_qemu/src/qemu/usermode.rs index 9f1d1dea42..c6e5b38b3d 100644 --- a/libafl_qemu/src/qemu/usermode.rs +++ b/libafl_qemu/src/qemu/usermode.rs @@ -1,6 +1,6 @@ use std::{ - intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts, - str::from_utf8_unchecked, + intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts_mut, + str::from_utf8_unchecked_mut, }; use libafl_qemu_sys::{ @@ -9,7 +9,7 @@ use libafl_qemu_sys::{ pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot, MapInfo, MmapPerms, VerifyAccess, }; -use libc::{c_char, c_int, strlen}; +use libc::{c_char, c_int, c_uchar, strlen}; #[cfg(feature = "python")] use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python}; @@ -139,8 +139,8 @@ impl Qemu { #[must_use] pub fn binary_path<'a>(&self) -> &'a str { unsafe { - from_utf8_unchecked(from_raw_parts( - exec_path, + from_utf8_unchecked_mut(from_raw_parts_mut( + exec_path as *mut c_uchar, strlen(exec_path as *const c_char), )) } diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 7df39cf3aa..3dcd3fcdad 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -39,11 +39,8 @@ use libafl_bolts::{ #[cfg(not(any(feature = "mips", feature = "hexagon")))] use libafl_qemu::modules::CmpLogModule; pub use libafl_qemu::qemu::Qemu; -use libafl_qemu::{ - modules::{edges, edges::StdEdgeCoverageModule}, - Emulator, QemuExecutor, -}; -use libafl_targets::{edges_map_mut_ptr, CmpLogObserver}; +use libafl_qemu::{modules::edges::StdEdgeCoverageModule, Emulator, QemuExecutor}; +use libafl_targets::{edges_map_mut_ptr, CmpLogObserver, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND}; use typed_builder::TypedBuilder; use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS}; @@ -160,14 +157,11 @@ where let time_observer = time_observer.clone(); // Create an observation channel using the coverage map - let edges_observer = unsafe { + let mut edges_observer = unsafe { HitcountsMapObserver::new(VariableMapObserver::from_mut_slice( "edges", - OwnedMutSlice::from_raw_parts_mut( - edges_map_mut_ptr(), - edges::EDGES_MAP_SIZE_IN_USE, - ), - addr_of_mut!(edges::MAX_EDGES_FOUND), + OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE), + addr_of_mut!(MAX_EDGES_FOUND), )) .track_indices() }; @@ -223,13 +217,19 @@ where #[cfg(not(any(feature = "mips", feature = "hexagon")))] { tuple_list!( - StdEdgeCoverageModule::builder().build(), + StdEdgeCoverageModule::builder() + .map_observer(edges_observer.as_mut()) + .build() + .unwrap(), CmpLogModule::default(), ) } #[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 { - 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<_, _, _, _, _>, _state: &mut _, diff --git a/libafl_targets/build.rs b/libafl_targets/build.rs index 674851d41e..3f92a0004c 100644 --- a/libafl_targets/build.rs +++ b/libafl_targets/build.rs @@ -26,36 +26,47 @@ fn main() { let dest_path = Path::new(&out_dir).join("constants.rs"); 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) - .expect("Could not parse LIBAFL_EDGES_MAP_SIZE_MAX"); - let edges_map_size_in_use: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE") + .expect("Could not parse LIBAFL_EDGES_MAP_ALLOCATED_SIZE"); + + 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) - .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") .map_or(Ok(SIXTY_FIVE_KB), str::parse) .expect("Could not parse LIBAFL_CMP_MAP_SIZE"); + let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W") .map_or(Ok(SIXTY_FIVE_KB), str::parse) .expect("Could not parse LIBAFL_CMPLOG_MAP_W"); + let cmplog_map_h: usize = option_env!("LIBAFL_CMPLOG_MAP_H") .map_or(Ok(32), str::parse) .expect("Could not parse LIBAFL_CMPLOG_MAP_H"); + let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE") .map_or(Ok(SIXTY_FIVE_KB), str::parse) .expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE"); + let ddg_map_size: usize = option_env!("LIBAFL_DDG_MAP_SIZE") .map_or(Ok(SIXTY_FIVE_KB), str::parse) .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!( constants_file, "// These constants are autogenerated by build.rs /// 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 - 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 pub const CMP_MAP_SIZE: usize = {cmp_map_size}; /// The width of the `CmpLog` map @@ -70,7 +81,10 @@ fn main() { ) .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_CMPLOG_MAP_W"); println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H"); @@ -160,8 +174,8 @@ fn main() { cc::Build::new() .file(src_dir.join("coverage.c")) .define( - "EDGES_MAP_SIZE_MAX", - Some(&*format!("{edges_map_size_max}")), + "EDGES_MAP_ALLOCATED_SIZE", + Some(&*format!("{edges_map_allocated_size}")), ) .define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}"))) .define("DDG_MAP_SIZE", Some(&*format!("{ddg_map_size}"))) diff --git a/libafl_targets/src/coverage.c b/libafl_targets/src/coverage.c index 727d5e1567..2ddba3963e 100644 --- a/libafl_targets/src/coverage.c +++ b/libafl_targets/src/coverage.c @@ -8,7 +8,7 @@ typedef uint32_t prev_loc_t; /* Maximum K for top-K context sensitivity */ #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; extern uint8_t __ddg_area_ptr_local[DDG_MAP_SIZE]; diff --git a/libafl_targets/src/coverage.rs b/libafl_targets/src/coverage.rs index 464a684cea..3732e5b4b1 100644 --- a/libafl_targets/src/coverage.rs +++ b/libafl_targets/src/coverage.rs @@ -20,12 +20,12 @@ use core::ptr::addr_of_mut; #[cfg(any(target_os = "linux", target_vendor = "apple"))] 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. #[no_mangle] #[allow(non_upper_case_globals)] -pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_SIZE_MAX] = [0; EDGES_MAP_SIZE_MAX]; +pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_ALLOCATED_SIZE] = [0; EDGES_MAP_ALLOCATED_SIZE]; pub use __afl_area_ptr_local as EDGES_MAP; /// The map for data dependency @@ -85,9 +85,9 @@ pub fn autotokens() -> Result { /// The actual size we use for the map of edges. /// This is used for forkserver backend -#[no_mangle] #[allow(non_upper_case_globals)] -pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE; +#[no_mangle] +pub static mut __afl_map_size: usize = EDGES_MAP_DEFAULT_SIZE; #[cfg(any( feature = "sancov_pcguard_edges", @@ -127,11 +127,11 @@ pub unsafe fn edges_map_mut_slice<'a>() -> OwnedMutSlice<'a, u8> { /// /// ```rust,ignore /// 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"))] /// 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 { #[cfg(feature = "pointer_maps")] { - EDGES_MAP_SIZE_MAX // the upper bound + EDGES_MAP_ALLOCATED_SIZE // the upper bound } #[cfg(not(feature = "pointer_maps"))] { diff --git a/libafl_targets/src/sancov_pcguard.rs b/libafl_targets/src/sancov_pcguard.rs index 6e6f2f1ff5..0cb0b73681 100644 --- a/libafl_targets/src/sancov_pcguard.rs +++ b/libafl_targets/src/sancov_pcguard.rs @@ -27,9 +27,9 @@ use crate::coverage::EDGES_MAP; use crate::coverage::MAX_EDGES_FOUND; #[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))] #[allow(unused)] -use crate::EDGES_MAP_SIZE_IN_USE; +use crate::EDGES_MAP_DEFAULT_SIZE; #[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(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; reduced = prev_array_8.reduce_xor() as usize; } - reduced %= EDGES_MAP_SIZE_IN_USE; + reduced %= EDGES_MAP_DEFAULT_SIZE; 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"))] { 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")] { 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")] @@ -291,13 +291,13 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32 #[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"))] { let edges_map_len = (*addr_of!(EDGES_MAP)).len(); MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1); - assert!((MAX_EDGES_FOUND <= edges_map_len), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({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."); } } } diff --git a/utils/libafl_fmt/src/main.rs b/utils/libafl_fmt/src/main.rs index 7a6831fa46..1b2913f06b 100644 --- a/utils/libafl_fmt/src/main.rs +++ b/utils/libafl_fmt/src/main.rs @@ -95,12 +95,15 @@ fn is_workspace_toml(path: &Path) -> bool { 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 - 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()) { - println!("[*] Skipping {}...", path.as_path().display()); + if is_workspace_toml(cargo_file_path.as_path()) { + println!("[*] Skipping {}...", cargo_file_path.as_path().display()); return Ok(()); } @@ -112,14 +115,18 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu .arg("+nightly") .arg("fmt") .arg("--manifest-path") - .arg(path.as_path()); + .arg(cargo_file_path.as_path()); if is_check { fmt_command.arg("--check"); } if verbose { - println!("[*] {} {}...", task_str, path.as_path().display()); + println!( + "[*] {} {}...", + task_str, + cargo_file_path.as_path().display() + ); } 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( ErrorKind::Other, 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( - path: PathBuf, + c_file_path: PathBuf, clang: String, is_check: bool, verbose: bool, @@ -151,16 +158,16 @@ async fn run_clang_fmt( .arg("-i") .arg("--style") .arg("file") - .arg(path.as_path()); + .arg(c_file_path.as_path()); if is_check { fmt_command.arg("-Werror").arg("--dry-run"); } - fmt_command.arg(path.as_path()); + fmt_command.arg(c_file_path.as_path()); if verbose { - println!("[*] {} {}...", task_str, path.as_path().display()); + println!("[*] {} {}...", task_str, c_file_path.as_path().display()); } let res = fmt_command.output().await?;