Skip to content

Commit

Permalink
Change fuzzbench_qemu fuzzer (AFLplusplus#2520)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
tokatoka and rmalmain authored Oct 8, 2024
1 parent 7344fdf commit c12c6f3
Show file tree
Hide file tree
Showing 58 changed files with 731 additions and 572 deletions.
25 changes: 0 additions & 25 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,28 +66,6 @@ jobs:
- name: Test libafl_targets no_std
run: cd libafl_targets && cargo test --no-default-features

llvm-tester:
runs-on: ubuntu-24.04
continue-on-error: true
strategy:
matrix:
llvm-version: [ "16", "17" ] # Add 18 when KyleMayes/install-llvm-action enables it
steps:
- name: Remove Dotnet & Haskell
run: rm -rf /usr/share/dotnet && rm -rf /opt/ghc
- name: Install curl
run: sudo apt-get install clang
- uses: dtolnay/rust-toolchain@stable
- name: Install LLVM and Clang
uses: KyleMayes/install-llvm-action@v2
with:
version: "${{matrix.llvm-version}}"
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
with: { shared-key: "llvm-tester" }
- name: Build and test with llvm-${{ matrix.llvm-version }}
run: pwd && ls & cd libafl_cc && cargo build --release

ubuntu-doc-build:
runs-on: ubuntu-24.04
steps:
Expand Down Expand Up @@ -246,9 +224,7 @@ jobs:

fuzzers:
needs:
- ubuntu
- fuzzers-preflight
- common
strategy:
fail-fast: true
matrix:
Expand Down Expand Up @@ -355,7 +331,6 @@ jobs:
fuzzers-qemu:
needs:
- common
- changes
if: ${{ needs.changes.outputs.qemu == 'true' }}
strategy:
Expand Down
2 changes: 1 addition & 1 deletion docs/src/DEBUGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Try running the fuzzer with the `introspection` feature of the `libafl`. This wi
```
let map = StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), EDGES_MAP.len());
```
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_SIZE_IN_USE`.
You should *never* use the `EDGES_MAP`'s size as this is just the size of the allocated size of the coverage map. Consider using something smaller or our default value `libafl_targets::LIBAFL_EDGES_MAP_DEFAULT_SIZE`.

## Q. I still have problems with my fuzzer.
Finally, if you really have no idea what is going on, run your fuzzer with logging enabled. (You can use `env_logger`, `SimpleStdoutLogger`, `SimpleStderrLogger` from `libafl_bolts`. `fuzzbench_text` has an example to show how to use it.) (Don't forget to enable stdout and stderr), and you can open an issue or ask us in Discord.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/core_concepts/executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ On your fuzzer side, you can allocate a shared memory region and make the `EDGES
```rust,ignore
let mut shmem;
unsafe{
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
shmem = StdShMemProvider::new().unwrap().new_shmem(EDGES_MAP_DEFAULT_SIZE).unwrap();
}
let shmem_buf = shmem.as_slice_mut();
unsafe{
Expand Down
2 changes: 1 addition & 1 deletion docs/src/design/migration-0.9.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ from libafl_target's `EDGES_MAP`.
In the future, instead of using:

```rust,ignore
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_SIZE_IN_USE] };
let edges = unsafe { &mut EDGES_MAP[0..EDGES_MAP_DEFAULT_SIZE] };
let edges_observer = StdMapObserver::new("edges", edges);
```

Expand Down
1 change: 1 addition & 0 deletions fuzzers/binary_only/fuzzbench_fork_qemu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
"x86_64",
"usermode",
] }
libafl_targets = { path = "../../../libafl_targets" }

log = { version = "0.4.22", features = ["release_max_level_info"] }
clap = { version = "4.5.18", features = ["default"] }
Expand Down
67 changes: 34 additions & 33 deletions fuzzers/binary_only/fuzzbench_fork_qemu/Makefile.toml
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
env_scripts = ['''
#!@duckscript
profile = get_env PROFILE
if eq ${profile} "dev"
set_env PROFILE_DIR debug
else
set_env PROFILE_DIR ${profile}
end
''', '''
#!@duckscript
runs_on_ci = get_env RUN_ON_CI
if ${runs_on_ci}
cargo_target_dir = get_env CARGO_MAKE_CRATE_TARGET_DIRECTORY
set_env TARGET_DIR ${cargo_target_dir}
end
''']

# Variables
[env]
FUZZER_NAME = 'libpng_harness'
FUZZER_NAME = 'harness'
PROJECT_DIR = { script = ["pwd"] }
PROFILE = { value = "release", condition = { env_not_set = ["PROFILE"] } }
PROFILE_DIR = { value = "release", condition = { env_not_set = [
"PROFILE_DIR",
] } }
TARGET_DIR = "${CARGO_MAKE_CRATE_TARGET_DIRECTORY}"

[tasks.unsupported]
script_runner = "@shell"
script = '''
echo "Qemu fuzzer not supported on windows"
'''

# libpng
[tasks.libpng]
linux_alias = "libpng_unix"
mac_alias = "libpng_unix"
windows_alias = "unsupported"

[tasks.libpng_unix]
condition = { files_not_exist = ["./libpng-1.6.37"] }
script_runner = "@shell"
script = '''
wget https://github.com/glennrp/libpng/archive/refs/tags/v1.6.37.tar.gz
tar -xvf v1.6.37.tar.gz
'''

# fuzzer
[tasks.fuzzer]
linux_alias = "fuzzer_unix"
Expand All @@ -46,20 +49,13 @@ windows_alias = "unsupported"
[tasks.harness_unix]
script_runner = "@shell"
script = '''
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
cd "${PROJECT_DIR}"
make -C libpng-1.6.37
cc -c "${PROJECT_DIR}/libfuzzer_main.c"
# Build the libpng harness
c++ \
../../inprocess/libfuzzer_libpng/harness.cc \
./libpng-1.6.37/.libs/libpng16.a \
cc \
./fuzz.c \
./libfuzzer_main.o \
-I./libpng-1.6.37/ \
-o ${FUZZER_NAME} \
-lm -lz
'''
dependencies = ["libpng"]

# Run the fuzzer
[tasks.run]
Expand All @@ -72,16 +68,16 @@ command = "cargo"
args = [
"run",
"--profile",
"${PROFILE_DIR}",
"${PROFILE}",
"./${FUZZER_NAME}",
"--",
"--libafl-in",
"../libfuzzer_libpng/corpus",
"./corpus",
"--libafl-out",
"./out",
"./${FUZZER_NAME}",
]
dependencies = ["harness", "fuzzer"]
dependencies = ["harness"]

# Run the fuzzer
[tasks.test]
Expand All @@ -93,7 +89,13 @@ windows_alias = "unsupported"
[tasks.test_unix]
script_runner = "@shell"
script = '''
echo "This test is skipped. QEMU-based fuzzer doesn't work on Github runners"
timeout 15s ${TARGET_DIR}/${PROFILE_DIR}/fuzzbench_fork_qemu ${PROJECT_DIR}/harness -- --libafl-in ${PROJECT_DIR}/../../inprocess/libfuzzer_libpng/corpus --libafl-out ${PROJECT_DIR}/out ${PROJECT_DIR}/harness | tee fuzz_stdout.log
if grep -qa "objectives: 1" fuzz_stdout.log; then
echo "Fuzzer is working"
else
echo "Fuzzer does not generate any testcases or any crashes"
exit 1
fi
'''
dependencies = ["harness", "fuzzer"]

Expand All @@ -108,7 +110,6 @@ windows_alias = "unsupported"
clear = true
script_runner = "@shell"
script = '''
rm -f ./${FUZZER_NAME} libfuzzer_main.o
make -C libpng-1.6.37 clean
rm -f ./${FUZZER_NAME}
cargo clean
'''
19 changes: 19 additions & 0 deletions fuzzers/binary_only/fuzzbench_fork_qemu/fuzz.c
Original file line number Diff line number Diff line change
@@ -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);
}*/
61 changes: 32 additions & 29 deletions fuzzers/binary_only/fuzzbench_fork_qemu/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use libafl::{
};
use libafl_bolts::{
current_time,
os::{dup2, unix_signals::Signal},
os::dup2,
rands::StdRand,
shmem::{ShMemProvider, StdShMemProvider},
tuples::{tuple_list, Merge},
Expand All @@ -50,11 +50,12 @@ use libafl_qemu::{
filter_qemu_args,
modules::{
cmplog::{CmpLogChildModule, CmpLogMap, CmpLogObserver},
edges::{StdEdgeCoverageChildModule, EDGES_MAP_PTR, EDGES_MAP_SIZE_IN_USE},
edges::StdEdgeCoverageChildModule,
},
Emulator, GuestReg, MmapPerms, QemuExitError, QemuExitReason, QemuForkExecutor,
QemuShutdownCause, Regs,
};
use libafl_targets::{EDGES_MAP_DEFAULT_SIZE, EDGES_MAP_PTR};
#[cfg(unix)]
use nix::unistd::dup;

Expand Down Expand Up @@ -148,10 +149,26 @@ fn fuzz(
env::remove_var("LD_LIBRARY_PATH");

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!(
StdEdgeCoverageChildModule::builder().build(),
StdEdgeCoverageChildModule::builder()
.map_observer(edges_observer.as_mut())
.build()?,
CmpLogChildModule::default(),
);

Expand Down Expand Up @@ -218,12 +235,6 @@ fn fuzz(
writeln!(log.borrow_mut(), "{:?} {s}", current_time()).unwrap();
});

let mut shmem_provider = StdShMemProvider::new()?;

let mut edges_shmem = shmem_provider.new_shmem(EDGES_MAP_SIZE_IN_USE).unwrap();
let edges = edges_shmem.as_slice_mut();
unsafe { EDGES_MAP_PTR = edges.as_mut_ptr() };

let mut cmp_shmem = shmem_provider.uninit_on_shmem::<CmpLogMap>().unwrap();
let cmplog = cmp_shmem.as_slice_mut();

Expand All @@ -247,15 +258,6 @@ fn fuzz(
},
};

// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(ConstMapObserver::<_, EDGES_MAP_SIZE_IN_USE>::from_mut_ptr(
"edges",
edges.as_mut_ptr(),
))
.track_indices()
};

// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");

Expand Down Expand Up @@ -321,7 +323,7 @@ fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| {
let mut harness = |emulator: &mut Emulator<_, _, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();
Expand All @@ -339,16 +341,17 @@ fn fuzz(
qemu.write_reg(Regs::Rsp, stack_ptr).unwrap();

match qemu.run() {
Ok(QemuExitReason::Breakpoint(_)) => {}
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(Signal::SigInterrupt))) => {
process::exit(0)
Ok(QemuExitReason::Breakpoint(_)) => ExitKind::Ok,
Ok(QemuExitReason::End(QemuShutdownCause::HostSignal(signal))) => {
signal.handle();
panic!("Unexpected signal: {signal:?}");
}
Err(QemuExitError::UnexpectedExit) => ExitKind::Crash,
_ => {
panic!("Unexpected QEMU exit.")
}
Err(QemuExitError::UnexpectedExit) => return ExitKind::Crash,
_ => panic!("Unexpected QEMU exit."),
}
}

ExitKind::Ok
};

let executor = QemuForkExecutor::new(
Expand Down Expand Up @@ -391,8 +394,8 @@ fn fuzz(
#[cfg(unix)]
{
let null_fd = file_null.as_raw_fd();
dup2(null_fd, io::stdout().as_raw_fd())?;
dup2(null_fd, io::stderr().as_raw_fd())?;
// dup2(null_fd, io::stdout().as_raw_fd())?;
// dup2(null_fd, io::stderr().as_raw_fd())?;
}
// reopen file to make sure we're at the end
log.replace(
Expand Down
1 change: 1 addition & 0 deletions fuzzers/binary_only/fuzzbench_qemu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ libafl_qemu = { path = "../../../libafl_qemu", features = [
"x86_64",
"usermode",
] }
libafl_targets = { path = "../../../libafl_targets", version = "0.13.2" }

log = { version = "0.4.22", features = ["release_max_level_info"] }
clap = { version = "4.5.18", features = ["default"] }
Expand Down
Loading

0 comments on commit c12c6f3

Please sign in to comment.