FRET-LibAFL/fuzzers/libfuzzer_libpng
Addison Crump 862de53cf6
Full libfuzzer shimming (for cargo-fuzz libfuzzer alternative and other use cases) (#981)
* squash libfuzzer edits

* fixup: compat with custom mutators

* use tui flag

* add introspection support

* use libfuzzer dep now that we've merged

* force input loading

* some fixes

* begin docs, impl shrink

* make whole-archive conditional and not default

* make more copies of counters maps

* lol, remember to add the observer

* make size edge map observer an observer

* fixup: make def of run driver conditional

* add sanity checks for insertion

* revert silencing of forks

* add experimental tmin support; add default asan flags

* use default options instead of specifying our own

* implement lockless mode

* fix merge

* fixup lockless corpus

* fixup for generalisation

* remove erroneous drop_in_place

* improve error logging in the case of corpus loading failure

* ok, use lock files 😔

* fix tmin

* implement merge (again); fix rare cases with maps being too small

* implement a scheduler for removing excess

* implement a walking strategy for corpus loading for large corpora

* revert filename parameter; rename and remove duplicates

* various cleanup and clippy satisfaction

* fix no_std tests

* clang-format

* expand and satisfy the clippy gods

* fix sanitizer_ifaces bindgen for no_std

* fix wasm fuzzer

* fixup clippy script

* rename and provide a small amount of explanation for sanitizer_interfaces

* fixup: HasLastReportTime

* fix clippy oddities

* restrict clippy checks to linux-only for libafl_libfuzzer_runtime

* name the mutators

* format

* fix clippy warning

* hope docker is fixed

* fix cmin lint

* clippy pass

* more docs

* more clippy

* fix remaining clippy complaints

* fix import

* miri fixes (no constructors executed)

* exclude libafl_libfuzzer from cargo-hack

* fix clippy check for sanitizer_interfaces

* fmt

* fix CI (?)

* deduplicate sancov 8bit for improved perf on ASAN

* merge 8bit coverage regions + comment out insane deduplication

* no erroring out on free hooks

* fixup for non-forking merge

* skip the corpus dir if we use it

* fixup: recent libafl changes and feature flags

* libafl_libfuzzer: use rust-lld for whole-archive feature

* clarify cause of failure

* mark unsafe

* clippy :cursed_cowboy:

* attempt to fix wasm

* spooky unknowable bug 👻

* more clippy lints

* clippy fix for merge

* use the version pin

* add unsafe to ::register

* Serdeany autoreg fix

* make type assert actionable

* miri fixes

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
Co-authored-by: Dominik Maier <dmnk@google.com>
Co-authored-by: Mrmaxmeier <Mrmaxmeier@gmail.com>
2023-08-24 13:30:23 +02:00
..
2021-02-12 23:05:00 +01:00
2020-12-31 14:48:54 +01:00
2023-08-17 17:15:03 +02:00
2023-05-09 16:45:20 +02:00
2022-10-05 20:13:46 +02:00

Libfuzzer for libpng

This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection.

In contrast to other fuzzer examples, this setup uses fuzz_loop_for, to occasionally respawn the fuzzer executor. While this costs performance, it can be useful for targets with memory leaks or other instabilities. If your target is really instable, however, consider exchanging the InProcessExecutor for a ForkserverExecutor instead.

It also uses the introspection feature, printing fuzzer stats during execution.

To show off crash detection, we added a ud2 instruction to the harness, edit harness.cc if you want a non-crashing example. It has been tested on Linux.

Build

To build this example, run

cargo build --release

This will build the library with the fuzzer (src/lib.rs) with the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback. In addition, it will also build two C and C++ compiler wrappers (bin/libafl_c(libafl_c/xx).rs) that you must use to compile the target.

The compiler wrappers, libafl_cc and libafl_cxx, will end up in ./target/release/ (or ./target/debug, in case you did not build with the --release flag).

Then download libpng, and unpack the archive:

wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz
tar -xvf libpng-1.6.37.tar.xz

Now compile libpng, using the libafl_cc compiler wrapper:

cd libpng-1.6.37
./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
make CC="$(pwd)/../target/release/libafl_cc" CXX="$(pwd)/../target/release/libafl_cxx" -j `nproc`

You can find the static lib at libpng-1.6.37/.libs/libpng16.a.

Now, we have to build the libfuzzer harness and link all together to create our fuzzer binary.

cd ..
./target/release/libafl_cxx ./harness.cc libpng-1.6.37/.libs/libpng16.a -I libpng-1.6.37/ -o fuzzer_libpng -lz -lm

Afterward, the fuzzer will be ready to run. Note that, unless you use the launcher, you will have to run the binary multiple times to actually start the fuzz process, see Run in the following. This allows you to run multiple different builds of the same fuzzer alongside, for example, with and without ASAN (-fsanitize=address) or with different mutators.

Run

The first time you run the binary, the broker will open a tcp port (currently on port 1337), waiting for fuzzer clients to connect. This port is local and only used for the initial handshake. All further communication happens via shared map, to be independent of the kernel. Currently, you must run the clients from the libfuzzer_libpng directory for them to be able to access the PNG corpus.

./fuzzer_libpng

[libafl/src/bolts/llmp.rs:407] "We're the broker" = "We\'re the broker"
Doing broker things. Run this tool again to start fuzzing in a client.

And after running the above again in a separate terminal:

[libafl/src/bolts/llmp.rs:1464] "New connection" = "New connection"
[libafl/src/bolts/llmp.rs:1464] addr = 127.0.0.1:33500
[libafl/src/bolts/llmp.rs:1464] stream.peer_addr().unwrap() = 127.0.0.1:33500
[LOG Debug]: Loaded 4 initial testcases.
[New Testcase #2] clients: 3, corpus: 6, objectives: 0, executions: 5, exec/sec: 0
< fuzzing stats >

As this example uses in-process fuzzing, we added a Restarting Event Manager (setup_restarting_mgr). This means each client will start itself again to listen for crashes and timeouts. By restarting the actual fuzzer, it can recover from these exit conditions.

In any real-world scenario, you should use taskset to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet).