Change fuzzbench_qemu fuzzer (#2520)
* change fuzzbench_qemu * real test * fix qemu crash hook * update bindings * fix fork executor, reduce trait bound overhead * make EdgeModule depend on observer to get ptrs. * do not make EdgeCoverageModule::new public * map observer as builder call * adapt examples with new edge coverage module builder. * TMP: everyone is a variable length map observer * reuse profile path script * fix absolute paths * remove some dependencies to make pipeline faster * compile-time builder initialization check --------- Co-authored-by: Romain Malmain <romain.malmain@pm.me>
This commit is contained in:
parent
7344fdf059
commit
c12c6f31e2
25
.github/workflows/build_and_test.yml
vendored
25
.github/workflows/build_and_test.yml
vendored
@ -66,28 +66,6 @@ jobs:
|
|||||||
- name: Test libafl_targets no_std
|
- name: Test libafl_targets no_std
|
||||||
run: cd libafl_targets && cargo test --no-default-features
|
run: cd libafl_targets && cargo test --no-default-features
|
||||||
|
|
||||||
llvm-tester:
|
|
||||||
runs-on: ubuntu-24.04
|
|
||||||
continue-on-error: true
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
llvm-version: [ "16", "17" ] # Add 18 when KyleMayes/install-llvm-action enables it
|
|
||||||
steps:
|
|
||||||
- name: Remove Dotnet & Haskell
|
|
||||||
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
|
|
||||||
- name: Install curl
|
|
||||||
run: sudo apt-get install clang
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
|
||||||
- name: Install LLVM and Clang
|
|
||||||
uses: KyleMayes/install-llvm-action@v2
|
|
||||||
with:
|
|
||||||
version: "${{matrix.llvm-version}}"
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: Swatinem/rust-cache@v2
|
|
||||||
with: { shared-key: "llvm-tester" }
|
|
||||||
- name: Build and test with llvm-${{ matrix.llvm-version }}
|
|
||||||
run: pwd && ls & cd libafl_cc && cargo build --release
|
|
||||||
|
|
||||||
ubuntu-doc-build:
|
ubuntu-doc-build:
|
||||||
runs-on: ubuntu-24.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
@ -246,9 +224,7 @@ jobs:
|
|||||||
|
|
||||||
fuzzers:
|
fuzzers:
|
||||||
needs:
|
needs:
|
||||||
- ubuntu
|
|
||||||
- fuzzers-preflight
|
- fuzzers-preflight
|
||||||
- common
|
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
@ -355,7 +331,6 @@ jobs:
|
|||||||
|
|
||||||
fuzzers-qemu:
|
fuzzers-qemu:
|
||||||
needs:
|
needs:
|
||||||
- common
|
|
||||||
- changes
|
- changes
|
||||||
if: ${{ needs.changes.outputs.qemu == 'true' }}
|
if: ${{ needs.changes.outputs.qemu == 'true' }}
|
||||||
strategy:
|
strategy:
|
||||||
|
@ -20,7 +20,7 @@ Try running the fuzzer with the `introspection` feature of the `libafl`. This wi
|
|||||||
```
|
```
|
||||||
let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len());
|
let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len());
|
||||||
```
|
```
|
||||||
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_SIZE_IN_USE`.
|
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_DEFAULT_SIZE`.
|
||||||
|
|
||||||
## Q. I still have problems with my fuzzer.
|
## Q. I still have problems with my fuzzer.
|
||||||
Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord.
|
Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord.
|
||||||
|
@ -57,7 +57,7 @@ On your fuzzer side, you can allocate a shared memory region and make the `EDGES
|
|||||||
```rust,ignore
|
```rust,ignore
|
||||||
let mut shmem;
|
let mut shmem;
|
||||||
unsafe{
|
unsafe{
|
||||||
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
|
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
|
||||||
}
|
}
|
||||||
let shmem_buf = shmem.as_slice_mut();
|
let shmem_buf = shmem.as_slice_mut();
|
||||||
unsafe{
|
unsafe{
|
||||||
|
@ -169,7 +169,7 @@ from libafl_target's `EDGES_MAP`.
|
|||||||
In the future, instead of using:
|
In the future, instead of using:
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_SIZE_IN_USE] };
|
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_DEFAULT_SIZE] };
|
||||||
let edges_observer = StdMapObserver::new("edges", edges);
|
let edges_observer = StdMapObserver::new("edges", edges);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
|
|||||||
"x86_64",
|
"x86_64",
|
||||||
"usermode",
|
"usermode",
|
||||||
] }
|
] }
|
||||||
|
libafl_targets = { path = "../../../libafl_targets" }
|
||||||
|
|
||||||
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
||||||
clap = { version = "4.5.18", features = ["default"] }
|
clap = { version = "4.5.18", features = ["default"] }
|
||||||
|
@ -1,11 +1,28 @@
|
|||||||
|
env_scripts = ['''
|
||||||
|
#!@duckscript
|
||||||
|
profile = get_env PROFILE
|
||||||
|
|
||||||
|
if eq ${profile} "dev"
|
||||||
|
set_env PROFILE_DIR debug
|
||||||
|
else
|
||||||
|
set_env PROFILE_DIR ${profile}
|
||||||
|
end
|
||||||
|
''', '''
|
||||||
|
#!@duckscript
|
||||||
|
runs_on_ci = get_env RUN_ON_CI
|
||||||
|
|
||||||
|
if ${runs_on_ci}
|
||||||
|
cargo_target_dir = get_env CARGO_MAKE_CRATE_TARGET_DIRECTORY
|
||||||
|
set_env TARGET_DIR ${cargo_target_dir}
|
||||||
|
end
|
||||||
|
''']
|
||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
[env]
|
[env]
|
||||||
FUZZER_NAME = 'libpng_harness'
|
FUZZER_NAME = 'harness'
|
||||||
PROJECT_DIR = { script = ["pwd"] }
|
PROJECT_DIR = { script = ["pwd"] }
|
||||||
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
|
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
|
||||||
PROFILE_DIR = { value = "release", condition = { env_not_set = [
|
TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"
|
||||||
"PROFILE_DIR",
|
|
||||||
] } }
|
|
||||||
|
|
||||||
[tasks.unsupported]
|
[tasks.unsupported]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
@ -13,20 +30,6 @@ script = '''
|
|||||||
echo "Qemu fuzzer not supported on windows"
|
echo "Qemu fuzzer not supported on windows"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# libpng
|
|
||||||
[tasks.libpng]
|
|
||||||
linux_alias = "libpng_unix"
|
|
||||||
mac_alias = "libpng_unix"
|
|
||||||
windows_alias = "unsupported"
|
|
||||||
|
|
||||||
[tasks.libpng_unix]
|
|
||||||
condition = { files_not_exist = ["./libpng-1.6.37"] }
|
|
||||||
script_runner = "@shell"
|
|
||||||
script = '''
|
|
||||||
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
|
|
||||||
tar -xvf v1.6.37.tar.gz
|
|
||||||
'''
|
|
||||||
|
|
||||||
# fuzzer
|
# fuzzer
|
||||||
[tasks.fuzzer]
|
[tasks.fuzzer]
|
||||||
linux_alias = "fuzzer_unix"
|
linux_alias = "fuzzer_unix"
|
||||||
@ -46,20 +49,13 @@ windows_alias = "unsupported"
|
|||||||
[tasks.harness_unix]
|
[tasks.harness_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
|
|
||||||
cd "${PROJECT_DIR}"
|
|
||||||
make -C libpng-1.6.37
|
|
||||||
cc -c "${PROJECT_DIR}/libfuzzer_main.c"
|
cc -c "${PROJECT_DIR}/libfuzzer_main.c"
|
||||||
# Build the libpng harness
|
cc \
|
||||||
c++ \
|
./fuzz.c \
|
||||||
../../inprocess/libfuzzer_libpng/harness.cc \
|
|
||||||
./libpng-1.6.37/.libs/libpng16.a \
|
|
||||||
./libfuzzer_main.o \
|
./libfuzzer_main.o \
|
||||||
-I./libpng-1.6.37/ \
|
|
||||||
-o ${FUZZER_NAME} \
|
-o ${FUZZER_NAME} \
|
||||||
-lm -lz
|
-lm -lz
|
||||||
'''
|
'''
|
||||||
dependencies = ["libpng"]
|
|
||||||
|
|
||||||
# Run the fuzzer
|
# Run the fuzzer
|
||||||
[tasks.run]
|
[tasks.run]
|
||||||
@ -72,16 +68,16 @@ command = "cargo"
|
|||||||
args = [
|
args = [
|
||||||
"run",
|
"run",
|
||||||
"--profile",
|
"--profile",
|
||||||
"${PROFILE_DIR}",
|
"${PROFILE}",
|
||||||
"./${FUZZER_NAME}",
|
"./${FUZZER_NAME}",
|
||||||
"--",
|
"--",
|
||||||
"--libafl-in",
|
"--libafl-in",
|
||||||
"../libfuzzer_libpng/corpus",
|
"./corpus",
|
||||||
"--libafl-out",
|
"--libafl-out",
|
||||||
"./out",
|
"./out",
|
||||||
"./${FUZZER_NAME}",
|
"./${FUZZER_NAME}",
|
||||||
]
|
]
|
||||||
dependencies = ["harness", "fuzzer"]
|
dependencies = ["harness"]
|
||||||
|
|
||||||
# Run the fuzzer
|
# Run the fuzzer
|
||||||
[tasks.test]
|
[tasks.test]
|
||||||
@ -93,7 +89,13 @@ windows_alias = "unsupported"
|
|||||||
[tasks.test_unix]
|
[tasks.test_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
echo "This test is skipped. QEMU-based fuzzer doesn't work on Github runners"
|
timeout 15s ${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_fork_qemu ${PROJECT_DIR}/harness -- --libafl-in ${PROJECT_DIR}/../../inprocess/libfuzzer_libpng/corpus --libafl-out ${PROJECT_DIR}/out ${PROJECT_DIR}/harness | tee fuzz_stdout.log
|
||||||
|
if grep -qa "objectives: 1" fuzz_stdout.log; then
|
||||||
|
echo "Fuzzer is working"
|
||||||
|
else
|
||||||
|
echo "Fuzzer does not generate any testcases or any crashes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
'''
|
'''
|
||||||
dependencies = ["harness", "fuzzer"]
|
dependencies = ["harness", "fuzzer"]
|
||||||
|
|
||||||
@ -108,7 +110,6 @@ windows_alias = "unsupported"
|
|||||||
clear = true
|
clear = true
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
rm -f ./${FUZZER_NAME} libfuzzer_main.o
|
rm -f ./${FUZZER_NAME}
|
||||||
make -C libpng-1.6.37 clean
|
|
||||||
cargo clean
|
cargo clean
|
||||||
'''
|
'''
|
||||||
|
19
fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c
Normal file
19
fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
|
||||||
|
char buf[8] = {'a', 'b', 'c', 'd'};
|
||||||
|
|
||||||
|
if (memcmp(Data, buf, 4) == 0) { abort(); }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
char buf [10] = {0};
|
||||||
|
LLVMFuzzerTestOneInput(buf, 10);
|
||||||
|
|
||||||
|
}*/
|
@ -39,7 +39,7 @@ use libafl::{
|
|||||||
};
|
};
|
||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
current_time,
|
current_time,
|
||||||
os::{dup2, unix_signals::Signal},
|
os::dup2,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge},
|
||||||
@ -50,11 +50,12 @@ use libafl_qemu::{
|
|||||||
filter_qemu_args,
|
filter_qemu_args,
|
||||||
modules::{
|
modules::{
|
||||||
cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver},
|
cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver},
|
||||||
edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE},
|
edges::StdEdgeCoverageChildModule,
|
||||||
},
|
},
|
||||||
Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor,
|
Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor,
|
||||||
QemuShutdownCause, Regs,
|
QemuShutdownCause, Regs,
|
||||||
};
|
};
|
||||||
|
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nix::unistd::dup;
|
use nix::unistd::dup;
|
||||||
|
|
||||||
@ -148,10 +149,26 @@ fn fuzz(
|
|||||||
env::remove_var("LD_LIBRARY_PATH");
|
env::remove_var("LD_LIBRARY_PATH");
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let env: Vec<(String, String)> = env::vars().collect();
|
|
||||||
|
let mut shmem_provider = StdShMemProvider::new()?;
|
||||||
|
|
||||||
|
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
|
||||||
|
let edges = edges_shmem.as_slice_mut();
|
||||||
|
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let mut edges_observer = unsafe {
|
||||||
|
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_DEFAULT_SIZE>::from_mut_ptr(
|
||||||
|
"edges",
|
||||||
|
edges.as_mut_ptr(),
|
||||||
|
))
|
||||||
|
.track_indices()
|
||||||
|
};
|
||||||
|
|
||||||
let emulator_modules = tuple_list!(
|
let emulator_modules = tuple_list!(
|
||||||
StdEdgeCoverageChildModule::builder().build(),
|
StdEdgeCoverageChildModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()?,
|
||||||
CmpLogChildModule::default(),
|
CmpLogChildModule::default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -218,12 +235,6 @@ fn fuzz(
|
|||||||
writeln!(log.borrow_mut(), "{:?} {s}", current_time()).unwrap();
|
writeln!(log.borrow_mut(), "{:?} {s}", current_time()).unwrap();
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut shmem_provider = StdShMemProvider::new()?;
|
|
||||||
|
|
||||||
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
|
|
||||||
let edges = edges_shmem.as_slice_mut();
|
|
||||||
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
|
|
||||||
|
|
||||||
let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap();
|
let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap();
|
||||||
let cmplog = cmp_shmem.as_slice_mut();
|
let cmplog = cmp_shmem.as_slice_mut();
|
||||||
|
|
||||||
@ -247,15 +258,6 @@ fn fuzz(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
|
||||||
let edges_observer = unsafe {
|
|
||||||
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr(
|
|
||||||
"edges",
|
|
||||||
edges.as_mut_ptr(),
|
|
||||||
))
|
|
||||||
.track_indices()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let time_observer = TimeObserver::new("time");
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
@ -321,7 +323,7 @@ fn fuzz(
|
|||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
// The wrapped harness function, calling out to the LLVM-style harness
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
let mut harness = |input: &BytesInput| {
|
let mut harness = |emulator: &mut Emulator<_, _, _, _, _>, input: &BytesInput| {
|
||||||
let target = input.target_bytes();
|
let target = input.target_bytes();
|
||||||
let mut buf = target.as_slice();
|
let mut buf = target.as_slice();
|
||||||
let mut len = buf.len();
|
let mut len = buf.len();
|
||||||
@ -339,16 +341,17 @@ fn fuzz(
|
|||||||
qemu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
qemu.write_reg(Regs::Rsp, stack_ptr).unwrap();
|
||||||
|
|
||||||
match qemu.run() {
|
match qemu.run() {
|
||||||
Ok(QemuExitReason::Breakpoint(_)) => {}
|
Ok(QemuExitReason::Breakpoint(_)) => ExitKind::Ok,
|
||||||
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => {
|
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => {
|
||||||
process::exit(0)
|
signal.handle();
|
||||||
|
panic!("Unexpected signal: {signal:?}");
|
||||||
|
}
|
||||||
|
Err(QemuExitError::UnexpectedExit) => ExitKind::Crash,
|
||||||
|
_ => {
|
||||||
|
panic!("Unexpected QEMU exit.")
|
||||||
}
|
}
|
||||||
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
|
|
||||||
_ => panic!("Unexpected QEMU exit."),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ExitKind::Ok
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let executor = QemuForkExecutor::new(
|
let executor = QemuForkExecutor::new(
|
||||||
@ -391,8 +394,8 @@ fn fuzz(
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
let null_fd = file_null.as_raw_fd();
|
let null_fd = file_null.as_raw_fd();
|
||||||
dup2(null_fd, io::stdout().as_raw_fd())?;
|
// dup2(null_fd, io::stdout().as_raw_fd())?;
|
||||||
dup2(null_fd, io::stderr().as_raw_fd())?;
|
// dup2(null_fd, io::stderr().as_raw_fd())?;
|
||||||
}
|
}
|
||||||
// reopen file to make sure we're at the end
|
// reopen file to make sure we're at the end
|
||||||
log.replace(
|
log.replace(
|
||||||
|
@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
|
|||||||
"x86_64",
|
"x86_64",
|
||||||
"usermode",
|
"usermode",
|
||||||
] }
|
] }
|
||||||
|
libafl_targets = { path = "../../../libafl_targets", version = "0.13.2" }
|
||||||
|
|
||||||
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
||||||
clap = { version = "4.5.18", features = ["default"] }
|
clap = { version = "4.5.18", features = ["default"] }
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
# Variables
|
# Variables
|
||||||
[env]
|
[env]
|
||||||
FUZZER_NAME = 'libpng_harness'
|
FUZZER_NAME = 'harness'
|
||||||
PROJECT_DIR = { script = ["pwd"] }
|
PROJECT_DIR = { script = ["pwd"] }
|
||||||
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
|
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
|
||||||
PROFILE_DIR = { value = "release", condition = { env_not_set = [
|
PROFILE_DIR = { value = "release", condition = { env_not_set = [
|
||||||
"PROFILE_DIR",
|
"PROFILE_DIR",
|
||||||
] } }
|
] } }
|
||||||
|
TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"
|
||||||
|
|
||||||
[tasks.unsupported]
|
[tasks.unsupported]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
@ -13,20 +14,6 @@ script = '''
|
|||||||
echo "Qemu fuzzer not supported on windows"
|
echo "Qemu fuzzer not supported on windows"
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# libpng
|
|
||||||
[tasks.libpng]
|
|
||||||
linux_alias = "libpng_unix"
|
|
||||||
mac_alias = "libpng_unix"
|
|
||||||
windows_alias = "unsupported"
|
|
||||||
|
|
||||||
[tasks.libpng_unix]
|
|
||||||
condition = { files_not_exist = ["./libpng-1.6.37"] }
|
|
||||||
script_runner = "@shell"
|
|
||||||
script = '''
|
|
||||||
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
|
|
||||||
tar -xvf v1.6.37.tar.gz
|
|
||||||
'''
|
|
||||||
|
|
||||||
# fuzzer
|
# fuzzer
|
||||||
[tasks.fuzzer]
|
[tasks.fuzzer]
|
||||||
linux_alias = "fuzzer_unix"
|
linux_alias = "fuzzer_unix"
|
||||||
@ -46,20 +33,13 @@ windows_alias = "unsupported"
|
|||||||
[tasks.harness_unix]
|
[tasks.harness_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
|
|
||||||
cd "${PROJECT_DIR}"
|
|
||||||
make -C libpng-1.6.37
|
|
||||||
cc -c "${PROJECT_DIR}/libfuzzer_main.c"
|
cc -c "${PROJECT_DIR}/libfuzzer_main.c"
|
||||||
# Build the libpng harness
|
cc \
|
||||||
c++ \
|
./fuzz.c \
|
||||||
../../inprocess/libfuzzer_libpng/harness.cc \
|
|
||||||
./libpng-1.6.37/.libs/libpng16.a \
|
|
||||||
./libfuzzer_main.o \
|
./libfuzzer_main.o \
|
||||||
-I./libpng-1.6.37/ \
|
|
||||||
-o ${FUZZER_NAME} \
|
-o ${FUZZER_NAME} \
|
||||||
-lm -lz
|
-lm -lz
|
||||||
'''
|
'''
|
||||||
dependencies = ["libpng"]
|
|
||||||
|
|
||||||
# Run the fuzzer
|
# Run the fuzzer
|
||||||
[tasks.run]
|
[tasks.run]
|
||||||
@ -81,7 +61,7 @@ args = [
|
|||||||
"./out",
|
"./out",
|
||||||
"./${FUZZER_NAME}",
|
"./${FUZZER_NAME}",
|
||||||
]
|
]
|
||||||
dependencies = ["harness", "fuzzer"]
|
dependencies = ["harness"]
|
||||||
|
|
||||||
# Run the fuzzer
|
# Run the fuzzer
|
||||||
[tasks.test]
|
[tasks.test]
|
||||||
@ -93,7 +73,13 @@ windows_alias = "unsupported"
|
|||||||
[tasks.test_unix]
|
[tasks.test_unix]
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
echo "This test is skipped. QEMU-based fuzzer doesn't work on Github runners"
|
timeout 15s ${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_qemu ${PROJECT_DIR}/harness -- --libafl-in ${PROJECT_DIR}/../../inprocess/libfuzzer_libpng/corpus --libafl-out ${PROJECT_DIR}/out ${PROJECT_DIR}/harness | tee fuzz_stdout.log
|
||||||
|
if grep -qa "objectives: 1" fuzz_stdout.log; then
|
||||||
|
echo "Fuzzer is working"
|
||||||
|
else
|
||||||
|
echo "Fuzzer does not generate any testcases or any crashes"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
'''
|
'''
|
||||||
dependencies = ["harness", "fuzzer"]
|
dependencies = ["harness", "fuzzer"]
|
||||||
|
|
||||||
@ -108,7 +94,6 @@ windows_alias = "unsupported"
|
|||||||
clear = true
|
clear = true
|
||||||
script_runner = "@shell"
|
script_runner = "@shell"
|
||||||
script = '''
|
script = '''
|
||||||
rm -f ./${FUZZER_NAME} libfuzzer_main.o
|
rm -f ./${FUZZER_NAME}
|
||||||
make -C libpng-1.6.37 clean
|
|
||||||
cargo clean
|
cargo clean
|
||||||
'''
|
'''
|
||||||
|
19
fuzzers/binary_only/fuzzbench_qemu/fuzz.c
Normal file
19
fuzzers/binary_only/fuzzbench_qemu/fuzz.c
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||||
|
if (Size >= 8 && *(uint32_t *)Data == 0xaabbccdd) { abort(); }
|
||||||
|
char buf[8] = {'a', 'b', 'c', 'd'};
|
||||||
|
|
||||||
|
if (memcmp(Data, buf, 4) == 0) { abort(); }
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main() {
|
||||||
|
|
||||||
|
char buf [10] = {0};
|
||||||
|
LLVMFuzzerTestOneInput(buf, 10);
|
||||||
|
|
||||||
|
}*/
|
@ -38,7 +38,7 @@ use libafl::{
|
|||||||
};
|
};
|
||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
current_time,
|
current_time,
|
||||||
os::{dup2, unix_signals::Signal},
|
os::dup2,
|
||||||
ownedref::OwnedMutSlice,
|
ownedref::OwnedMutSlice,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
@ -50,9 +50,7 @@ use libafl_qemu::{
|
|||||||
filter_qemu_args,
|
filter_qemu_args,
|
||||||
// asan::{init_with_asan, QemuAsanHelper},
|
// asan::{init_with_asan, QemuAsanHelper},
|
||||||
modules::cmplog::{CmpLogModule, CmpLogObserver},
|
modules::cmplog::{CmpLogModule, CmpLogObserver},
|
||||||
modules::edges::{
|
modules::edges::StdEdgeCoverageModule,
|
||||||
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
|
|
||||||
},
|
|
||||||
Emulator,
|
Emulator,
|
||||||
GuestReg,
|
GuestReg,
|
||||||
//snapshot::QemuSnapshotHelper,
|
//snapshot::QemuSnapshotHelper,
|
||||||
@ -64,6 +62,7 @@ use libafl_qemu::{
|
|||||||
QemuShutdownCause,
|
QemuShutdownCause,
|
||||||
Regs,
|
Regs,
|
||||||
};
|
};
|
||||||
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_ALLOCATED_SIZE, MAX_EDGES_FOUND};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nix::unistd::dup;
|
use nix::unistd::dup;
|
||||||
|
|
||||||
@ -253,10 +252,10 @@ fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = unsafe {
|
let mut edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
))
|
))
|
||||||
.track_indices()
|
.track_indices()
|
||||||
@ -347,9 +346,9 @@ fn fuzz(
|
|||||||
|
|
||||||
match qemu.run() {
|
match qemu.run() {
|
||||||
Ok(QemuExitReason::Breakpoint(_)) => {}
|
Ok(QemuExitReason::Breakpoint(_)) => {}
|
||||||
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(
|
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => {
|
||||||
Signal::SigInterrupt,
|
signal.handle();
|
||||||
))) => process::exit(0),
|
}
|
||||||
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
|
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
|
||||||
_ => panic!("Unexpected QEMU exit."),
|
_ => panic!("Unexpected QEMU exit."),
|
||||||
}
|
}
|
||||||
@ -359,7 +358,10 @@ fn fuzz(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let modules = tuple_list!(
|
let modules = tuple_list!(
|
||||||
StdEdgeCoverageModule::builder().build(),
|
StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
// QemuAsanHelper::default(asan),
|
// QemuAsanHelper::default(asan),
|
||||||
//QemuSnapshotHelper::new()
|
//QemuSnapshotHelper::new()
|
||||||
|
@ -34,5 +34,6 @@ clap = { version = "4.5.18", features = ["derive", "string"] }
|
|||||||
libafl = { path = "../../../libafl" }
|
libafl = { path = "../../../libafl" }
|
||||||
libafl_bolts = { path = "../../../libafl_bolts" }
|
libafl_bolts = { path = "../../../libafl_bolts" }
|
||||||
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
|
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
|
||||||
|
libafl_targets = { path = "../../../libafl_targets" }
|
||||||
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
||||||
rangemap = { version = "1.5.1" }
|
rangemap = { version = "1.5.1" }
|
||||||
|
@ -27,11 +27,11 @@ use libafl_bolts::{
|
|||||||
AsSlice, AsSliceMut,
|
AsSlice, AsSliceMut,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
elf::EasyElf,
|
elf::EasyElf, modules::edges::StdEdgeCoverageChildModule, ArchExtras, CallingConvention,
|
||||||
modules::edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE},
|
Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError, QemuExitReason,
|
||||||
ArchExtras, CallingConvention, Emulator, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitError,
|
QemuForkExecutor, QemuShutdownCause, Regs,
|
||||||
QemuExitReason, QemuForkExecutor, QemuShutdownCause, Regs,
|
|
||||||
};
|
};
|
||||||
|
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Version;
|
pub struct Version;
|
||||||
@ -155,12 +155,12 @@ pub fn fuzz() -> Result<(), Error> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
|
let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
|
||||||
let edges = edges_shmem.as_slice_mut();
|
let edges = edges_shmem.as_slice_mut();
|
||||||
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
|
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };
|
||||||
|
|
||||||
let edges_observer = unsafe {
|
let mut edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr(
|
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_DEFAULT_SIZE>::from_mut_ptr(
|
||||||
"edges",
|
"edges",
|
||||||
edges.as_mut_ptr(),
|
edges.as_mut_ptr(),
|
||||||
))
|
))
|
||||||
@ -185,7 +185,7 @@ pub fn fuzz() -> Result<(), Error> {
|
|||||||
let scheduler = QueueScheduler::new();
|
let scheduler = QueueScheduler::new();
|
||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
let mut harness = |input: &BytesInput| {
|
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>, input: &BytesInput| {
|
||||||
let target = input.target_bytes();
|
let target = input.target_bytes();
|
||||||
let mut buf = target.as_slice();
|
let mut buf = target.as_slice();
|
||||||
let mut len = buf.len();
|
let mut len = buf.len();
|
||||||
@ -218,7 +218,9 @@ pub fn fuzz() -> Result<(), Error> {
|
|||||||
ExitKind::Ok
|
ExitKind::Ok
|
||||||
};
|
};
|
||||||
|
|
||||||
let modules = tuple_list!(StdEdgeCoverageChildModule::builder().build());
|
let modules = tuple_list!(StdEdgeCoverageChildModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()?);
|
||||||
|
|
||||||
let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?;
|
let emulator = Emulator::empty().qemu(qemu).modules(modules).build()?;
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ libafl_bolts = { path = "../../../libafl_bolts", features = [
|
|||||||
"errors_backtrace",
|
"errors_backtrace",
|
||||||
] }
|
] }
|
||||||
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
|
libafl_qemu = { path = "../../../libafl_qemu", features = ["usermode"] }
|
||||||
|
libafl_targets = { path = "../../../libafl_targets" }
|
||||||
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
log = { version = "0.4.22", features = ["release_max_level_info"] }
|
||||||
nix = { version = "0.29.0", features = ["fs"] }
|
nix = { version = "0.29.0", features = ["fs"] }
|
||||||
rangemap = { version = "1.5.1" }
|
rangemap = { version = "1.5.1" }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{env, ops::Range};
|
use std::env;
|
||||||
|
|
||||||
use libafl::{
|
use libafl::{
|
||||||
corpus::{InMemoryOnDiskCorpus, OnDiskCorpus},
|
corpus::{InMemoryOnDiskCorpus, OnDiskCorpus},
|
||||||
@ -16,8 +16,6 @@ use libafl_qemu::{
|
|||||||
asan::{init_qemu_with_asan, AsanModule},
|
asan::{init_qemu_with_asan, AsanModule},
|
||||||
asan_guest::{init_qemu_with_asan_guest, AsanGuestModule},
|
asan_guest::{init_qemu_with_asan_guest, AsanGuestModule},
|
||||||
cmplog::CmpLogModule,
|
cmplog::CmpLogModule,
|
||||||
edges::StdEdgeCoverageModule,
|
|
||||||
StdAddressFilter,
|
|
||||||
},
|
},
|
||||||
ArchExtras, GuestAddr, Qemu,
|
ArchExtras, GuestAddr, Qemu,
|
||||||
};
|
};
|
||||||
@ -57,7 +55,7 @@ impl<'a> Client<'a> {
|
|||||||
.collect::<Vec<(String, String)>>()
|
.collect::<Vec<(String, String)>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_pc(qemu: &Qemu) -> Result<GuestAddr, Error> {
|
fn start_pc(qemu: Qemu) -> Result<GuestAddr, Error> {
|
||||||
let mut elf_buffer = Vec::new();
|
let mut elf_buffer = Vec::new();
|
||||||
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
|
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
|
||||||
|
|
||||||
@ -67,39 +65,6 @@ impl<'a> Client<'a> {
|
|||||||
Ok(start_pc)
|
Ok(start_pc)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::similar_names)] // elf != self
|
|
||||||
fn coverage_filter(&self, qemu: &Qemu) -> Result<StdAddressFilter, Error> {
|
|
||||||
/* Conversion is required on 32-bit targets, but not on 64-bit ones */
|
|
||||||
if let Some(includes) = &self.options.include {
|
|
||||||
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
|
||||||
let rules = includes
|
|
||||||
.iter()
|
|
||||||
.map(|x| Range {
|
|
||||||
start: x.start.into(),
|
|
||||||
end: x.end.into(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<Range<GuestAddr>>>();
|
|
||||||
Ok(StdAddressFilter::allow_list(rules))
|
|
||||||
} else if let Some(excludes) = &self.options.exclude {
|
|
||||||
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
|
||||||
let rules = excludes
|
|
||||||
.iter()
|
|
||||||
.map(|x| Range {
|
|
||||||
start: x.start.into(),
|
|
||||||
end: x.end.into(),
|
|
||||||
})
|
|
||||||
.collect::<Vec<Range<GuestAddr>>>();
|
|
||||||
Ok(StdAddressFilter::deny_list(rules))
|
|
||||||
} else {
|
|
||||||
let mut elf_buffer = Vec::new();
|
|
||||||
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
|
|
||||||
let range = elf
|
|
||||||
.get_section(".text", qemu.load_addr())
|
|
||||||
.ok_or_else(|| Error::key_not_found("Failed to find .text section"))?;
|
|
||||||
Ok(StdAddressFilter::allow_list(vec![range]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run<M: Monitor>(
|
pub fn run<M: Monitor>(
|
||||||
&self,
|
&self,
|
||||||
state: Option<ClientState>,
|
state: Option<ClientState>,
|
||||||
@ -131,7 +96,7 @@ impl<'a> Client<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let start_pc = Self::start_pc(&qemu)?;
|
let start_pc = Self::start_pc(qemu)?;
|
||||||
log::debug!("start_pc @ {start_pc:#x}");
|
log::debug!("start_pc @ {start_pc:#x}");
|
||||||
|
|
||||||
#[cfg(not(feature = "injections"))]
|
#[cfg(not(feature = "injections"))]
|
||||||
@ -163,10 +128,6 @@ impl<'a> Client<'a> {
|
|||||||
|
|
||||||
let is_cmplog = self.options.is_cmplog_core(core_id);
|
let is_cmplog = self.options.is_cmplog_core(core_id);
|
||||||
|
|
||||||
let edge_coverage_module = StdEdgeCoverageModule::builder()
|
|
||||||
.address_filter(self.coverage_filter(&qemu)?)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let extra_tokens = injection_module
|
let extra_tokens = injection_module
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|h| h.tokens.clone())
|
.map(|h| h.tokens.clone())
|
||||||
@ -174,7 +135,7 @@ impl<'a> Client<'a> {
|
|||||||
|
|
||||||
let instance_builder = Instance::builder()
|
let instance_builder = Instance::builder()
|
||||||
.options(self.options)
|
.options(self.options)
|
||||||
.qemu(&qemu)
|
.qemu(qemu)
|
||||||
.mgr(mgr)
|
.mgr(mgr)
|
||||||
.core_id(core_id)
|
.core_id(core_id)
|
||||||
.extra_tokens(extra_tokens);
|
.extra_tokens(extra_tokens);
|
||||||
@ -183,7 +144,6 @@ impl<'a> Client<'a> {
|
|||||||
if let Some(injection_module) = injection_module {
|
if let Some(injection_module) = injection_module {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
edge_coverage_module,
|
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
AsanModule::default(asan.take().unwrap()),
|
AsanModule::default(asan.take().unwrap()),
|
||||||
injection_module,
|
injection_module,
|
||||||
@ -193,7 +153,6 @@ impl<'a> Client<'a> {
|
|||||||
} else {
|
} else {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
edge_coverage_module,
|
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
AsanModule::default(asan.take().unwrap()),
|
AsanModule::default(asan.take().unwrap()),
|
||||||
),
|
),
|
||||||
@ -204,9 +163,8 @@ impl<'a> Client<'a> {
|
|||||||
if let Some(injection_module) = injection_module {
|
if let Some(injection_module) = injection_module {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
edge_coverage_module,
|
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
AsanGuestModule::default(&qemu, asan_lib.take().unwrap()),
|
AsanGuestModule::default(qemu, asan_lib.take().unwrap()),
|
||||||
injection_module
|
injection_module
|
||||||
),
|
),
|
||||||
state,
|
state,
|
||||||
@ -214,9 +172,8 @@ impl<'a> Client<'a> {
|
|||||||
} else {
|
} else {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
edge_coverage_module,
|
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
AsanGuestModule::default(&qemu, asan_lib.take().unwrap()),
|
AsanGuestModule::default(qemu, asan_lib.take().unwrap()),
|
||||||
),
|
),
|
||||||
state,
|
state,
|
||||||
)
|
)
|
||||||
@ -224,52 +181,35 @@ impl<'a> Client<'a> {
|
|||||||
} else if is_asan {
|
} else if is_asan {
|
||||||
if let Some(injection_module) = injection_module {
|
if let Some(injection_module) = injection_module {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(AsanModule::default(asan.take().unwrap()), injection_module),
|
||||||
edge_coverage_module,
|
|
||||||
AsanModule::default(asan.take().unwrap()),
|
|
||||||
injection_module
|
|
||||||
),
|
|
||||||
state,
|
state,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(AsanModule::default(asan.take().unwrap()),),
|
||||||
edge_coverage_module,
|
|
||||||
AsanModule::default(asan.take().unwrap()),
|
|
||||||
),
|
|
||||||
state,
|
state,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else if is_asan_guest {
|
} else if is_asan_guest {
|
||||||
let modules = tuple_list!(
|
let modules = tuple_list!(AsanGuestModule::default(qemu, asan_lib.take().unwrap()));
|
||||||
edge_coverage_module,
|
|
||||||
AsanGuestModule::default(&qemu, asan_lib.take().unwrap())
|
|
||||||
);
|
|
||||||
instance_builder.build().run(modules, state)
|
instance_builder.build().run(modules, state)
|
||||||
} else if is_cmplog {
|
} else if is_cmplog {
|
||||||
if let Some(injection_module) = injection_module {
|
if let Some(injection_module) = injection_module {
|
||||||
instance_builder.build().run(
|
instance_builder.build().run(
|
||||||
tuple_list!(
|
tuple_list!(CmpLogModule::default(), injection_module),
|
||||||
edge_coverage_module,
|
|
||||||
CmpLogModule::default(),
|
|
||||||
injection_module
|
|
||||||
),
|
|
||||||
state,
|
state,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
instance_builder.build().run(
|
instance_builder
|
||||||
tuple_list!(edge_coverage_module, CmpLogModule::default()),
|
.build()
|
||||||
state,
|
.run(tuple_list!(CmpLogModule::default()), state)
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else if let Some(injection_module) = injection_module {
|
} else if let Some(injection_module) = injection_module {
|
||||||
instance_builder
|
instance_builder
|
||||||
.build()
|
.build()
|
||||||
.run(tuple_list!(edge_coverage_module, injection_module), state)
|
.run(tuple_list!(injection_module), state)
|
||||||
} else {
|
} else {
|
||||||
instance_builder
|
instance_builder.build().run(tuple_list!(), state)
|
||||||
.build()
|
|
||||||
.run(tuple_list!(edge_coverage_module), state)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ use libafl::{
|
|||||||
use libafl_bolts::AsSlice;
|
use libafl_bolts::AsSlice;
|
||||||
use libafl_qemu::{ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, Regs};
|
use libafl_qemu::{ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, Regs};
|
||||||
|
|
||||||
pub struct Harness<'a> {
|
pub struct Harness {
|
||||||
qemu: &'a Qemu,
|
qemu: Qemu,
|
||||||
input_addr: GuestAddr,
|
input_addr: GuestAddr,
|
||||||
pc: GuestAddr,
|
pc: GuestAddr,
|
||||||
stack_ptr: GuestAddr,
|
stack_ptr: GuestAddr,
|
||||||
@ -16,8 +16,8 @@ pub struct Harness<'a> {
|
|||||||
|
|
||||||
pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB
|
pub const MAX_INPUT_SIZE: usize = 1_048_576; // 1MB
|
||||||
|
|
||||||
impl<'a> Harness<'a> {
|
impl Harness {
|
||||||
pub fn new(qemu: &Qemu) -> Result<Harness, Error> {
|
pub fn new(qemu: Qemu) -> Result<Harness, Error> {
|
||||||
let input_addr = qemu
|
let input_addr = qemu
|
||||||
.map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite)
|
.map_private(0, MAX_INPUT_SIZE, MmapPerms::ReadWrite)
|
||||||
.map_err(|e| Error::unknown(format!("Failed to map input buffer: {e:}")))?;
|
.map_err(|e| Error::unknown(format!("Failed to map input buffer: {e:}")))?;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use core::{fmt::Debug, ptr::addr_of_mut};
|
use core::{fmt::Debug, ptr::addr_of_mut};
|
||||||
use std::{marker::PhantomData, process};
|
use std::{marker::PhantomData, ops::Range, process};
|
||||||
|
|
||||||
#[cfg(feature = "simplemgr")]
|
#[cfg(feature = "simplemgr")]
|
||||||
use libafl::events::SimpleEventManager;
|
use libafl::events::SimpleEventManager;
|
||||||
@ -35,16 +35,16 @@ use libafl_bolts::{
|
|||||||
core_affinity::CoreId,
|
core_affinity::CoreId,
|
||||||
ownedref::OwnedMutSlice,
|
ownedref::OwnedMutSlice,
|
||||||
rands::StdRand,
|
rands::StdRand,
|
||||||
tuples::{tuple_list, Merge},
|
tuples::{tuple_list, Merge, Prepend},
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
|
elf::EasyElf,
|
||||||
modules::{
|
modules::{
|
||||||
cmplog::CmpLogObserver,
|
cmplog::CmpLogObserver, EmulatorModuleTuple, StdAddressFilter, StdEdgeCoverageModule,
|
||||||
edges::{edges_map_mut_ptr, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND},
|
|
||||||
EmulatorModuleTuple,
|
|
||||||
},
|
},
|
||||||
Emulator, Qemu, QemuExecutor,
|
Emulator, GuestAddr, Qemu, QemuExecutor,
|
||||||
};
|
};
|
||||||
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
use typed_builder::TypedBuilder;
|
use typed_builder::TypedBuilder;
|
||||||
|
|
||||||
use crate::{harness::Harness, options::FuzzerOptions};
|
use crate::{harness::Harness, options::FuzzerOptions};
|
||||||
@ -61,7 +61,7 @@ pub type ClientMgr<M> =
|
|||||||
#[derive(TypedBuilder)]
|
#[derive(TypedBuilder)]
|
||||||
pub struct Instance<'a, M: Monitor> {
|
pub struct Instance<'a, M: Monitor> {
|
||||||
options: &'a FuzzerOptions,
|
options: &'a FuzzerOptions,
|
||||||
qemu: &'a Qemu,
|
qemu: Qemu,
|
||||||
mgr: ClientMgr<M>,
|
mgr: ClientMgr<M>,
|
||||||
core_id: CoreId,
|
core_id: CoreId,
|
||||||
#[builder(default)]
|
#[builder(default)]
|
||||||
@ -71,20 +71,60 @@ pub struct Instance<'a, M: Monitor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, M: Monitor> Instance<'a, M> {
|
impl<'a, M: Monitor> Instance<'a, M> {
|
||||||
|
#[allow(clippy::similar_names)] // elf != self
|
||||||
|
fn coverage_filter(&self, qemu: Qemu) -> Result<StdAddressFilter, Error> {
|
||||||
|
/* Conversion is required on 32-bit targets, but not on 64-bit ones */
|
||||||
|
if let Some(includes) = &self.options.include {
|
||||||
|
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
||||||
|
let rules = includes
|
||||||
|
.iter()
|
||||||
|
.map(|x| Range {
|
||||||
|
start: x.start.into(),
|
||||||
|
end: x.end.into(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<Range<GuestAddr>>>();
|
||||||
|
Ok(StdAddressFilter::allow_list(rules))
|
||||||
|
} else if let Some(excludes) = &self.options.exclude {
|
||||||
|
#[cfg_attr(target_pointer_width = "64", allow(clippy::useless_conversion))]
|
||||||
|
let rules = excludes
|
||||||
|
.iter()
|
||||||
|
.map(|x| Range {
|
||||||
|
start: x.start.into(),
|
||||||
|
end: x.end.into(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<Range<GuestAddr>>>();
|
||||||
|
Ok(StdAddressFilter::deny_list(rules))
|
||||||
|
} else {
|
||||||
|
let mut elf_buffer = Vec::new();
|
||||||
|
let elf = EasyElf::from_file(qemu.binary_path(), &mut elf_buffer)?;
|
||||||
|
let range = elf
|
||||||
|
.get_section(".text", qemu.load_addr())
|
||||||
|
.ok_or_else(|| Error::key_not_found("Failed to find .text section"))?;
|
||||||
|
Ok(StdAddressFilter::allow_list(vec![range]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run<ET>(&mut self, modules: ET, state: Option<ClientState>) -> Result<(), Error>
|
pub fn run<ET>(&mut self, modules: ET, state: Option<ClientState>) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
ET: EmulatorModuleTuple<ClientState> + Debug,
|
ET: EmulatorModuleTuple<ClientState> + Debug,
|
||||||
{
|
{
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = unsafe {
|
let mut edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
))
|
))
|
||||||
.track_indices()
|
.track_indices()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let edge_coverage_module = StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.address_filter(self.coverage_filter(self.qemu)?)
|
||||||
|
.build()?;
|
||||||
|
|
||||||
|
let modules = modules.prepend(edge_coverage_module);
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let time_observer = TimeObserver::new("time");
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
@ -154,10 +194,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
|
|||||||
// A fuzzer with feedbacks and a corpus scheduler
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
|
||||||
|
|
||||||
let emulator = Emulator::empty()
|
let emulator = Emulator::empty().qemu(self.qemu).modules(modules).build()?;
|
||||||
.qemu(*self.qemu)
|
|
||||||
.modules(modules)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
if self.options.is_cmplog_core(self.core_id) {
|
if self.options.is_cmplog_core(self.core_id) {
|
||||||
// Create a QEMU in-process executor
|
// Create a QEMU in-process executor
|
||||||
|
@ -24,7 +24,7 @@ use libafl_bolts::{
|
|||||||
tuples::{tuple_list, Handled, MatchNameRef, Merge},
|
tuples::{tuple_list, Handled, MatchNameRef, Merge},
|
||||||
AsSliceMut, Truncate,
|
AsSliceMut, Truncate,
|
||||||
};
|
};
|
||||||
use libafl_targets::EDGES_MAP_SIZE_IN_USE;
|
use libafl_targets::EDGES_MAP_DEFAULT_SIZE;
|
||||||
use nix::sys::signal::Signal;
|
use nix::sys::signal::Signal;
|
||||||
|
|
||||||
/// The commandline args this fuzzer accepts
|
/// The commandline args this fuzzer accepts
|
||||||
@ -87,7 +87,7 @@ struct Opt {
|
|||||||
pub fn main() {
|
pub fn main() {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
const MAP_SIZE: usize = EDGES_MAP_SIZE_IN_USE; //65536;
|
const MAP_SIZE: usize = EDGES_MAP_DEFAULT_SIZE; //65536;
|
||||||
let opt = Opt::parse();
|
let opt = Opt::parse();
|
||||||
|
|
||||||
let corpus_dirs: Vec<PathBuf> = [opt.in_dir].to_vec();
|
let corpus_dirs: Vec<PathBuf> = [opt.in_dir].to_vec();
|
||||||
|
@ -28,6 +28,7 @@ codegen-units = 1
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
libafl = { path = "../../../libafl" }
|
libafl = { path = "../../../libafl" }
|
||||||
libafl_bolts = { path = "../../../libafl_bolts" }
|
libafl_bolts = { path = "../../../libafl_bolts" }
|
||||||
|
libafl_targets = { path = "../../../libafl_targets" }
|
||||||
libafl_qemu = { path = "../../../libafl_qemu", features = [
|
libafl_qemu = { path = "../../../libafl_qemu", features = [
|
||||||
"arm",
|
"arm",
|
||||||
"systemmode",
|
"systemmode",
|
||||||
|
@ -33,11 +33,11 @@ use libafl_qemu::{
|
|||||||
elf::EasyElf,
|
elf::EasyElf,
|
||||||
emu::Emulator,
|
emu::Emulator,
|
||||||
executor::QemuExecutor,
|
executor::QemuExecutor,
|
||||||
modules::edges::{
|
modules::edges::StdEdgeCoverageModule,
|
||||||
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
|
|
||||||
},
|
|
||||||
GuestPhysAddr, GuestReg, QemuMemoryChunk,
|
GuestPhysAddr, GuestReg, QemuMemoryChunk,
|
||||||
};
|
};
|
||||||
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
|
|
||||||
// use libafl_qemu::QemuSnapshotBuilder; // for normal qemu snapshot
|
// use libafl_qemu::QemuSnapshotBuilder; // for normal qemu snapshot
|
||||||
|
|
||||||
pub static mut MAX_INPUT_SIZE: usize = 50;
|
pub static mut MAX_INPUT_SIZE: usize = 50;
|
||||||
@ -86,10 +86,33 @@ pub fn fuzz() {
|
|||||||
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
|
let mut harness =
|
||||||
|
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
|
||||||
|
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let mut edges_observer = unsafe {
|
||||||
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
|
"edges",
|
||||||
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
|
))
|
||||||
|
.track_indices()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an observation channel to keep track of the execution time
|
||||||
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
// Initialize QEMU Emulator
|
// Initialize QEMU Emulator
|
||||||
let emu = Emulator::builder()
|
let emu = Emulator::builder()
|
||||||
.qemu_cli(args)
|
.qemu_cli(args)
|
||||||
.add_module(StdEdgeCoverageModule::builder().build())
|
.add_module(
|
||||||
|
StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()?,
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -119,25 +142,6 @@ pub fn fuzz() {
|
|||||||
let devices = emu.list_devices();
|
let devices = emu.list_devices();
|
||||||
println!("Devices = {:?}", devices);
|
println!("Devices = {:?}", devices);
|
||||||
|
|
||||||
// The wrapped harness function, calling out to the LLVM-style harness
|
|
||||||
let mut harness =
|
|
||||||
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
|
|
||||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
|
||||||
let edges_observer = unsafe {
|
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
|
||||||
"edges",
|
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
|
||||||
))
|
|
||||||
.track_indices()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
|
||||||
let time_observer = TimeObserver::new("time");
|
|
||||||
|
|
||||||
// Feedback to rate the interestingness of an input
|
// Feedback to rate the interestingness of an input
|
||||||
// This one is composed by two Feedbacks in OR
|
// This one is composed by two Feedbacks in OR
|
||||||
let mut feedback = feedback_or!(
|
let mut feedback = feedback_or!(
|
||||||
|
@ -29,15 +29,11 @@ use libafl_bolts::{
|
|||||||
AsSlice,
|
AsSlice,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{
|
||||||
config,
|
config, elf::EasyElf, executor::QemuExecutor, modules::edges::StdEdgeCoverageModuleBuilder,
|
||||||
elf::EasyElf,
|
|
||||||
executor::QemuExecutor,
|
|
||||||
modules::edges::{
|
|
||||||
edges_map_mut_ptr, StdEdgeCoverageModuleBuilder, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
|
|
||||||
},
|
|
||||||
Emulator, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, Regs,
|
Emulator, Qemu, QemuExitError, QemuExitReason, QemuRWError, QemuShutdownCause, Regs,
|
||||||
};
|
};
|
||||||
use libafl_qemu_sys::GuestPhysAddr;
|
use libafl_qemu_sys::GuestPhysAddr;
|
||||||
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
|
|
||||||
pub static mut MAX_INPUT_SIZE: usize = 50;
|
pub static mut MAX_INPUT_SIZE: usize = 50;
|
||||||
|
|
||||||
@ -86,6 +82,17 @@ pub fn fuzz() {
|
|||||||
|
|
||||||
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
let mut run_client = |state: Option<_>, mut mgr, _core_id| {
|
||||||
let target_dir = env::var("TARGET_DIR").expect("TARGET_DIR env not set");
|
let target_dir = env::var("TARGET_DIR").expect("TARGET_DIR env not set");
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let mut edges_observer = unsafe {
|
||||||
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
|
"edges",
|
||||||
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
|
))
|
||||||
|
.track_indices()
|
||||||
|
};
|
||||||
|
|
||||||
// Initialize QEMU
|
// Initialize QEMU
|
||||||
let qemu = Qemu::builder()
|
let qemu = Qemu::builder()
|
||||||
.machine("mps2-an385")
|
.machine("mps2-an385")
|
||||||
@ -103,7 +110,9 @@ pub fn fuzz() {
|
|||||||
.build()
|
.build()
|
||||||
.expect("Failed to initialized QEMU");
|
.expect("Failed to initialized QEMU");
|
||||||
|
|
||||||
let emulator_modules = tuple_list!(StdEdgeCoverageModuleBuilder::default().build());
|
let emulator_modules = tuple_list!(StdEdgeCoverageModuleBuilder::default()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()?);
|
||||||
|
|
||||||
let emulator = Emulator::empty()
|
let emulator = Emulator::empty()
|
||||||
.qemu(qemu)
|
.qemu(qemu)
|
||||||
@ -186,16 +195,6 @@ pub fn fuzz() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
|
||||||
let edges_observer = unsafe {
|
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
|
||||||
"edges",
|
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
|
||||||
))
|
|
||||||
.track_indices()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let time_observer = TimeObserver::new("time");
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
|
@ -26,13 +26,8 @@ use libafl_bolts::{
|
|||||||
shmem::{ShMemProvider, StdShMemProvider},
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
tuples::tuple_list,
|
tuples::tuple_list,
|
||||||
};
|
};
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{emu::Emulator, executor::QemuExecutor, modules::edges::StdEdgeCoverageModule};
|
||||||
emu::Emulator,
|
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
executor::QemuExecutor,
|
|
||||||
modules::edges::{
|
|
||||||
edges_map_mut_ptr, StdEdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// use libafl_qemu::QemuSnapshotBuilder; for normal qemu snapshot
|
// use libafl_qemu::QemuSnapshotBuilder; for normal qemu snapshot
|
||||||
|
|
||||||
pub fn fuzz() {
|
pub fn fuzz() {
|
||||||
@ -52,8 +47,20 @@ pub fn fuzz() {
|
|||||||
// Initialize QEMU
|
// Initialize QEMU
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let mut edges_observer = unsafe {
|
||||||
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
|
"edges",
|
||||||
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
|
))
|
||||||
|
.track_indices()
|
||||||
|
};
|
||||||
|
|
||||||
// Choose modules to use
|
// Choose modules to use
|
||||||
let modules = tuple_list!(StdEdgeCoverageModule::builder().build());
|
let modules = tuple_list!(StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()?);
|
||||||
|
|
||||||
let emu = Emulator::builder()
|
let emu = Emulator::builder()
|
||||||
.qemu_cli(args)
|
.qemu_cli(args)
|
||||||
@ -69,16 +76,6 @@ pub fn fuzz() {
|
|||||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
|
||||||
let edges_observer = unsafe {
|
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
|
||||||
"edges",
|
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
|
||||||
))
|
|
||||||
.track_indices()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create an observation channel to keep track of the execution time
|
// Create an observation channel to keep track of the execution time
|
||||||
let time_observer = TimeObserver::new("time");
|
let time_observer = TimeObserver::new("time");
|
||||||
|
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
|
|
||||||
This folder contains an example linux kernel fuzzer using qemu systemmode.
|
This folder contains an example linux kernel fuzzer using qemu systemmode.
|
||||||
|
|
||||||
|
## Warning
|
||||||
|
|
||||||
|
For now, only the fuzzer is public. We plan to release the auto-builder for linux
|
||||||
|
images in the near future.
|
||||||
|
If you wish to experiment now, you will need to build the linux image manually.
|
||||||
|
|
||||||
## Prerequisite
|
## Prerequisite
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
@ -36,7 +36,8 @@ use libafl_qemu::{
|
|||||||
modules::{
|
modules::{
|
||||||
cmplog::CmpLogObserver,
|
cmplog::CmpLogObserver,
|
||||||
edges::{
|
edges::{
|
||||||
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_SIZE_MAX, MAX_EDGES_FOUND,
|
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_ALLOCATED_SIZE,
|
||||||
|
MAX_EDGES_FOUND,
|
||||||
},
|
},
|
||||||
CmpLogModule,
|
CmpLogModule,
|
||||||
},
|
},
|
||||||
@ -89,7 +90,7 @@ pub fn fuzz() {
|
|||||||
let edges_observer = unsafe {
|
let edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_MAX),
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
))
|
))
|
||||||
.track_indices()
|
.track_indices()
|
||||||
|
@ -3,6 +3,12 @@
|
|||||||
This folder contains an example linux process fuzzer using qemu systemmode.
|
This folder contains an example linux process fuzzer using qemu systemmode.
|
||||||
This is demo, most of the time for classic linux process fuzzing, it is better to use a more conventional method.
|
This is demo, most of the time for classic linux process fuzzing, it is better to use a more conventional method.
|
||||||
|
|
||||||
|
## Warning
|
||||||
|
|
||||||
|
For now, only the fuzzer is public. We plan to release the auto-builder for linux
|
||||||
|
images in the near future.
|
||||||
|
If you wish to experiment now, you will need to build the linux image manually.
|
||||||
|
|
||||||
## Prerequisite
|
## Prerequisite
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
@ -36,7 +36,8 @@ use libafl_qemu::{
|
|||||||
modules::{
|
modules::{
|
||||||
cmplog::CmpLogObserver,
|
cmplog::CmpLogObserver,
|
||||||
edges::{
|
edges::{
|
||||||
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_SIZE_MAX, MAX_EDGES_FOUND,
|
edges_map_mut_ptr, StdEdgeCoverageClassicModule, EDGES_MAP_ALLOCATED_SIZE,
|
||||||
|
MAX_EDGES_FOUND,
|
||||||
},
|
},
|
||||||
CmpLogModule,
|
CmpLogModule,
|
||||||
},
|
},
|
||||||
@ -91,7 +92,7 @@ pub fn fuzz() {
|
|||||||
let edges_observer = unsafe {
|
let edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_MAX),
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_ALLOCATED_SIZE),
|
||||||
addr_of_mut!(MAX_EDGES_FOUND),
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
))
|
))
|
||||||
.track_indices()
|
.track_indices()
|
||||||
|
@ -55,7 +55,7 @@ use libafl_bolts::{
|
|||||||
use libafl_targets::autotokens;
|
use libafl_targets::autotokens;
|
||||||
use libafl_targets::{
|
use libafl_targets::{
|
||||||
edges_map_mut_ptr, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CtxHook,
|
edges_map_mut_ptr, libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CtxHook,
|
||||||
EDGES_MAP_SIZE_IN_USE,
|
EDGES_MAP_DEFAULT_SIZE,
|
||||||
};
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nix::unistd::dup;
|
use nix::unistd::dup;
|
||||||
@ -252,7 +252,7 @@ fn fuzz(
|
|||||||
let edges_observer = HitcountsMapObserver::new(unsafe {
|
let edges_observer = HitcountsMapObserver::new(unsafe {
|
||||||
StdMapObserver::from_mut_slice(
|
StdMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE_IN_USE),
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.track_indices();
|
.track_indices();
|
||||||
|
@ -40,10 +40,7 @@ use crate::{
|
|||||||
|
|
||||||
/// The inmem executor's handlers.
|
/// The inmem executor's handlers.
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct InProcessHooks<S>
|
pub struct InProcessHooks<S> {
|
||||||
where
|
|
||||||
S: UsesInput,
|
|
||||||
{
|
|
||||||
/// On crash C function pointer
|
/// On crash C function pointer
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub crash_handler: *const c_void,
|
pub crash_handler: *const c_void,
|
||||||
|
@ -35,12 +35,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// The internal state of `GenericInProcessExecutor`.
|
/// The internal state of `GenericInProcessExecutor`.
|
||||||
pub struct GenericInProcessExecutorInner<HT, OT, S>
|
pub struct GenericInProcessExecutorInner<HT, OT, S> {
|
||||||
where
|
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State,
|
|
||||||
{
|
|
||||||
/// The observers, observing each run
|
/// The observers, observing each run
|
||||||
pub(super) observers: OT,
|
pub(super) observers: OT,
|
||||||
// Crash and timeout hah
|
// Crash and timeout hah
|
||||||
@ -50,9 +45,7 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S> Debug for GenericInProcessExecutorInner<HT, OT, S>
|
impl<HT, OT, S> Debug for GenericInProcessExecutorInner<HT, OT, S>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
OT: Debug,
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
|
||||||
S: State,
|
|
||||||
{
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("GenericInProcessExecutorState")
|
f.debug_struct("GenericInProcessExecutorState")
|
||||||
@ -63,8 +56,6 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S> UsesState for GenericInProcessExecutorInner<HT, OT, S>
|
impl<HT, OT, S> UsesState for GenericInProcessExecutorInner<HT, OT, S>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State,
|
S: State,
|
||||||
{
|
{
|
||||||
type State = S;
|
type State = S;
|
||||||
@ -72,7 +63,6 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S>
|
impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: State,
|
S: State,
|
||||||
{
|
{
|
||||||
@ -92,7 +82,6 @@ where
|
|||||||
impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
|
impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
HT: ExecutorHooksTuple<S>,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State,
|
S: State,
|
||||||
{
|
{
|
||||||
/// This function marks the boundary between the fuzzer and the target
|
/// This function marks the boundary between the fuzzer and the target
|
||||||
@ -156,7 +145,7 @@ impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
|
|||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
HT: ExecutorHooksTuple<S>,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: HasExecutions + HasSolutions + HasCorpus + State,
|
S: HasCorpus + HasExecutions + HasSolutions + UsesInput,
|
||||||
{
|
{
|
||||||
/// Create a new in mem executor with the default timeout (5 sec)
|
/// Create a new in mem executor with the default timeout (5 sec)
|
||||||
pub fn generic<E, EM, OF, Z>(
|
pub fn generic<E, EM, OF, Z>(
|
||||||
@ -288,9 +277,7 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutorInner<HT, OT, S>
|
impl<HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutorInner<HT, OT, S>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
S: UsesInput,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State + HasExecutions + HasSolutions + HasCorpus,
|
|
||||||
{
|
{
|
||||||
/// the timeout handler
|
/// the timeout handler
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -35,15 +35,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Inner state of GenericInProcessExecutor-like structures.
|
/// Inner state of GenericInProcessExecutor-like structures.
|
||||||
pub struct GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
pub struct GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> {
|
||||||
where
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: UsesInput,
|
|
||||||
SP: ShMemProvider,
|
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
|
||||||
pub(super) hooks: (InChildProcessHooks<S>, HT),
|
pub(super) hooks: (InChildProcessHooks<S>, HT),
|
||||||
pub(super) shmem_provider: SP,
|
pub(super) shmem_provider: SP,
|
||||||
pub(super) observers: OT,
|
pub(super) observers: OT,
|
||||||
@ -56,12 +48,9 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
impl<HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
||||||
where
|
where
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
HT: Debug,
|
||||||
S: UsesInput,
|
OT: Debug,
|
||||||
SP: ShMemProvider,
|
SP: Debug,
|
||||||
HT: ExecutorHooksTuple<S> + Debug,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
@ -86,12 +75,7 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S, SP, EM, Z> UsesState for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
impl<HT, OT, S, SP, EM, Z> UsesState for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
||||||
where
|
where
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State,
|
S: State,
|
||||||
SP: ShMemProvider,
|
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
type State = S;
|
type State = S;
|
||||||
}
|
}
|
||||||
@ -195,9 +179,6 @@ where
|
|||||||
HT: ExecutorHooksTuple<S>,
|
HT: ExecutorHooksTuple<S>,
|
||||||
S: State,
|
S: State,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
SP: ShMemProvider,
|
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
/// This function marks the boundary between the fuzzer and the target.
|
/// This function marks the boundary between the fuzzer and the target.
|
||||||
@ -319,12 +300,8 @@ where
|
|||||||
|
|
||||||
impl<HT, OT, S, SP, EM, Z> HasObservers for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
impl<HT, OT, S, SP, EM, Z> HasObservers for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
|
||||||
where
|
where
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
S: State,
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
SP: ShMemProvider,
|
S: State,
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
type Observers = OT;
|
type Observers = OT;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ use crate::{
|
|||||||
fuzzer::HasObjective,
|
fuzzer::HasObjective,
|
||||||
inputs::UsesInput,
|
inputs::UsesInput,
|
||||||
observers::ObserversTuple,
|
observers::ObserversTuple,
|
||||||
state::{HasExecutions, HasSolutions, State, UsesState},
|
state::{HasExecutions, State, UsesState},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -32,15 +32,11 @@ use crate::{
|
|||||||
pub type StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> =
|
pub type StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> =
|
||||||
StatefulGenericInProcessForkExecutor<'a, H, (), OT, S, SP, ES, EM, Z>;
|
StatefulGenericInProcessForkExecutor<'a, H, (), OT, S, SP, ES, EM, Z>;
|
||||||
|
|
||||||
impl<'a, H, OT, S, SP, ES, EM, Z, OF> StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z>
|
impl<'a, H, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
SP: ShMemProvider,
|
S: State,
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
|
||||||
OF: Feedback<EM, S::Input, OT, S>,
|
|
||||||
S: State + HasSolutions,
|
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
|
||||||
{
|
{
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
/// The constructor for `InProcessForkExecutor`
|
/// The constructor for `InProcessForkExecutor`
|
||||||
@ -71,30 +67,26 @@ where
|
|||||||
/// [`StatefulGenericInProcessForkExecutor`] is an executor that forks the current process before each execution. Harness can access some internal state.
|
/// [`StatefulGenericInProcessForkExecutor`] is an executor that forks the current process before each execution. Harness can access some internal state.
|
||||||
pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
|
pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
SP: ShMemProvider,
|
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
|
/// The harness function, being executed for each fuzzing loop execution
|
||||||
harness_fn: &'a mut H,
|
harness_fn: &'a mut H,
|
||||||
exposed_executor_state: ES,
|
/// The state used as argument of the harness
|
||||||
inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>,
|
pub exposed_executor_state: ES,
|
||||||
|
/// Inner state of the executor
|
||||||
|
pub inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>,
|
||||||
phantom: PhantomData<ES>,
|
phantom: PhantomData<ES>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, HT, OT, S, SP, ES, EM, Z> Debug
|
impl<H, HT, OT, S, SP, ES, EM, Z> Debug
|
||||||
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
HT: Debug,
|
||||||
|
OT: Debug,
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
SP: ShMemProvider,
|
SP: Debug,
|
||||||
HT: ExecutorHooksTuple<S> + Debug,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
@ -116,13 +108,8 @@ where
|
|||||||
impl<H, HT, OT, S, SP, ES, EM, Z> UsesState
|
impl<H, HT, OT, S, SP, ES, EM, Z> UsesState
|
||||||
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
|
||||||
S: State,
|
S: State,
|
||||||
SP: ShMemProvider,
|
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
type State = S;
|
type State = S;
|
||||||
}
|
}
|
||||||
@ -130,14 +117,14 @@ where
|
|||||||
impl<EM, H, HT, OT, S, SP, Z, ES, OF> Executor<EM, Z>
|
impl<EM, H, HT, OT, S, SP, Z, ES, OF> Executor<EM, Z>
|
||||||
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
|
HT: ExecutorHooksTuple<S>,
|
||||||
|
OF: Feedback<EM, S::Input, OT, S>,
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
OT: ObserversTuple<S::Input, S> + Debug,
|
||||||
S: State + HasExecutions,
|
S: State + HasExecutions,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
OF: Feedback<EM, S::Input, OT, S>,
|
|
||||||
{
|
{
|
||||||
#[allow(unreachable_code)]
|
#[allow(unreachable_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -156,7 +143,7 @@ where
|
|||||||
Ok(ForkResult::Child) => {
|
Ok(ForkResult::Child) => {
|
||||||
// Child
|
// Child
|
||||||
self.inner.pre_run_target_child(fuzzer, state, mgr, input)?;
|
self.inner.pre_run_target_child(fuzzer, state, mgr, input)?;
|
||||||
(self.harness_fn)(input, &mut self.exposed_executor_state);
|
(self.harness_fn)(&mut self.exposed_executor_state, input);
|
||||||
self.inner.post_run_target_child(fuzzer, state, mgr, input);
|
self.inner.post_run_target_child(fuzzer, state, mgr, input);
|
||||||
Ok(ExitKind::Ok)
|
Ok(ExitKind::Ok)
|
||||||
}
|
}
|
||||||
@ -170,18 +157,13 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, H, HT, OT, S, SP, ES, EM, Z, OF>
|
impl<'a, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
|
StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
HT: ExecutorHooksTuple<S>,
|
HT: ExecutorHooksTuple<S>,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
SP: ShMemProvider,
|
S: State,
|
||||||
Z: UsesState<State = S>,
|
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
|
||||||
OF: Feedback<EM, S::Input, OT, S>,
|
|
||||||
S: State + HasSolutions,
|
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
|
||||||
{
|
{
|
||||||
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
|
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
@ -228,15 +210,12 @@ where
|
|||||||
impl<H, HT, OT, S, SP, ES, EM, Z> HasObservers
|
impl<H, HT, OT, S, SP, ES, EM, Z> HasObservers
|
||||||
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
|
||||||
where
|
where
|
||||||
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
|
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
|
||||||
HT: ExecutorHooksTuple<S>,
|
|
||||||
S: State,
|
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
SP: ShMemProvider,
|
S: State,
|
||||||
EM: UsesState<State = S>,
|
|
||||||
Z: UsesState<State = S>,
|
|
||||||
{
|
{
|
||||||
type Observers = OT;
|
type Observers = OT;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
|
||||||
self.inner.observers()
|
self.inner.observers()
|
||||||
|
@ -12,10 +12,12 @@ use libafl_bolts::{ownedref::OwnedMutSlice, AsSlice, AsSliceMut, HasLen, Named};
|
|||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
observers::{map::MapObserver, Observer},
|
observers::{map::MapObserver, Observer, VariableLengthMapObserver},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: remove the size field and implement ConstantLengthMapObserver
|
||||||
|
|
||||||
/// Use a const size to speedup `Feedback::is_interesting` when the user can
|
/// Use a const size to speedup `Feedback::is_interesting` when the user can
|
||||||
/// know the size of the map at compile time.
|
/// know the size of the map at compile time.
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -24,6 +26,7 @@ pub struct ConstMapObserver<'a, T, const N: usize> {
|
|||||||
map: OwnedMutSlice<'a, T>,
|
map: OwnedMutSlice<'a, T>,
|
||||||
initial: T,
|
initial: T,
|
||||||
name: Cow<'static, str>,
|
name: Cow<'static, str>,
|
||||||
|
size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'_, T, N>
|
impl<I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'_, T, N>
|
||||||
@ -147,6 +150,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T, const N: usize> VariableLengthMapObserver for ConstMapObserver<'_, T, N>
|
||||||
|
where
|
||||||
|
T: PartialEq + Copy + Hash + Serialize + DeserializeOwned + Debug + 'static,
|
||||||
|
{
|
||||||
|
fn map_slice(&mut self) -> &[Self::Entry] {
|
||||||
|
self.map.as_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
|
||||||
|
self.map.as_slice_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&mut self) -> &usize {
|
||||||
|
&N
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_mut(&mut self) -> &mut usize {
|
||||||
|
&mut self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T, const N: usize> Deref for ConstMapObserver<'_, T, N> {
|
impl<T, const N: usize> Deref for ConstMapObserver<'_, T, N> {
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
fn deref(&self) -> &[T] {
|
fn deref(&self) -> &[T] {
|
||||||
@ -176,6 +200,7 @@ where
|
|||||||
map: OwnedMutSlice::from(map),
|
map: OwnedMutSlice::from(map),
|
||||||
name: Cow::from(name),
|
name: Cow::from(name),
|
||||||
initial: T::default(),
|
initial: T::default(),
|
||||||
|
size: N,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,6 +213,7 @@ where
|
|||||||
map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N),
|
map: OwnedMutSlice::from_raw_parts_mut(map_ptr, N),
|
||||||
name: Cow::from(name),
|
name: Cow::from(name),
|
||||||
initial: T::default(),
|
initial: T::default(),
|
||||||
|
size: N,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +235,7 @@ where
|
|||||||
map: OwnedMutSlice::from(map),
|
map: OwnedMutSlice::from(map),
|
||||||
name: Cow::from(name),
|
name: Cow::from(name),
|
||||||
initial,
|
initial,
|
||||||
|
size: N,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
executors::ExitKind,
|
executors::ExitKind,
|
||||||
observers::{map::MapObserver, DifferentialObserver, Observer},
|
observers::{map::MapObserver, DifferentialObserver, Observer, VariableLengthMapObserver},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -220,6 +220,7 @@ where
|
|||||||
fn hash_simple(&self) -> u64 {
|
fn hash_simple(&self) -> u64 {
|
||||||
self.base.hash_simple()
|
self.base.hash_simple()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_vec(&self) -> Vec<u8> {
|
fn to_vec(&self) -> Vec<u8> {
|
||||||
self.base.to_vec()
|
self.base.to_vec()
|
||||||
}
|
}
|
||||||
@ -229,6 +230,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<M> VariableLengthMapObserver for HitcountsMapObserver<M>
|
||||||
|
where
|
||||||
|
M: VariableLengthMapObserver + MapObserver<Entry = u8>,
|
||||||
|
{
|
||||||
|
fn map_slice(&mut self) -> &[Self::Entry] {
|
||||||
|
self.base.map_slice()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
|
||||||
|
self.base.map_slice_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&mut self) -> &usize {
|
||||||
|
self.base.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_mut(&mut self) -> &mut usize {
|
||||||
|
self.base.size_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> Truncate for HitcountsMapObserver<M>
|
impl<M> Truncate for HitcountsMapObserver<M>
|
||||||
where
|
where
|
||||||
M: Named + Serialize + serde::de::DeserializeOwned + Truncate,
|
M: Named + Serialize + serde::de::DeserializeOwned + Truncate,
|
||||||
|
@ -385,6 +385,33 @@ pub trait MapObserver:
|
|||||||
fn how_many_set(&self, indexes: &[usize]) -> usize;
|
fn how_many_set(&self, indexes: &[usize]) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The "real" length of the underlying map could change at any point in time.
|
||||||
|
/// Thus, the size of the map should be fetched each time it is used.
|
||||||
|
pub trait VariableLengthMapObserver: MapObserver {
|
||||||
|
/// A mutable slice reference to the map.
|
||||||
|
/// The length of the map gives the maximum allocatable size.
|
||||||
|
fn map_slice(&mut self) -> &[Self::Entry];
|
||||||
|
|
||||||
|
/// A slice reference to the map.
|
||||||
|
/// The length of the map gives the maximum allocatable size.
|
||||||
|
fn map_slice_mut(&mut self) -> &mut [Self::Entry];
|
||||||
|
|
||||||
|
/// A reference to the size of the map.
|
||||||
|
fn size(&mut self) -> &usize;
|
||||||
|
|
||||||
|
/// A mutable reference to the size of the map.
|
||||||
|
fn size_mut(&mut self) -> &mut usize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implementors guarantee the size of the map is constant at any point in time and equals N.
|
||||||
|
pub trait ConstantLengthMapObserver<const N: usize>: MapObserver {
|
||||||
|
/// The size of the map
|
||||||
|
const LENGTH: usize = N;
|
||||||
|
|
||||||
|
/// A mutable slice reference to the map
|
||||||
|
fn map_slice_mut(&mut self) -> &mut [Self::Entry; N];
|
||||||
|
}
|
||||||
|
|
||||||
impl<M> CanTrack for M
|
impl<M> CanTrack for M
|
||||||
where
|
where
|
||||||
M: MapObserver,
|
M: MapObserver,
|
||||||
|
@ -15,7 +15,7 @@ use libafl_bolts::{
|
|||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
observers::{map::MapObserver, Observer},
|
observers::{map::MapObserver, Observer, VariableLengthMapObserver},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -149,6 +149,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> VariableLengthMapObserver for VariableMapObserver<'_, T>
|
||||||
|
where
|
||||||
|
T: PartialEq + Copy + Hash + Serialize + DeserializeOwned + Debug,
|
||||||
|
{
|
||||||
|
fn map_slice(&mut self) -> &[Self::Entry] {
|
||||||
|
self.map.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_slice_mut(&mut self) -> &mut [Self::Entry] {
|
||||||
|
self.map.as_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&mut self) -> &usize {
|
||||||
|
self.size.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_mut(&mut self) -> &mut usize {
|
||||||
|
self.size.as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> Deref for VariableMapObserver<'_, T> {
|
impl<T> Deref for VariableMapObserver<'_, T> {
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
fn deref(&self) -> &[T] {
|
fn deref(&self) -> &[T] {
|
||||||
|
@ -905,6 +905,24 @@ impl<T: Sized> OwnedMutPtr<T> {
|
|||||||
pub unsafe fn from_raw_mut(ptr: *mut T) -> Self {
|
pub unsafe fn from_raw_mut(ptr: *mut T) -> Self {
|
||||||
Self::Ptr(ptr)
|
Self::Ptr(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a pointer to the inner object
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_ptr(&self) -> *const T {
|
||||||
|
match self {
|
||||||
|
OwnedMutPtr::Ptr(ptr) => *ptr,
|
||||||
|
OwnedMutPtr::Owned(owned) => &**owned,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable pointer to the inner object
|
||||||
|
#[must_use]
|
||||||
|
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||||
|
match self {
|
||||||
|
OwnedMutPtr::Ptr(ptr) => *ptr,
|
||||||
|
OwnedMutPtr::Owned(owned) => &mut **owned,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Sized + Serialize> Serialize for OwnedMutPtr<T> {
|
impl<T: Sized + Serialize> Serialize for OwnedMutPtr<T> {
|
||||||
|
@ -239,7 +239,7 @@ fn main() {
|
|||||||
println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS");
|
println!("cargo:rerun-if-env-changed=LLVM_CXXFLAGS");
|
||||||
println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS");
|
println!("cargo:rerun-if-env-changed=LLVM_LDFLAGS");
|
||||||
println!("cargo:rerun-if-env-changed=LLVM_VERSION");
|
println!("cargo:rerun-if-env-changed=LLVM_VERSION");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_DDG_MAP_SIZE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_DDG_MAP_SIZE");
|
||||||
println!("cargo:rerun-if-changed=src/common-llvm.h");
|
println!("cargo:rerun-if-changed=src/common-llvm.h");
|
||||||
@ -312,13 +312,13 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
|
|||||||
};
|
};
|
||||||
let mut cxxflags: Vec<String> = cxxflags.split_whitespace().map(String::from).collect();
|
let mut cxxflags: Vec<String> = cxxflags.split_whitespace().map(String::from).collect();
|
||||||
|
|
||||||
let edges_map_size_in_use: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE")
|
let edge_map_default_size: usize = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
|
||||||
.map_or(Ok(65_536), str::parse)
|
.map_or(Ok(65_536), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
let edges_map_size_max: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_MAX")
|
let edge_map_allocated_size: usize = option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")
|
||||||
.map_or(Ok(2_621_440), str::parse)
|
.map_or(Ok(2_621_440), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
cxxflags.push(format!("-DEDGES_MAP_SIZE_IN_USE={edges_map_size_in_use}"));
|
cxxflags.push(format!("-DEDGES_MAP_DEFAULT_SIZE={edge_map_default_size}"));
|
||||||
|
|
||||||
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
|
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
|
||||||
.map_or(Ok(65_536), str::parse)
|
.map_or(Ok(65_536), str::parse)
|
||||||
@ -348,9 +348,9 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
|
|||||||
pub const CLANGXX_PATH: &str = {clangcpp:?};
|
pub const CLANGXX_PATH: &str = {clangcpp:?};
|
||||||
|
|
||||||
/// The default size of the edges map the fuzzer uses
|
/// The default size of the edges map the fuzzer uses
|
||||||
pub const EDGES_MAP_SIZE_IN_USE: usize = {edges_map_size_in_use};
|
pub const EDGES_MAP_DEFAULT_SIZE: usize = {edge_map_default_size};
|
||||||
/// The real allocated size of the edges map
|
/// The real allocated size of the edges map
|
||||||
pub const EDGES_MAP_SIZE_MAX: usize = {edges_map_size_max};
|
pub const EDGES_MAP_ALLOCATED_SIZE: usize = {edge_map_allocated_size};
|
||||||
|
|
||||||
/// The size of the accounting maps
|
/// The size of the accounting maps
|
||||||
pub const ACCOUNTING_MAP_SIZE: usize = {acc_map_size};
|
pub const ACCOUNTING_MAP_SIZE: usize = {acc_map_size};
|
||||||
|
@ -95,9 +95,9 @@ where
|
|||||||
/// Inserts an edge into CFG.
|
/// Inserts an edge into CFG.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let map_size = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE")
|
let map_size = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
|
||||||
.map_or(Ok(65536), str::parse)
|
.map_or(Ok(65536), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
Self {
|
Self {
|
||||||
edges: (0..map_size).map(|_| None).collect(),
|
edges: (0..map_size).map(|_| None).collect(),
|
||||||
func_to_entry_bb: HashMap::default(),
|
func_to_entry_bb: HashMap::default(),
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
#define MAP_SIZE EDGES_MAP_SIZE_IN_USE
|
#define MAP_SIZE EDGES_MAP_DEFAULT_SIZE
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
#define MAP_SIZE EDGES_MAP_SIZE_IN_USE
|
#define MAP_SIZE EDGES_MAP_DEFAULT_SIZE
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -133,6 +133,11 @@ pub fn generate(
|
|||||||
})
|
})
|
||||||
.header(wrapper_h.display().to_string())
|
.header(wrapper_h.display().to_string())
|
||||||
.clang_args(clang_args)
|
.clang_args(clang_args)
|
||||||
|
.allowlist_var("libafl_dump_core_hook")
|
||||||
|
.allowlist_var("libafl_force_dfl")
|
||||||
|
.allowlist_var("mmap_next_start")
|
||||||
|
.allowlist_var("guest_base")
|
||||||
|
.allowlist_var("exec_path")
|
||||||
.allowlist_type("target_ulong")
|
.allowlist_type("target_ulong")
|
||||||
.allowlist_type("target_long")
|
.allowlist_type("target_long")
|
||||||
.allowlist_type("CPUState")
|
.allowlist_type("CPUState")
|
||||||
|
@ -2,21 +2,11 @@ use core::{slice::from_raw_parts, str::from_utf8_unchecked};
|
|||||||
|
|
||||||
use libc::{c_char, strlen};
|
use libc::{c_char, strlen};
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
use paste::paste;
|
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python};
|
use pyo3::{pyclass, pymethods, IntoPy, PyObject, Python};
|
||||||
use strum_macros::EnumIter;
|
use strum_macros::EnumIter;
|
||||||
|
|
||||||
use crate::{extern_c_checked, libafl_mapinfo, GuestAddr, MmapPerms};
|
use crate::{libafl_mapinfo, GuestAddr, MmapPerms};
|
||||||
|
|
||||||
extern_c_checked! {
|
|
||||||
pub static exec_path: *const u8;
|
|
||||||
pub static guest_base: usize;
|
|
||||||
pub static mut mmap_next_start: GuestAddr;
|
|
||||||
|
|
||||||
pub static mut libafl_dump_core_hook: unsafe extern "C" fn(i32);
|
|
||||||
pub static mut libafl_force_dfl: i32;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)]
|
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)]
|
||||||
#[repr(i32)]
|
#[repr(i32)]
|
||||||
|
@ -12525,6 +12525,9 @@ impl Default for IntervalTreeNode {
|
|||||||
pub type IntervalTreeRoot = RBRootLeftCached;
|
pub type IntervalTreeRoot = RBRootLeftCached;
|
||||||
pub type abi_ulong = target_ulong;
|
pub type abi_ulong = target_ulong;
|
||||||
pub type abi_long = target_long;
|
pub type abi_long = target_long;
|
||||||
|
extern "C" {
|
||||||
|
pub static mut guest_base: usize;
|
||||||
|
}
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#[doc = " --- Begin LibAFL code ---"]
|
#[doc = " --- Begin LibAFL code ---"]
|
||||||
pub fn pageflags_get_root() -> *mut IntervalTreeRoot;
|
pub fn pageflags_get_root() -> *mut IntervalTreeRoot;
|
||||||
@ -13274,6 +13277,12 @@ impl Default for TranslationBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub static mut exec_path: *mut ::std::os::raw::c_char;
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub static mut mmap_next_start: abi_ulong;
|
||||||
|
}
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn target_mprotect(
|
pub fn target_mprotect(
|
||||||
start: abi_ulong,
|
start: abi_ulong,
|
||||||
@ -13757,6 +13766,13 @@ impl Default for libafl_mapinfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub static mut libafl_dump_core_hook:
|
||||||
|
::std::option::Option<unsafe extern "C" fn(host_sig: ::std::os::raw::c_int)>;
|
||||||
|
}
|
||||||
|
extern "C" {
|
||||||
|
pub static mut libafl_force_dfl: ::std::os::raw::c_int;
|
||||||
|
}
|
||||||
extern "C" {
|
extern "C" {
|
||||||
pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int);
|
pub fn libafl_dump_core_exec(signal: ::std::os::raw::c_int);
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@ use crate::qemu::{
|
|||||||
};
|
};
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
use crate::qemu::{
|
use crate::qemu::{
|
||||||
CrashHookClosure, PostSyscallHookClosure, PostSyscallHookFn, PreSyscallHookClosure,
|
CrashHookClosure, CrashHookFn, PostSyscallHookClosure, PostSyscallHookFn,
|
||||||
PreSyscallHookFn,
|
PreSyscallHookClosure, PreSyscallHookFn,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper,
|
cpu_run_post_exec_hook_wrapper, cpu_run_pre_exec_hook_wrapper,
|
||||||
@ -68,9 +68,6 @@ macro_rules! hook_to_repr {
|
|||||||
|
|
||||||
static mut EMULATOR_TOOLS: *mut () = ptr::null_mut();
|
static mut EMULATOR_TOOLS: *mut () = ptr::null_mut();
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
|
||||||
static mut CRASH_HOOKS: Vec<HookRepr> = vec![];
|
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
pub extern "C" fn crash_hook_wrapper<ET, S>(target_sig: i32)
|
pub extern "C" fn crash_hook_wrapper<ET, S>(target_sig: i32)
|
||||||
where
|
where
|
||||||
@ -78,17 +75,17 @@ where
|
|||||||
S: Unpin + UsesInput,
|
S: Unpin + UsesInput,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let hooks = Qemu::get().unwrap().hooks();
|
let emulator_modules = EmulatorModules::<ET, S>::emulator_modules_mut().unwrap();
|
||||||
|
|
||||||
for crash_hook in &mut (*addr_of_mut!(CRASH_HOOKS)) {
|
for crash_hook in &mut (*addr_of_mut!(emulator_modules.hooks.crash_hooks)) {
|
||||||
match crash_hook {
|
match crash_hook {
|
||||||
HookRepr::Function(ptr) => {
|
HookRepr::Function(ptr) => {
|
||||||
let func: fn(QemuHooks, i32) = transmute(*ptr);
|
let func: CrashHookFn<ET, S> = transmute(*ptr);
|
||||||
func(hooks, target_sig);
|
func(emulator_modules, target_sig);
|
||||||
}
|
}
|
||||||
HookRepr::Closure(ptr) => {
|
HookRepr::Closure(ptr) => {
|
||||||
let func: &mut Box<dyn FnMut(QemuHooks, i32)> = transmute(ptr);
|
let func: &mut CrashHookClosure<ET, S> = transmute(ptr);
|
||||||
func(hooks, target_sig);
|
func(emulator_modules, target_sig);
|
||||||
}
|
}
|
||||||
HookRepr::Empty => (),
|
HookRepr::Empty => (),
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use libafl::{
|
|||||||
executors::{
|
executors::{
|
||||||
hooks::inprocess::InProcessExecutorHandlerData,
|
hooks::inprocess::InProcessExecutorHandlerData,
|
||||||
inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks},
|
inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks},
|
||||||
|
inprocess_fork::stateful::StatefulInProcessForkExecutor,
|
||||||
Executor, ExitKind, HasObservers,
|
Executor, ExitKind, HasObservers,
|
||||||
},
|
},
|
||||||
feedbacks::Feedback,
|
feedbacks::Feedback,
|
||||||
@ -25,10 +26,6 @@ use libafl::{
|
|||||||
Error, ExecutionProcessor, HasScheduler,
|
Error, ExecutionProcessor, HasScheduler,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
use libafl::{
|
|
||||||
events::EventManager, executors::InProcessForkExecutor, state::HasLastReportTime, HasMetadata,
|
|
||||||
};
|
|
||||||
#[cfg(feature = "fork")]
|
|
||||||
use libafl_bolts::shmem::ShMemProvider;
|
use libafl_bolts::shmem::ShMemProvider;
|
||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
os::unix_signals::{ucontext_t, Signal},
|
os::unix_signals::{ucontext_t, Signal},
|
||||||
@ -278,20 +275,21 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> =
|
||||||
|
StatefulInProcessForkExecutor<'a, H, OT, S, SP, Emulator<CM, ED, ET, S, SM>, EM, Z>;
|
||||||
|
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
||||||
where
|
where
|
||||||
CM: CommandManager<ED, ET, S, SM>,
|
CM: CommandManager<ED, ET, S, SM>,
|
||||||
EM: UsesState<State = S>,
|
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: UsesInput,
|
S: UsesInput,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
Z: UsesState<State = S>,
|
Z: UsesState<State = S>,
|
||||||
{
|
{
|
||||||
inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>,
|
inner: QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>,
|
||||||
emulator: Emulator<CM, ED, ET, S, SM>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
@ -302,7 +300,7 @@ where
|
|||||||
EM: UsesState<State = S>,
|
EM: UsesState<State = S>,
|
||||||
ED: Debug,
|
ED: Debug,
|
||||||
ET: EmulatorModuleTuple<S> + Debug,
|
ET: EmulatorModuleTuple<S> + Debug,
|
||||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
OT: ObserversTuple<S::Input, S> + Debug,
|
||||||
S: UsesInput + Debug,
|
S: UsesInput + Debug,
|
||||||
SM: Debug,
|
SM: Debug,
|
||||||
@ -312,7 +310,7 @@ where
|
|||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("QemuForkExecutor")
|
f.debug_struct("QemuForkExecutor")
|
||||||
.field("inner", &self.inner)
|
.field("inner", &self.inner)
|
||||||
.field("emulator", &self.emulator)
|
.field("emulator", &self.inner.exposed_executor_state)
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,7 +322,7 @@ where
|
|||||||
CM: CommandManager<ED, ET, S, SM>,
|
CM: CommandManager<ED, ET, S, SM>,
|
||||||
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: State + HasSolutions,
|
S: State + HasSolutions,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -344,8 +342,9 @@ where
|
|||||||
assert!(!ET::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded");
|
assert!(!ET::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded");
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
inner: InProcessForkExecutor::new(
|
inner: StatefulInProcessForkExecutor::new(
|
||||||
harness_fn,
|
harness_fn,
|
||||||
|
emulator,
|
||||||
observers,
|
observers,
|
||||||
fuzzer,
|
fuzzer,
|
||||||
state,
|
state,
|
||||||
@ -353,39 +352,41 @@ where
|
|||||||
timeout,
|
timeout,
|
||||||
shmem_provider,
|
shmem_provider,
|
||||||
)?,
|
)?,
|
||||||
emulator,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> &InProcessForkExecutor<'a, H, OT, S, SP, EM, Z> {
|
pub fn inner(&self) -> &QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
|
||||||
&self.inner
|
&self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, OT, S, SP, EM, Z> {
|
pub fn inner_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> &mut QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
|
||||||
&mut self.inner
|
&mut self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emulator(&self) -> &Emulator<CM, ED, ET, S, SM> {
|
pub fn emulator(&self) -> &Emulator<CM, ED, ET, S, SM> {
|
||||||
&self.emulator
|
&self.inner.exposed_executor_state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emulator_mut(&mut self) -> &Emulator<CM, ED, ET, S, SM> {
|
pub fn emulator_mut(&mut self) -> &Emulator<CM, ED, ET, S, SM> {
|
||||||
&mut self.emulator
|
&mut self.inner.exposed_executor_state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fork")]
|
#[cfg(feature = "fork")]
|
||||||
impl<'a, CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor<EM, Z>
|
impl<CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor<EM, Z>
|
||||||
for QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
||||||
where
|
where
|
||||||
CM: CommandManager<ED, ET, S, SM>,
|
CM: CommandManager<ED, ET, S, SM>,
|
||||||
EM: EventManager<InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>, Z, State = S>,
|
ED: EmulatorDriver<CM, ET, S, SM>,
|
||||||
H: FnMut(&S::Input) -> ExitKind,
|
EM: EventFirer<State = S> + EventRestarter<State = S>,
|
||||||
S: Unpin + State + HasMetadata + HasExecutions + HasLastReportTime + HasCorpus + HasSolutions,
|
|
||||||
OT: ObserversTuple<S::Input, S> + Debug,
|
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
SP: ShMemProvider,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind,
|
||||||
OF: Feedback<EM, S::Input, OT, S>,
|
OF: Feedback<EM, S::Input, OT, S>,
|
||||||
|
OT: ObserversTuple<S::Input, S> + Debug,
|
||||||
|
S: State + HasExecutions + Unpin,
|
||||||
|
SP: ShMemProvider,
|
||||||
Z: HasObjective<Objective = OF, State = S>,
|
Z: HasObjective<Objective = OF, State = S>,
|
||||||
{
|
{
|
||||||
fn run_target(
|
fn run_target(
|
||||||
@ -395,7 +396,20 @@ where
|
|||||||
mgr: &mut EM,
|
mgr: &mut EM,
|
||||||
input: &Self::Input,
|
input: &Self::Input,
|
||||||
) -> Result<ExitKind, Error> {
|
) -> Result<ExitKind, Error> {
|
||||||
self.inner.run_target(fuzzer, state, mgr, input)
|
self.inner.exposed_executor_state.first_exec(state);
|
||||||
|
|
||||||
|
self.inner.exposed_executor_state.pre_exec(state, input);
|
||||||
|
|
||||||
|
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
|
||||||
|
|
||||||
|
self.inner.exposed_executor_state.post_exec(
|
||||||
|
input,
|
||||||
|
&mut *self.inner.inner.observers_mut(),
|
||||||
|
state,
|
||||||
|
&mut exit_kind,
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(exit_kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,9 +418,8 @@ impl<CM, ED, EM, ET, H, OT, S, SM, SP, Z> UsesState
|
|||||||
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
|
||||||
where
|
where
|
||||||
CM: CommandManager<ED, ET, S, SM>,
|
CM: CommandManager<ED, ET, S, SM>,
|
||||||
EM: UsesState<State = S>,
|
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: State,
|
S: State,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
@ -422,7 +435,7 @@ where
|
|||||||
CM: CommandManager<ED, ET, S, SM>,
|
CM: CommandManager<ED, ET, S, SM>,
|
||||||
EM: UsesState<State = S>,
|
EM: UsesState<State = S>,
|
||||||
ET: EmulatorModuleTuple<S>,
|
ET: EmulatorModuleTuple<S>,
|
||||||
H: FnMut(&S::Input) -> ExitKind + ?Sized,
|
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + ?Sized,
|
||||||
OT: ObserversTuple<S::Input, S>,
|
OT: ObserversTuple<S::Input, S>,
|
||||||
S: State,
|
S: State,
|
||||||
SP: ShMemProvider,
|
SP: ShMemProvider,
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
use std::{cell::UnsafeCell, cmp::max, fmt::Debug};
|
use std::{cell::UnsafeCell, cmp::max, fmt::Debug, ptr, ptr::addr_of};
|
||||||
|
|
||||||
use hashbrown::{hash_map::Entry, HashMap};
|
use hashbrown::{hash_map::Entry, HashMap};
|
||||||
use libafl::{inputs::UsesInput, HasMetadata};
|
use libafl::{inputs::UsesInput, observers::VariableLengthMapObserver, HasMetadata};
|
||||||
|
use libafl_bolts::Error;
|
||||||
use libafl_qemu_sys::GuestAddr;
|
use libafl_qemu_sys::GuestAddr;
|
||||||
#[cfg(emulation_mode = "systemmode")]
|
#[cfg(emulation_mode = "systemmode")]
|
||||||
use libafl_qemu_sys::GuestPhysAddr;
|
use libafl_qemu_sys::GuestPhysAddr;
|
||||||
pub use libafl_targets::{
|
use libafl_targets::EDGES_MAP;
|
||||||
edges_map_mut_ptr, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_SIZE_MAX,
|
|
||||||
MAX_EDGES_FOUND,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -20,6 +18,18 @@ use crate::{
|
|||||||
qemu::Hook,
|
qemu::Hook,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut LIBAFL_QEMU_EDGES_MAP_PTR: *mut u8 = ptr::null_mut();
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut LIBAFL_QEMU_EDGES_MAP_SIZE_PTR: *mut usize = ptr::null_mut();
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut LIBAFL_QEMU_EDGES_MAP_ALLOCATED_SIZE: usize = 0;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
static mut LIBAFL_QEMU_EDGES_MAP_MASK_MAX: usize = 0;
|
||||||
|
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(not(feature = "serdeany_autoreg"), miri),
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
allow(clippy::unsafe_derive_deserialize)
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
@ -100,7 +110,7 @@ pub struct EdgeCoverageFullVariant;
|
|||||||
pub type StdEdgeCoverageFullModule =
|
pub type StdEdgeCoverageFullModule =
|
||||||
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>;
|
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>;
|
||||||
pub type StdEdgeCoverageFullModuleBuilder =
|
pub type StdEdgeCoverageFullModuleBuilder =
|
||||||
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant>;
|
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageFullVariant, false>;
|
||||||
|
|
||||||
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageFullVariant {
|
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageFullVariant {
|
||||||
fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
|
fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
|
||||||
@ -193,7 +203,7 @@ pub struct EdgeCoverageClassicVariant;
|
|||||||
pub type StdEdgeCoverageClassicModule =
|
pub type StdEdgeCoverageClassicModule =
|
||||||
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>;
|
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>;
|
||||||
pub type StdEdgeCoverageClassicModuleBuilder =
|
pub type StdEdgeCoverageClassicModuleBuilder =
|
||||||
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant>;
|
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageClassicVariant, false>;
|
||||||
|
|
||||||
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageClassicVariant {
|
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageClassicVariant {
|
||||||
const DO_SIDE_EFFECTS: bool = false;
|
const DO_SIDE_EFFECTS: bool = false;
|
||||||
@ -293,7 +303,7 @@ pub struct EdgeCoverageChildVariant;
|
|||||||
pub type StdEdgeCoverageChildModule =
|
pub type StdEdgeCoverageChildModule =
|
||||||
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>;
|
EdgeCoverageModule<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>;
|
||||||
pub type StdEdgeCoverageChildModuleBuilder =
|
pub type StdEdgeCoverageChildModuleBuilder =
|
||||||
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant>;
|
EdgeCoverageModuleBuilder<StdAddressFilter, StdPageFilter, EdgeCoverageChildVariant, false>;
|
||||||
|
|
||||||
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageChildVariant {
|
impl<AF, PF> EdgeCoverageVariant<AF, PF> for EdgeCoverageChildVariant {
|
||||||
const DO_SIDE_EFFECTS: bool = false;
|
const DO_SIDE_EFFECTS: bool = false;
|
||||||
@ -339,13 +349,13 @@ impl Default for StdEdgeCoverageChildModuleBuilder {
|
|||||||
|
|
||||||
impl StdEdgeCoverageChildModule {
|
impl StdEdgeCoverageChildModule {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn builder() -> StdEdgeCoverageClassicModuleBuilder {
|
pub fn builder() -> StdEdgeCoverageChildModuleBuilder {
|
||||||
EdgeCoverageModuleBuilder::default()
|
EdgeCoverageModuleBuilder::default().jit(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EdgeCoverageModuleBuilder<AF, PF, V> {
|
pub struct EdgeCoverageModuleBuilder<AF, PF, V, const IS_INITIALIZED: bool> {
|
||||||
variant: V,
|
variant: V,
|
||||||
address_filter: AF,
|
address_filter: AF,
|
||||||
page_filter: PF,
|
page_filter: PF,
|
||||||
@ -364,8 +374,20 @@ pub struct EdgeCoverageModule<AF, PF, V> {
|
|||||||
use_jit: bool,
|
use_jit: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V, true> {
|
||||||
pub fn new(
|
pub fn build(self) -> Result<EdgeCoverageModule<AF, PF, V>, Error> {
|
||||||
|
Ok(EdgeCoverageModule::new(
|
||||||
|
self.address_filter,
|
||||||
|
self.page_filter,
|
||||||
|
self.variant,
|
||||||
|
self.use_hitcounts,
|
||||||
|
self.use_jit,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<AF, PF, V, const IS_INITIALIZED: bool> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
|
||||||
|
fn new(
|
||||||
variant: V,
|
variant: V,
|
||||||
address_filter: AF,
|
address_filter: AF,
|
||||||
page_filter: PF,
|
page_filter: PF,
|
||||||
@ -381,17 +403,32 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self) -> EdgeCoverageModule<AF, PF, V> {
|
#[must_use]
|
||||||
EdgeCoverageModule::new(
|
pub fn map_observer<O>(self, map_observer: &mut O) -> EdgeCoverageModuleBuilder<AF, PF, V, true>
|
||||||
|
where
|
||||||
|
O: VariableLengthMapObserver,
|
||||||
|
{
|
||||||
|
let map_ptr = map_observer.map_slice_mut().as_mut_ptr() as *mut u8;
|
||||||
|
let map_max_size = map_observer.map_slice_mut().len();
|
||||||
|
let size_ptr = map_observer.as_mut().size_mut() as *mut usize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
LIBAFL_QEMU_EDGES_MAP_PTR = map_ptr;
|
||||||
|
LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = size_ptr;
|
||||||
|
LIBAFL_QEMU_EDGES_MAP_ALLOCATED_SIZE = map_max_size;
|
||||||
|
LIBAFL_QEMU_EDGES_MAP_MASK_MAX = map_max_size - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EdgeCoverageModuleBuilder::<AF, PF, V, true>::new(
|
||||||
|
self.variant,
|
||||||
self.address_filter,
|
self.address_filter,
|
||||||
self.page_filter,
|
self.page_filter,
|
||||||
self.variant,
|
|
||||||
self.use_hitcounts,
|
self.use_hitcounts,
|
||||||
self.use_jit,
|
self.use_jit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variant<V2>(self, variant: V2) -> EdgeCoverageModuleBuilder<AF, PF, V2> {
|
pub fn variant<V2>(self, variant: V2) -> EdgeCoverageModuleBuilder<AF, PF, V2, IS_INITIALIZED> {
|
||||||
EdgeCoverageModuleBuilder::new(
|
EdgeCoverageModuleBuilder::new(
|
||||||
variant,
|
variant,
|
||||||
self.address_filter,
|
self.address_filter,
|
||||||
@ -401,7 +438,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address_filter<AF2>(self, address_filter: AF2) -> EdgeCoverageModuleBuilder<AF2, PF, V> {
|
pub fn address_filter<AF2>(
|
||||||
|
self,
|
||||||
|
address_filter: AF2,
|
||||||
|
) -> EdgeCoverageModuleBuilder<AF2, PF, V, IS_INITIALIZED> {
|
||||||
EdgeCoverageModuleBuilder::new(
|
EdgeCoverageModuleBuilder::new(
|
||||||
self.variant,
|
self.variant,
|
||||||
address_filter,
|
address_filter,
|
||||||
@ -411,7 +451,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_filter<PF2>(self, page_filter: PF2) -> EdgeCoverageModuleBuilder<AF, PF2, V> {
|
pub fn page_filter<PF2>(
|
||||||
|
self,
|
||||||
|
page_filter: PF2,
|
||||||
|
) -> EdgeCoverageModuleBuilder<AF, PF2, V, IS_INITIALIZED> {
|
||||||
EdgeCoverageModuleBuilder::new(
|
EdgeCoverageModuleBuilder::new(
|
||||||
self.variant,
|
self.variant,
|
||||||
self.address_filter,
|
self.address_filter,
|
||||||
@ -422,7 +465,10 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn hitcounts(self, use_hitcounts: bool) -> EdgeCoverageModuleBuilder<AF, PF, V> {
|
pub fn hitcounts(
|
||||||
|
self,
|
||||||
|
use_hitcounts: bool,
|
||||||
|
) -> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
|
||||||
EdgeCoverageModuleBuilder::new(
|
EdgeCoverageModuleBuilder::new(
|
||||||
self.variant,
|
self.variant,
|
||||||
self.address_filter,
|
self.address_filter,
|
||||||
@ -433,7 +479,7 @@ impl<AF, PF, V> EdgeCoverageModuleBuilder<AF, PF, V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder<AF, PF, V> {
|
pub fn jit(self, use_jit: bool) -> EdgeCoverageModuleBuilder<AF, PF, V, IS_INITIALIZED> {
|
||||||
EdgeCoverageModuleBuilder::new(
|
EdgeCoverageModuleBuilder::new(
|
||||||
self.variant,
|
self.variant,
|
||||||
self.address_filter,
|
self.address_filter,
|
||||||
@ -548,10 +594,15 @@ where
|
|||||||
S: Unpin + UsesInput + HasMetadata,
|
S: Unpin + UsesInput + HasMetadata,
|
||||||
V: EdgeCoverageVariant<AF, PF>,
|
V: EdgeCoverageVariant<AF, PF>,
|
||||||
{
|
{
|
||||||
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
||||||
|
unsafe {
|
||||||
|
assert!(LIBAFL_QEMU_EDGES_MAP_MASK_MAX > 0);
|
||||||
|
assert_ne!(*addr_of!(LIBAFL_QEMU_EDGES_MAP_SIZE_PTR), ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
{
|
{
|
||||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
if !module.must_instrument(src) && !module.must_instrument(dest) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -563,29 +614,30 @@ where
|
|||||||
.current_cpu()
|
.current_cpu()
|
||||||
.and_then(|cpu| cpu.current_paging_id());
|
.and_then(|cpu| cpu.current_paging_id());
|
||||||
|
|
||||||
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) {
|
if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = state.expect("The gen_unique_edge_ids hook works only for in-process fuzzing");
|
let state = state.expect("The gen_unique_edge_ids hook works only for in-process fuzzing");
|
||||||
let meta = state.metadata_or_insert_with(QemuEdgesMapMetadata::new);
|
let meta = state.metadata_or_insert_with(QemuEdgesMapMetadata::new);
|
||||||
|
|
||||||
match meta.map.entry((src, dest)) {
|
match meta.map.entry((src, dest)) {
|
||||||
Entry::Occupied(e) => {
|
Entry::Occupied(e) => {
|
||||||
let id = *e.get();
|
let id = *e.get();
|
||||||
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MAX_EDGES_FOUND = max(MAX_EDGES_FOUND, nxt);
|
let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
|
||||||
|
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = max(*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR, nxt);
|
||||||
}
|
}
|
||||||
Some(id)
|
Some(id)
|
||||||
}
|
}
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
let id = meta.current_id;
|
let id = meta.current_id;
|
||||||
e.insert(id);
|
e.insert(id);
|
||||||
meta.current_id = (id + 1) & (EDGES_MAP_SIZE_MAX as u64 - 1);
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MAX_EDGES_FOUND = meta.current_id as usize;
|
meta.current_id = (id + 1) & (LIBAFL_QEMU_EDGES_MAP_MASK_MAX as u64);
|
||||||
|
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = meta.current_id as usize;
|
||||||
}
|
}
|
||||||
// GuestAddress is u32 for 32 bit guests
|
// GuestAddress is u32 for 32 bit guests
|
||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
@ -624,9 +676,9 @@ where
|
|||||||
S: Unpin + UsesInput + HasMetadata,
|
S: Unpin + UsesInput + HasMetadata,
|
||||||
V: EdgeCoverageVariant<AF, PF>,
|
V: EdgeCoverageVariant<AF, PF>,
|
||||||
{
|
{
|
||||||
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
if !h.must_instrument(src) && !h.must_instrument(dest) {
|
if !module.must_instrument(src) && !module.must_instrument(dest) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,29 +689,31 @@ where
|
|||||||
.current_cpu()
|
.current_cpu()
|
||||||
.and_then(|cpu| cpu.current_paging_id());
|
.and_then(|cpu| cpu.current_paging_id());
|
||||||
|
|
||||||
if !h.must_instrument(src, paging_id) && !h.must_instrument(dest, paging_id) {
|
if !module.must_instrument(src, paging_id) && !module.must_instrument(dest, paging_id) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let id = hash_me(src as u64) ^ hash_me(dest as u64);
|
let id = hash_me(src as u64) ^ hash_me(dest as u64);
|
||||||
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MAX_EDGES_FOUND = nxt;
|
let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
|
||||||
|
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = nxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GuestAddress is u32 for 32 bit guests
|
// GuestAddress is u32 for 32 bit guests
|
||||||
#[allow(clippy::unnecessary_cast)]
|
#[allow(clippy::unnecessary_cast)]
|
||||||
Some(id)
|
Some(id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently.
|
/// Increases id at `EDGES_MAP_PTR` - potentially racey if called concurrently.
|
||||||
pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
|
pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
let ptr = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize);
|
||||||
*ptr = (*ptr).wrapping_add(1);
|
*ptr = (*ptr).wrapping_add(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -669,7 +723,7 @@ pub unsafe extern "C" fn trace_edge_hitcount_ptr(_: *const (), id: u64) {
|
|||||||
/// Worst case we set the byte to 1 multiple times.
|
/// Worst case we set the byte to 1 multiple times.
|
||||||
pub unsafe extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) {
|
pub unsafe extern "C" fn trace_edge_single_ptr(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = EDGES_MAP_PTR.add(id as usize);
|
let ptr = LIBAFL_QEMU_EDGES_MAP_PTR.add(id as usize);
|
||||||
*ptr = 1;
|
*ptr = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -687,10 +741,11 @@ where
|
|||||||
S: Unpin + UsesInput + HasMetadata,
|
S: Unpin + UsesInput + HasMetadata,
|
||||||
V: EdgeCoverageVariant<AF, PF>,
|
V: EdgeCoverageVariant<AF, PF>,
|
||||||
{
|
{
|
||||||
if let Some(h) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
// first check if we should filter
|
||||||
|
if let Some(module) = emulator_modules.get::<EdgeCoverageModule<AF, PF, V>>() {
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
{
|
{
|
||||||
if !h.must_instrument(pc) {
|
if !module.must_instrument(pc) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -701,17 +756,17 @@ where
|
|||||||
.current_cpu()
|
.current_cpu()
|
||||||
.and_then(|cpu| cpu.current_paging_id());
|
.and_then(|cpu| cpu.current_paging_id());
|
||||||
|
|
||||||
if !h.must_instrument(pc, page_id) {
|
if !module.must_instrument(pc, page_id) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = hash_me(pc as u64);
|
let id = hash_me(pc as u64);
|
||||||
let nxt = (id as usize + 1) & (EDGES_MAP_SIZE_MAX - 1);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
MAX_EDGES_FOUND = nxt;
|
let nxt = (id as usize + 1) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
|
||||||
|
*LIBAFL_QEMU_EDGES_MAP_SIZE_PTR = nxt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// GuestAddress is u32 for 32 bit guests
|
// GuestAddress is u32 for 32 bit guests
|
||||||
@ -724,8 +779,8 @@ where
|
|||||||
pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
|
pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
PREV_LOC.with(|prev_loc| {
|
PREV_LOC.with(|prev_loc| {
|
||||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1);
|
let x = ((*prev_loc.get() ^ id) as usize) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
|
||||||
let entry = EDGES_MAP_PTR.add(x);
|
let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x);
|
||||||
*entry = (*entry).wrapping_add(1);
|
*entry = (*entry).wrapping_add(1);
|
||||||
*prev_loc.get() = id.overflowing_shr(1).0;
|
*prev_loc.get() = id.overflowing_shr(1).0;
|
||||||
});
|
});
|
||||||
@ -737,8 +792,8 @@ pub unsafe extern "C" fn trace_block_transition_hitcount(_: *const (), id: u64)
|
|||||||
pub unsafe extern "C" fn trace_block_transition_single(_: *const (), id: u64) {
|
pub unsafe extern "C" fn trace_block_transition_single(_: *const (), id: u64) {
|
||||||
unsafe {
|
unsafe {
|
||||||
PREV_LOC.with(|prev_loc| {
|
PREV_LOC.with(|prev_loc| {
|
||||||
let x = ((*prev_loc.get() ^ id) as usize) & (EDGES_MAP_SIZE_MAX - 1);
|
let x = ((*prev_loc.get() ^ id) as usize) & LIBAFL_QEMU_EDGES_MAP_MASK_MAX;
|
||||||
let entry = EDGES_MAP_PTR.add(x);
|
let entry = LIBAFL_QEMU_EDGES_MAP_PTR.add(x);
|
||||||
*entry = 1;
|
*entry = 1;
|
||||||
*prev_loc.get() = id.overflowing_shr(1).0;
|
*prev_loc.get() = id.overflowing_shr(1).0;
|
||||||
});
|
});
|
||||||
|
@ -146,8 +146,8 @@ impl<F> AsanGuestModule<F> {
|
|||||||
|
|
||||||
impl AsanGuestModule<StdAddressFilter> {
|
impl AsanGuestModule<StdAddressFilter> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn default(emu: &Qemu, asan: String) -> Self {
|
pub fn default(qemu: Qemu, asan: String) -> Self {
|
||||||
Self::new(emu, asan, StdAddressFilter::default())
|
Self::new(qemu, asan, StdAddressFilter::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,12 +156,12 @@ where
|
|||||||
F: AddressFilter,
|
F: AddressFilter,
|
||||||
{
|
{
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(emu: &Qemu, asan: String, filter: F) -> Self {
|
pub fn new(qemu: Qemu, asan: String, filter: F) -> Self {
|
||||||
for mapping in emu.mappings() {
|
for mapping in qemu.mappings() {
|
||||||
println!("mapping: {mapping:#?}");
|
println!("mapping: {mapping:#?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mappings = emu
|
let mappings = qemu
|
||||||
.mappings()
|
.mappings()
|
||||||
.map(|m| QemuAsanGuestMapping::from(&m))
|
.map(|m| QemuAsanGuestMapping::from(&m))
|
||||||
.collect::<Vec<QemuAsanGuestMapping>>();
|
.collect::<Vec<QemuAsanGuestMapping>>();
|
||||||
|
@ -34,7 +34,7 @@ use crate::{
|
|||||||
pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
|
pub const SNAPSHOT_PAGE_SIZE: usize = 4096;
|
||||||
pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
|
pub const SNAPSHOT_PAGE_MASK: GuestAddr = !(SNAPSHOT_PAGE_SIZE as GuestAddr - 1);
|
||||||
|
|
||||||
pub type StopExecutionCallback = Box<dyn FnMut(&mut SnapshotModule, &Qemu)>;
|
pub type StopExecutionCallback = Box<dyn FnMut(&mut SnapshotModule, Qemu)>;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SnapshotPageInfo {
|
pub struct SnapshotPageInfo {
|
||||||
@ -510,7 +510,7 @@ impl SnapshotModule {
|
|||||||
if self.mmap_limit != 0 && total_size > self.mmap_limit {
|
if self.mmap_limit != 0 && total_size > self.mmap_limit {
|
||||||
let mut cb = self.stop_execution.take().unwrap();
|
let mut cb = self.stop_execution.take().unwrap();
|
||||||
let qemu = Qemu::get().unwrap();
|
let qemu = Qemu::get().unwrap();
|
||||||
cb(self, &qemu);
|
cb(self, qemu);
|
||||||
self.stop_execution = Some(cb);
|
self.stop_execution = Some(cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -712,6 +712,8 @@ create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId);
|
|||||||
|
|
||||||
// Crash hook wrappers
|
// Crash hook wrappers
|
||||||
#[cfg(emulation_mode = "usermode")]
|
#[cfg(emulation_mode = "usermode")]
|
||||||
|
pub type CrashHookFn<ET, S> = fn(&mut EmulatorModules<ET, S>, i32);
|
||||||
|
#[cfg(emulation_mode = "usermode")]
|
||||||
pub type CrashHookClosure<ET, S> = Box<dyn FnMut(&mut EmulatorModules<ET, S>, i32)>;
|
pub type CrashHookClosure<ET, S> = Box<dyn FnMut(&mut EmulatorModules<ET, S>, i32)>;
|
||||||
|
|
||||||
/// The thin wrapper around QEMU hooks.
|
/// The thin wrapper around QEMU hooks.
|
||||||
@ -1035,7 +1037,7 @@ impl QemuHooks {
|
|||||||
#[allow(clippy::unused_self)]
|
#[allow(clippy::unused_self)]
|
||||||
pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) {
|
pub(crate) fn set_crash_hook(self, callback: extern "C" fn(i32)) {
|
||||||
unsafe {
|
unsafe {
|
||||||
libafl_dump_core_hook = callback;
|
libafl_dump_core_hook = Some(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,10 +155,10 @@ static mut GDB_COMMANDS: Vec<Box<FatPtr>> = Vec::new();
|
|||||||
|
|
||||||
unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool {
|
unsafe extern "C" fn gdb_cmd(data: *mut c_void, buf: *mut u8, len: usize) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(&Qemu, &'r str) -> bool>);
|
let closure = &mut *(data as *mut Box<dyn for<'r> FnMut(Qemu, &'r str) -> bool>);
|
||||||
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
|
let cmd = std::str::from_utf8_unchecked(std::slice::from_raw_parts(buf, len));
|
||||||
let qemu = Qemu::get_unchecked();
|
let qemu = Qemu::get_unchecked();
|
||||||
closure(&qemu, cmd)
|
closure(qemu, cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts,
|
intrinsics::copy_nonoverlapping, mem::MaybeUninit, slice::from_raw_parts_mut,
|
||||||
str::from_utf8_unchecked,
|
str::from_utf8_unchecked_mut,
|
||||||
};
|
};
|
||||||
|
|
||||||
use libafl_qemu_sys::{
|
use libafl_qemu_sys::{
|
||||||
@ -9,7 +9,7 @@ use libafl_qemu_sys::{
|
|||||||
pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot,
|
pageflags_get_root, read_self_maps, GuestAddr, GuestUsize, IntervalTreeNode, IntervalTreeRoot,
|
||||||
MapInfo, MmapPerms, VerifyAccess,
|
MapInfo, MmapPerms, VerifyAccess,
|
||||||
};
|
};
|
||||||
use libc::{c_char, c_int, strlen};
|
use libc::{c_char, c_int, c_uchar, strlen};
|
||||||
#[cfg(feature = "python")]
|
#[cfg(feature = "python")]
|
||||||
use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python};
|
use pyo3::{pyclass, pymethods, IntoPy, PyObject, PyRef, PyRefMut, Python};
|
||||||
|
|
||||||
@ -139,8 +139,8 @@ impl Qemu {
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn binary_path<'a>(&self) -> &'a str {
|
pub fn binary_path<'a>(&self) -> &'a str {
|
||||||
unsafe {
|
unsafe {
|
||||||
from_utf8_unchecked(from_raw_parts(
|
from_utf8_unchecked_mut(from_raw_parts_mut(
|
||||||
exec_path,
|
exec_path as *mut c_uchar,
|
||||||
strlen(exec_path as *const c_char),
|
strlen(exec_path as *const c_char),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -39,11 +39,8 @@ use libafl_bolts::{
|
|||||||
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
||||||
use libafl_qemu::modules::CmpLogModule;
|
use libafl_qemu::modules::CmpLogModule;
|
||||||
pub use libafl_qemu::qemu::Qemu;
|
pub use libafl_qemu::qemu::Qemu;
|
||||||
use libafl_qemu::{
|
use libafl_qemu::{modules::edges::StdEdgeCoverageModule, Emulator, QemuExecutor};
|
||||||
modules::{edges, edges::StdEdgeCoverageModule},
|
use libafl_targets::{edges_map_mut_ptr, CmpLogObserver, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
|
||||||
Emulator, QemuExecutor,
|
|
||||||
};
|
|
||||||
use libafl_targets::{edges_map_mut_ptr, CmpLogObserver};
|
|
||||||
use typed_builder::TypedBuilder;
|
use typed_builder::TypedBuilder;
|
||||||
|
|
||||||
use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS};
|
use crate::{CORPUS_CACHE_SIZE, DEFAULT_TIMEOUT_SECS};
|
||||||
@ -160,14 +157,11 @@ where
|
|||||||
let time_observer = time_observer.clone();
|
let time_observer = time_observer.clone();
|
||||||
|
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
let edges_observer = unsafe {
|
let mut edges_observer = unsafe {
|
||||||
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
HitcountsMapObserver::new(VariableMapObserver::from_mut_slice(
|
||||||
"edges",
|
"edges",
|
||||||
OwnedMutSlice::from_raw_parts_mut(
|
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_DEFAULT_SIZE),
|
||||||
edges_map_mut_ptr(),
|
addr_of_mut!(MAX_EDGES_FOUND),
|
||||||
edges::EDGES_MAP_SIZE_IN_USE,
|
|
||||||
),
|
|
||||||
addr_of_mut!(edges::MAX_EDGES_FOUND),
|
|
||||||
))
|
))
|
||||||
.track_indices()
|
.track_indices()
|
||||||
};
|
};
|
||||||
@ -223,13 +217,19 @@ where
|
|||||||
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
|
||||||
{
|
{
|
||||||
tuple_list!(
|
tuple_list!(
|
||||||
StdEdgeCoverageModule::builder().build(),
|
StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()
|
||||||
|
.unwrap(),
|
||||||
CmpLogModule::default(),
|
CmpLogModule::default(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "mips", feature = "hexagon"))]
|
#[cfg(any(feature = "mips", feature = "hexagon"))]
|
||||||
{
|
{
|
||||||
tuple_list!(StdEdgeCoverageModule::builder().build())
|
tuple_list!(StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -345,7 +345,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let modules = tuple_list!(StdEdgeCoverageModule::builder().build());
|
let modules = tuple_list!(StdEdgeCoverageModule::builder()
|
||||||
|
.map_observer(edges_observer.as_mut())
|
||||||
|
.build()
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
|
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
|
||||||
_state: &mut _,
|
_state: &mut _,
|
||||||
|
@ -26,36 +26,47 @@ fn main() {
|
|||||||
let dest_path = Path::new(&out_dir).join("constants.rs");
|
let dest_path = Path::new(&out_dir).join("constants.rs");
|
||||||
let mut constants_file = File::create(dest_path).expect("Could not create file");
|
let mut constants_file = File::create(dest_path).expect("Could not create file");
|
||||||
|
|
||||||
let edges_map_size_max: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_MAX")
|
let edges_map_allocated_size: usize = option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")
|
||||||
|
.or(option_env!("LIBAFL_EDGES_MAP_ALLOCATED_SIZE")) // keep old env for retrocompatibility
|
||||||
.map_or(Ok(TWO_MB), str::parse)
|
.map_or(Ok(TWO_MB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_MAX");
|
.expect("Could not parse LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
|
||||||
let edges_map_size_in_use: usize = option_env!("LIBAFL_EDGES_MAP_SIZE_IN_USE")
|
|
||||||
|
let edges_map_default_size: usize = option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")
|
||||||
|
.or(option_env!("LIBAFL_EDGES_MAP_DEFAULT_SIZE")) // keep old env for retrocompatibility
|
||||||
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
|
|
||||||
let cmp_map_size: usize = option_env!("LIBAFL_CMP_MAP_SIZE")
|
let cmp_map_size: usize = option_env!("LIBAFL_CMP_MAP_SIZE")
|
||||||
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_CMP_MAP_SIZE");
|
.expect("Could not parse LIBAFL_CMP_MAP_SIZE");
|
||||||
|
|
||||||
let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W")
|
let cmplog_map_w: usize = option_env!("LIBAFL_CMPLOG_MAP_W")
|
||||||
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_CMPLOG_MAP_W");
|
.expect("Could not parse LIBAFL_CMPLOG_MAP_W");
|
||||||
|
|
||||||
let cmplog_map_h: usize = option_env!("LIBAFL_CMPLOG_MAP_H")
|
let cmplog_map_h: usize = option_env!("LIBAFL_CMPLOG_MAP_H")
|
||||||
.map_or(Ok(32), str::parse)
|
.map_or(Ok(32), str::parse)
|
||||||
.expect("Could not parse LIBAFL_CMPLOG_MAP_H");
|
.expect("Could not parse LIBAFL_CMPLOG_MAP_H");
|
||||||
|
|
||||||
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
|
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
|
||||||
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE");
|
.expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
|
|
||||||
let ddg_map_size: usize = option_env!("LIBAFL_DDG_MAP_SIZE")
|
let ddg_map_size: usize = option_env!("LIBAFL_DDG_MAP_SIZE")
|
||||||
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
.map_or(Ok(SIXTY_FIVE_KB), str::parse)
|
||||||
.expect("Could not parse LIBAFL_DDG_MAP_SIZE");
|
.expect("Could not parse LIBAFL_DDG_MAP_SIZE");
|
||||||
|
|
||||||
|
assert!(edges_map_default_size <= edges_map_allocated_size);
|
||||||
|
assert!(edges_map_default_size.is_power_of_two());
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
constants_file,
|
constants_file,
|
||||||
"// These constants are autogenerated by build.rs
|
"// These constants are autogenerated by build.rs
|
||||||
|
|
||||||
/// The default size of the edges map the fuzzer uses
|
/// The default size of the edges map the fuzzer uses
|
||||||
pub const EDGES_MAP_SIZE_IN_USE: usize = {edges_map_size_in_use};
|
pub const EDGES_MAP_DEFAULT_SIZE: usize = {edges_map_default_size};
|
||||||
/// The real allocated size of the edges map
|
/// The real allocated size of the edges map
|
||||||
pub const EDGES_MAP_SIZE_MAX: usize = {edges_map_size_max};
|
pub const EDGES_MAP_ALLOCATED_SIZE: usize = {edges_map_allocated_size};
|
||||||
/// The size of the cmps map
|
/// The size of the cmps map
|
||||||
pub const CMP_MAP_SIZE: usize = {cmp_map_size};
|
pub const CMP_MAP_SIZE: usize = {cmp_map_size};
|
||||||
/// The width of the `CmpLog` map
|
/// The width of the `CmpLog` map
|
||||||
@ -70,7 +81,10 @@ fn main() {
|
|||||||
)
|
)
|
||||||
.expect("Could not write file");
|
.expect("Could not write file");
|
||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE_IN_USE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_DEFAULT_SIZE");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_ALLOCATED_SIZE");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_CMP_MAP_SIZE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_CMP_MAP_SIZE");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_W");
|
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_W");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H");
|
println!("cargo:rerun-if-env-changed=LIBAFL_CMPLOG_MAP_H");
|
||||||
@ -160,8 +174,8 @@ fn main() {
|
|||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file(src_dir.join("coverage.c"))
|
.file(src_dir.join("coverage.c"))
|
||||||
.define(
|
.define(
|
||||||
"EDGES_MAP_SIZE_MAX",
|
"EDGES_MAP_ALLOCATED_SIZE",
|
||||||
Some(&*format!("{edges_map_size_max}")),
|
Some(&*format!("{edges_map_allocated_size}")),
|
||||||
)
|
)
|
||||||
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}")))
|
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{acc_map_size}")))
|
||||||
.define("DDG_MAP_SIZE", Some(&*format!("{ddg_map_size}")))
|
.define("DDG_MAP_SIZE", Some(&*format!("{ddg_map_size}")))
|
||||||
|
@ -8,7 +8,7 @@ typedef uint32_t prev_loc_t;
|
|||||||
/* Maximum K for top-K context sensitivity */
|
/* Maximum K for top-K context sensitivity */
|
||||||
#define CTX_MAX_K 32U
|
#define CTX_MAX_K 32U
|
||||||
|
|
||||||
extern uint8_t __afl_area_ptr_local[EDGES_MAP_SIZE_MAX];
|
extern uint8_t __afl_area_ptr_local[EDGES_MAP_ALLOCATED_SIZE];
|
||||||
uint8_t *__afl_area_ptr = __afl_area_ptr_local;
|
uint8_t *__afl_area_ptr = __afl_area_ptr_local;
|
||||||
|
|
||||||
extern uint8_t __ddg_area_ptr_local[DDG_MAP_SIZE];
|
extern uint8_t __ddg_area_ptr_local[DDG_MAP_SIZE];
|
||||||
|
@ -20,12 +20,12 @@ use core::ptr::addr_of_mut;
|
|||||||
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
#[cfg(any(target_os = "linux", target_vendor = "apple"))]
|
||||||
use libafl::{mutators::Tokens, Error};
|
use libafl::{mutators::Tokens, Error};
|
||||||
|
|
||||||
use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_SIZE_IN_USE, EDGES_MAP_SIZE_MAX};
|
use crate::{ACCOUNTING_MAP_SIZE, DDG_MAP_SIZE, EDGES_MAP_ALLOCATED_SIZE, EDGES_MAP_DEFAULT_SIZE};
|
||||||
|
|
||||||
/// The map for edges.
|
/// The map for edges.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_SIZE_MAX] = [0; EDGES_MAP_SIZE_MAX];
|
pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_ALLOCATED_SIZE] = [0; EDGES_MAP_ALLOCATED_SIZE];
|
||||||
pub use __afl_area_ptr_local as EDGES_MAP;
|
pub use __afl_area_ptr_local as EDGES_MAP;
|
||||||
|
|
||||||
/// The map for data dependency
|
/// The map for data dependency
|
||||||
@ -85,9 +85,9 @@ pub fn autotokens() -> Result<Tokens, Error> {
|
|||||||
|
|
||||||
/// The actual size we use for the map of edges.
|
/// The actual size we use for the map of edges.
|
||||||
/// This is used for forkserver backend
|
/// This is used for forkserver backend
|
||||||
#[no_mangle]
|
|
||||||
#[allow(non_upper_case_globals)]
|
#[allow(non_upper_case_globals)]
|
||||||
pub static mut __afl_map_size: usize = EDGES_MAP_SIZE_IN_USE;
|
#[no_mangle]
|
||||||
|
pub static mut __afl_map_size: usize = EDGES_MAP_DEFAULT_SIZE;
|
||||||
|
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "sancov_pcguard_edges",
|
feature = "sancov_pcguard_edges",
|
||||||
@ -127,11 +127,11 @@ pub unsafe fn edges_map_mut_slice<'a>() -> OwnedMutSlice<'a, u8> {
|
|||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// use libafl::observers::StdMapObserver;
|
/// use libafl::observers::StdMapObserver;
|
||||||
/// use libafl_targets::{EDGES_MAP, EDGES_MAP_SIZE_IN_USE};
|
/// use libafl_targets::{EDGES_MAP, EDGES_MAP_DEFAULT_SIZE};
|
||||||
///
|
///
|
||||||
/// #[cfg(not(feature = "pointer_maps"))]
|
/// #[cfg(not(feature = "pointer_maps"))]
|
||||||
/// let observer = unsafe {
|
/// let observer = unsafe {
|
||||||
/// StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP_SIZE_IN_USE)
|
/// StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP_DEFAULT_SIZE)
|
||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -192,7 +192,7 @@ pub fn edges_max_num() -> usize {
|
|||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "pointer_maps")]
|
#[cfg(feature = "pointer_maps")]
|
||||||
{
|
{
|
||||||
EDGES_MAP_SIZE_MAX // the upper bound
|
EDGES_MAP_ALLOCATED_SIZE // the upper bound
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "pointer_maps"))]
|
#[cfg(not(feature = "pointer_maps"))]
|
||||||
{
|
{
|
||||||
|
@ -27,9 +27,9 @@ use crate::coverage::EDGES_MAP;
|
|||||||
use crate::coverage::MAX_EDGES_FOUND;
|
use crate::coverage::MAX_EDGES_FOUND;
|
||||||
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
|
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::EDGES_MAP_SIZE_IN_USE;
|
use crate::EDGES_MAP_DEFAULT_SIZE;
|
||||||
#[cfg(feature = "pointer_maps")]
|
#[cfg(feature = "pointer_maps")]
|
||||||
use crate::{coverage::EDGES_MAP_PTR, EDGES_MAP_SIZE_MAX};
|
use crate::{coverage::EDGES_MAP_PTR, EDGES_MAP_ALLOCATED_SIZE};
|
||||||
|
|
||||||
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
#[cfg(all(feature = "sancov_pcguard_edges", feature = "sancov_pcguard_hitcounts"))]
|
||||||
#[cfg(not(any(doc, feature = "clippy")))]
|
#[cfg(not(any(doc, feature = "clippy")))]
|
||||||
@ -204,7 +204,7 @@ unsafe fn update_ngram(pos: usize) -> usize {
|
|||||||
prev_array_8.as_mut_array()[0] = pos as u32;
|
prev_array_8.as_mut_array()[0] = pos as u32;
|
||||||
reduced = prev_array_8.reduce_xor() as usize;
|
reduced = prev_array_8.reduce_xor() as usize;
|
||||||
}
|
}
|
||||||
reduced %= EDGES_MAP_SIZE_IN_USE;
|
reduced %= EDGES_MAP_DEFAULT_SIZE;
|
||||||
reduced
|
reduced
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,13 +233,13 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: *mut u32) {
|
|||||||
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
|
#[cfg(any(feature = "sancov_ngram4", feature = "sancov_ngram8"))]
|
||||||
{
|
{
|
||||||
pos = update_ngram(pos);
|
pos = update_ngram(pos);
|
||||||
// println!("Wrinting to {} {}", pos, EDGES_MAP_SIZE_IN_USE);
|
// println!("Wrinting to {} {}", pos, EDGES_MAP_DEFAULT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sancov_ctx")]
|
#[cfg(feature = "sancov_ctx")]
|
||||||
{
|
{
|
||||||
pos ^= __afl_prev_ctx as usize;
|
pos ^= __afl_prev_ctx as usize;
|
||||||
// println!("Wrinting to {} {}", pos, EDGES_MAP_SIZE_IN_USE);
|
// println!("Wrinting to {} {}", pos, EDGES_MAP_DEFAULT_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "pointer_maps")]
|
#[cfg(feature = "pointer_maps")]
|
||||||
@ -291,13 +291,13 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32
|
|||||||
|
|
||||||
#[cfg(feature = "pointer_maps")]
|
#[cfg(feature = "pointer_maps")]
|
||||||
{
|
{
|
||||||
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1) % EDGES_MAP_SIZE_MAX;
|
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1) % EDGES_MAP_ALLOCATED_SIZE;
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "pointer_maps"))]
|
#[cfg(not(feature = "pointer_maps"))]
|
||||||
{
|
{
|
||||||
let edges_map_len = (*addr_of!(EDGES_MAP)).len();
|
let edges_map_len = (*addr_of!(EDGES_MAP)).len();
|
||||||
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1);
|
MAX_EDGES_FOUND = MAX_EDGES_FOUND.wrapping_add(1);
|
||||||
assert!((MAX_EDGES_FOUND <= edges_map_len), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({edges_map_len}). Use the LIBAFL_EDGES_MAP_SIZE_IN_USE env to increase it at compile time.");
|
assert!((MAX_EDGES_FOUND <= edges_map_len), "The number of edges reported by SanitizerCoverage exceed the size of the edges map ({edges_map_len}). Use the LIBAFL_EDGES_MAP_DEFAULT_SIZE env to increase it at compile time.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,12 +95,15 @@ fn is_workspace_toml(path: &Path) -> bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Result<()> {
|
async fn run_cargo_fmt(cargo_file_path: PathBuf, is_check: bool, verbose: bool) -> io::Result<()> {
|
||||||
// Make sure we parse the correct file
|
// Make sure we parse the correct file
|
||||||
assert_eq!(path.file_name().unwrap().to_str().unwrap(), "Cargo.toml");
|
assert_eq!(
|
||||||
|
cargo_file_path.file_name().unwrap().to_str().unwrap(),
|
||||||
|
"Cargo.toml"
|
||||||
|
);
|
||||||
|
|
||||||
if is_workspace_toml(path.as_path()) {
|
if is_workspace_toml(cargo_file_path.as_path()) {
|
||||||
println!("[*] Skipping {}...", path.as_path().display());
|
println!("[*] Skipping {}...", cargo_file_path.as_path().display());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,14 +115,18 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
|
|||||||
.arg("+nightly")
|
.arg("+nightly")
|
||||||
.arg("fmt")
|
.arg("fmt")
|
||||||
.arg("--manifest-path")
|
.arg("--manifest-path")
|
||||||
.arg(path.as_path());
|
.arg(cargo_file_path.as_path());
|
||||||
|
|
||||||
if is_check {
|
if is_check {
|
||||||
fmt_command.arg("--check");
|
fmt_command.arg("--check");
|
||||||
}
|
}
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
println!("[*] {} {}...", task_str, path.as_path().display());
|
println!(
|
||||||
|
"[*] {} {}...",
|
||||||
|
task_str,
|
||||||
|
cargo_file_path.as_path().display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = fmt_command.output().await?;
|
let res = fmt_command.output().await?;
|
||||||
@ -130,7 +137,7 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
|
|||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
ErrorKind::Other,
|
ErrorKind::Other,
|
||||||
format!(
|
format!(
|
||||||
"Cargo fmt failed. Run cargo fmt for {path:#?}.\nstdout: {stdout}\nstderr: {stderr}"),
|
"Cargo fmt failed. Run cargo fmt for {cargo_file_path:#?}.\nstdout: {stdout}\nstderr: {stderr}\ncommand: {fmt_command:?}"),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +145,7 @@ async fn run_cargo_fmt(path: PathBuf, is_check: bool, verbose: bool) -> io::Resu
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn run_clang_fmt(
|
async fn run_clang_fmt(
|
||||||
path: PathBuf,
|
c_file_path: PathBuf,
|
||||||
clang: String,
|
clang: String,
|
||||||
is_check: bool,
|
is_check: bool,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
@ -151,16 +158,16 @@ async fn run_clang_fmt(
|
|||||||
.arg("-i")
|
.arg("-i")
|
||||||
.arg("--style")
|
.arg("--style")
|
||||||
.arg("file")
|
.arg("file")
|
||||||
.arg(path.as_path());
|
.arg(c_file_path.as_path());
|
||||||
|
|
||||||
if is_check {
|
if is_check {
|
||||||
fmt_command.arg("-Werror").arg("--dry-run");
|
fmt_command.arg("-Werror").arg("--dry-run");
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt_command.arg(path.as_path());
|
fmt_command.arg(c_file_path.as_path());
|
||||||
|
|
||||||
if verbose {
|
if verbose {
|
||||||
println!("[*] {} {}...", task_str, path.as_path().display());
|
println!("[*] {} {}...", task_str, c_file_path.as_path().display());
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = fmt_command.output().await?;
|
let res = fmt_command.output().await?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user