diff --git a/README.md b/README.md index 23b528871c..453e7c77da 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,12 @@ Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust. -LibAFL is written and maintained by Andrea Fioraldi and Dominik Maier . +LibAFL is written and maintained by + + * [Andrea Fioraldi](https://twitter.com/andreafioraldi) + * [Dominik Maier](https://twitter.com/domenuk) + * [s1341](https://twitter.com/srubenst1341) + * [Dongjia Zhang](https://github.com/tokatoka) ## Why LibAFL? @@ -27,7 +32,7 @@ It offers a main crate that provide building blocks for custom fuzzers, [libafl] LibAFL offers integrations with popular instrumentation frameworks. At the moment, the supported backends are: + SanitizerCoverage, in [libafl_targets](./libafl_targets) -+ Frida, in [libafl_frida](./libafl_frida), by s1341 ++ Frida, in [libafl_frida](./libafl_frida) + QEMU user-mode, in [libafl_qemu](./libafl_qemu) ## Getting started @@ -69,11 +74,15 @@ The best-tested fuzzer is [`./fuzzers/libfuzzer_libpng`](./fuzzers/libfuzzer_lib + [Installation guide](./docs/src/getting_started/setup.md) -+ Our RC3 [talk](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO") explaining the core concepts - + [Online API documentation](https://docs.rs/libafl/) -+ The LibAFL book (very WIP) [online](https://aflplus.plus/libafl-book) or in the [repo](./docs/src/) ++ The LibAFL book (WIP) [online](https://aflplus.plus/libafl-book) or in the [repo](./docs/src/) + ++ Our RC3 [talk](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO") explaining the core concepts + ++ Our Fuzzcon Europe [talk](https://www.youtube.com/watch?v=PWB8GIhFAaI "LibAFL: The Advanced Fuzzing Library") with a (a bit but not so much outdated) step-by-step discussion on how to build some example fuzzers + ++ The Fuzzing101 [solutions](https://github.com/epi052/fuzzing-101-solutions) & series of [blog posts](https://epi052.gitlab.io/notes-to-self/blog/2021-11-01-fuzzing-101-with-libafl/) by [epi](https://github.com/epi052) ## Contributing @@ -82,7 +91,7 @@ Check the [TODO.md](./TODO.md) file for features that we plan to support. For bugs, feel free to open issues or contact us directly. Thank you for your support. <3 Even though we will gladly assist you in finishing up your PR, try to -- use *stable* rust +- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26)) - run `cargo fmt` on your code before pushing - check the output of `cargo clippy --all` or `./clippy.sh` - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. diff --git a/fuzzers/baby_fuzzer/Cargo.toml b/fuzzers/baby_fuzzer/Cargo.toml index edec167c48..e2062bafff 100644 --- a/fuzzers/baby_fuzzer/Cargo.toml +++ b/fuzzers/baby_fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/baby_fuzzer_gramatron/Cargo.toml b/fuzzers/baby_fuzzer_gramatron/Cargo.toml index c56b765308..e0ee53e49f 100644 --- a/fuzzers/baby_fuzzer_gramatron/Cargo.toml +++ b/fuzzers/baby_fuzzer_gramatron/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.6.0" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/baby_fuzzer_nautilus/Cargo.toml b/fuzzers/baby_fuzzer_nautilus/Cargo.toml index 72b87f68e4..bdf85324fb 100644 --- a/fuzzers/baby_fuzzer_nautilus/Cargo.toml +++ b/fuzzers/baby_fuzzer_nautilus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.6.0" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/baby_fuzzer_tokens/Cargo.toml b/fuzzers/baby_fuzzer_tokens/Cargo.toml index db4814bb01..e2062bafff 100644 --- a/fuzzers/baby_fuzzer_tokens/Cargo.toml +++ b/fuzzers/baby_fuzzer_tokens/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_fuzzer" -version = "0.6.0" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/baby_no_std/Cargo.toml b/fuzzers/baby_no_std/Cargo.toml index 3d335caf20..87b732e002 100644 --- a/fuzzers/baby_no_std/Cargo.toml +++ b/fuzzers/baby_no_std/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "baby_no_std" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/forkserver_simple/Cargo.toml b/fuzzers/forkserver_simple/Cargo.toml index c8fd88515b..200f258b4f 100644 --- a/fuzzers/forkserver_simple/Cargo.toml +++ b/fuzzers/forkserver_simple/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "forkserver_simple" -version = "0.6.1" +version = "0.7.0" authors = ["tokatoka "] edition = "2021" diff --git a/fuzzers/frida_libpng/Cargo.toml b/fuzzers/frida_libpng/Cargo.toml index 3b83db753c..7a2a6fffe5 100644 --- a/fuzzers/frida_libpng/Cargo.toml +++ b/fuzzers/frida_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "frida_libpng" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" build = "build.rs" @@ -31,8 +31,8 @@ reqwest = { version = "0.11.4", features = ["blocking"] } libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} capstone = "0.10.0" frida-gum = { version = "0.6.1", features = [ "auto-download", "event-sink", "invocation-listener"] } -libafl_frida = { path = "../../libafl_frida", version = "0.6.1", features = ["cmplog"] } -libafl_targets = { path = "../../libafl_targets", version = "0.6.1" , features = ["sancov_cmplog"] } +libafl_frida = { path = "../../libafl_frida", features = ["cmplog"] } +libafl_targets = { path = "../../libafl_targets", features = ["sancov_cmplog"] } lazy_static = "1.4.0" libc = "0.2" libloading = "0.7.0" diff --git a/fuzzers/fuzzbench/Cargo.toml b/fuzzers/fuzzbench/Cargo.toml index 8ebea0ebd8..817863ad64 100644 --- a/fuzzers/fuzzbench/Cargo.toml +++ b/fuzzers/fuzzbench/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fuzzbench" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/fuzzbench_gsoc/Cargo.toml b/fuzzers/fuzzbench_gsoc/Cargo.toml index 8ebea0ebd8..817863ad64 100644 --- a/fuzzers/fuzzbench_gsoc/Cargo.toml +++ b/fuzzers/fuzzbench_gsoc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fuzzbench" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/fuzzbench_qemu/Cargo.toml b/fuzzers/fuzzbench_qemu/Cargo.toml index d88c0ef936..e45625f178 100644 --- a/fuzzers/fuzzbench_qemu/Cargo.toml +++ b/fuzzers/fuzzbench_qemu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fuzzbench_qemu" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/generic_inmemory/Cargo.toml b/fuzzers/generic_inmemory/Cargo.toml index 764012bb1c..9be2ef6b6f 100644 --- a/fuzzers/generic_inmemory/Cargo.toml +++ b/fuzzers/generic_inmemory/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "generic_inmemory" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libafl_atheris/Cargo.toml b/fuzzers/libafl_atheris/Cargo.toml index cada5b5524..6a6f269e25 100644 --- a/fuzzers/libafl_atheris/Cargo.toml +++ b/fuzzers/libafl_atheris/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_atheris" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2018" diff --git a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml index 83f229de66..544fa8f7b8 100644 --- a/fuzzers/libfuzzer_libmozjpeg/Cargo.toml +++ b/fuzzers/libfuzzer_libmozjpeg/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libmozjpeg" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libfuzzer_libpng/Cargo.toml b/fuzzers/libfuzzer_libpng/Cargo.toml index 93ccfce014..dd2867b7c7 100644 --- a/fuzzers/libfuzzer_libpng/Cargo.toml +++ b/fuzzers/libfuzzer_libpng/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libfuzzer_libpng_ctx/Cargo.toml b/fuzzers/libfuzzer_libpng_ctx/Cargo.toml index 315a34c555..837048a85b 100644 --- a/fuzzers/libfuzzer_libpng_ctx/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_ctx/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng_launcher" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml index e72dfee7d0..fe970cda07 100644 --- a/fuzzers/libfuzzer_libpng_launcher/Cargo.toml +++ b/fuzzers/libfuzzer_libpng_launcher/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_libpng_launcher" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libfuzzer_reachability/Cargo.toml b/fuzzers/libfuzzer_reachability/Cargo.toml index 71fa7caf9b..9a36f60c8f 100644 --- a/fuzzers/libfuzzer_reachability/Cargo.toml +++ b/fuzzers/libfuzzer_reachability/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_reachability" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/libfuzzer_stb_image/Cargo.toml b/fuzzers/libfuzzer_stb_image/Cargo.toml index 5cf980b4b2..ff8639623c 100644 --- a/fuzzers/libfuzzer_stb_image/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_stb_image" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" build = "build.rs" diff --git a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/Cargo.toml b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/Cargo.toml index 1a6405f934..5c47a68919 100644 --- a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_stb_image_concolic" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier ", "Julius Hohnerlein"] edition = "2021" build = "build.rs" diff --git a/fuzzers/libfuzzer_stb_image_concolic/runtime/Cargo.toml b/fuzzers/libfuzzer_stb_image_concolic/runtime/Cargo.toml index 9b0348102a..ff2264d66b 100644 --- a/fuzzers/libfuzzer_stb_image_concolic/runtime/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image_concolic/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "example_runtime" -version = "0.1.0" +version = "0.7.0" edition = "2021" authors = ["Julius Hohnerlein "] diff --git a/fuzzers/libfuzzer_stb_image_sugar/Cargo.toml b/fuzzers/libfuzzer_stb_image_sugar/Cargo.toml index 474ca64037..2aaf2052a5 100644 --- a/fuzzers/libfuzzer_stb_image_sugar/Cargo.toml +++ b/fuzzers/libfuzzer_stb_image_sugar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfuzzer_stb_image" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" build = "build.rs" diff --git a/fuzzers/push_harness/Cargo.toml b/fuzzers/push_harness/Cargo.toml index 5ac8be3a91..551f56ecd0 100644 --- a/fuzzers/push_harness/Cargo.toml +++ b/fuzzers/push_harness/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "push_harness" -version = "0.5.0" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/push_stage_harness/Cargo.toml b/fuzzers/push_stage_harness/Cargo.toml index e309d81351..66c01c2668 100644 --- a/fuzzers/push_stage_harness/Cargo.toml +++ b/fuzzers/push_stage_harness/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "push_stage_harness" -version = "0.5.0" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/qemu_launcher/.gitignore b/fuzzers/qemu_launcher/.gitignore new file mode 100644 index 0000000000..a977a2ca5b --- /dev/null +++ b/fuzzers/qemu_launcher/.gitignore @@ -0,0 +1 @@ +libpng-* \ No newline at end of file diff --git a/fuzzers/qemu_launcher/Cargo.toml b/fuzzers/qemu_launcher/Cargo.toml new file mode 100644 index 0000000000..5426c25948 --- /dev/null +++ b/fuzzers/qemu_launcher/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "qemu_launcher" +version = "0.7.0" +authors = ["Andrea Fioraldi ", "Dominik Maier "] +edition = "2018" + +[features] +default = ["std"] +std = [] + +[profile.release] +lto = true +codegen-units = 1 +opt-level = 3 +debug = true + +[dependencies] +libafl = { path = "../../libafl/" } +libafl_qemu = { path = "../../libafl_qemu/" } diff --git a/fuzzers/qemu_launcher/Makefile b/fuzzers/qemu_launcher/Makefile new file mode 100644 index 0000000000..42f3d0f843 --- /dev/null +++ b/fuzzers/qemu_launcher/Makefile @@ -0,0 +1,41 @@ +FUZZER_NAME="libpng_harness" +PROJECT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +UNAME := $(shell uname) + +PHONY: all + +all: fuzzer + +libpng-1.6.37: + 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 + +target/release/qemu_launcher: src/* + cargo build --release + +libpng-1.6.37/.libs/libpng16.a: libpng-1.6.37 + cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes + $(MAKE) -C libpng-1.6.37 + # Build the libpng harness + c++ \ + $(PROJECT_DIR)/harness.cc \ + $(PROJECT_DIR)/libpng-1.6.37/.libs/libpng16.a \ + -I$(PROJECT_DIR)/libpng-1.6.37/ \ + -o $(FUZZER_NAME) \ + -lm -lz + +fuzzer: target/release/qemu_launcher libpng-1.6.37/.libs/libpng16.a + +clean: + rm ./$(FUZZER_NAME) + $(MAKE) -C libpng-1.6.37 clean + +run: all + cargo run --release ./$(FUZZER_NAME) + +short_test: all + rm -rf libafl_unix_shmem_server || true + timeout 10s cargo run --release ./$(FUZZER_NAME) & + +test: all + timeout 60s cargo run --release ./$(FUZZER_NAME) & diff --git a/fuzzers/qemu_launcher/README.md b/fuzzers/qemu_launcher/README.md new file mode 100644 index 0000000000..b96b0e851c --- /dev/null +++ b/fuzzers/qemu_launcher/README.md @@ -0,0 +1,47 @@ +# Libfuzzer for libpng, with launcher + +This folder contains an example fuzzer for libpng, using LLMP for fast multi-process fuzzing and crash detection. +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. + +In contrast to the normal libfuzzer libpng example, this uses the `launcher` feature, that automatically spawns `n` child processes, and binds them to a free core. + +## Build + +To build this example, run + +```bash +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. + +Then download libpng, and unpack the archive: +```bash +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: + +```bash +cd libpng-1.6.37 +./configure +make CC=../target/release/libafl_cc CXX=../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 +``` + +Afterwards, the fuzzer will be ready to run. + +## Run + +Just run once, the launcher feature should do the rest. \ No newline at end of file diff --git a/fuzzers/qemu_launcher/corpus/not_kitty.png b/fuzzers/qemu_launcher/corpus/not_kitty.png new file mode 100644 index 0000000000..eff7c1707b Binary files /dev/null and b/fuzzers/qemu_launcher/corpus/not_kitty.png differ diff --git a/fuzzers/qemu_launcher/corpus/not_kitty_alpha.png b/fuzzers/qemu_launcher/corpus/not_kitty_alpha.png new file mode 100644 index 0000000000..2fb8da2c8f Binary files /dev/null and b/fuzzers/qemu_launcher/corpus/not_kitty_alpha.png differ diff --git a/fuzzers/qemu_launcher/corpus/not_kitty_gamma.png b/fuzzers/qemu_launcher/corpus/not_kitty_gamma.png new file mode 100644 index 0000000000..939d9d29a9 Binary files /dev/null and b/fuzzers/qemu_launcher/corpus/not_kitty_gamma.png differ diff --git a/fuzzers/qemu_launcher/corpus/not_kitty_icc.png b/fuzzers/qemu_launcher/corpus/not_kitty_icc.png new file mode 100644 index 0000000000..f0c7804d99 Binary files /dev/null and b/fuzzers/qemu_launcher/corpus/not_kitty_icc.png differ diff --git a/fuzzers/qemu_launcher/harness.cc b/fuzzers/qemu_launcher/harness.cc new file mode 100644 index 0000000000..46a1a0ca09 --- /dev/null +++ b/fuzzers/qemu_launcher/harness.cc @@ -0,0 +1,203 @@ +// libpng_read_fuzzer.cc +// Copyright 2017-2018 Glenn Randers-Pehrson +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that may +// be found in the LICENSE file https://cs.chromium.org/chromium/src/LICENSE + +// Last changed in libpng 1.6.35 [July 15, 2018] + +// The modifications in 2017 by Glenn Randers-Pehrson include +// 1. addition of a PNG_CLEANUP macro, +// 2. setting the option to ignore ADLER32 checksums, +// 3. adding "#include " which is needed on some platforms +// to provide memcpy(). +// 4. adding read_end_info() and creating an end_info structure. +// 5. adding calls to png_set_*() transforms commonly used by browsers. + +#include +#include +#include + +#include + +#define PNG_INTERNAL +#include "png.h" + +#define PNG_CLEANUP \ + if(png_handler.png_ptr) \ + { \ + if (png_handler.row_ptr) \ + png_free(png_handler.png_ptr, png_handler.row_ptr); \ + if (png_handler.end_info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + &png_handler.end_info_ptr); \ + else if (png_handler.info_ptr) \ + png_destroy_read_struct(&png_handler.png_ptr, &png_handler.info_ptr,\ + nullptr); \ + else \ + png_destroy_read_struct(&png_handler.png_ptr, nullptr, nullptr); \ + png_handler.png_ptr = nullptr; \ + png_handler.row_ptr = nullptr; \ + png_handler.info_ptr = nullptr; \ + png_handler.end_info_ptr = nullptr; \ + } + +struct BufState { + const uint8_t* data; + size_t bytes_left; +}; + +struct PngObjectHandler { + png_infop info_ptr = nullptr; + png_structp png_ptr = nullptr; + png_infop end_info_ptr = nullptr; + png_voidp row_ptr = nullptr; + BufState* buf_state = nullptr; + + ~PngObjectHandler() { + if (row_ptr) + png_free(png_ptr, row_ptr); + if (end_info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info_ptr); + else if (info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + else + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + delete buf_state; + } +}; + +void user_read_data(png_structp png_ptr, png_bytep data, size_t length) { + BufState* buf_state = static_cast(png_get_io_ptr(png_ptr)); + if (length > buf_state->bytes_left) { + png_error(png_ptr, "read error"); + } + memcpy(data, buf_state->data, length); + buf_state->bytes_left -= length; + buf_state->data += length; +} + +static const int kPngHeaderSize = 8; + +// Entry point for LibFuzzer. +// Roughly follows the libpng book example: +// http://www.libpng.org/pub/png/book/chapter13.html +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + if (size < kPngHeaderSize) { + return 0; + } + + std::vector v(data, data + size); + if (png_sig_cmp(v.data(), 0, kPngHeaderSize)) { + // not a PNG. + return 0; + } + + PngObjectHandler png_handler; + png_handler.png_ptr = nullptr; + png_handler.row_ptr = nullptr; + png_handler.info_ptr = nullptr; + png_handler.end_info_ptr = nullptr; + + png_handler.png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_handler.png_ptr) { + return 0; + } + + png_handler.info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.info_ptr) { + PNG_CLEANUP + return 0; + } + + png_handler.end_info_ptr = png_create_info_struct(png_handler.png_ptr); + if (!png_handler.end_info_ptr) { + PNG_CLEANUP + return 0; + } + + png_set_crc_action(png_handler.png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); +#ifdef PNG_IGNORE_ADLER32 + png_set_option(png_handler.png_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); +#endif + + // Setting up reading from buffer. + png_handler.buf_state = new BufState(); + png_handler.buf_state->data = data + kPngHeaderSize; + png_handler.buf_state->bytes_left = size - kPngHeaderSize; + png_set_read_fn(png_handler.png_ptr, png_handler.buf_state, user_read_data); + png_set_sig_bytes(png_handler.png_ptr, kPngHeaderSize); + + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + // Reading. + png_read_info(png_handler.png_ptr, png_handler.info_ptr); + + // reset error handler to put png_deleter into scope. + if (setjmp(png_jmpbuf(png_handler.png_ptr))) { + PNG_CLEANUP + return 0; + } + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type, compression_type; + int filter_type; + + if (!png_get_IHDR(png_handler.png_ptr, png_handler.info_ptr, &width, + &height, &bit_depth, &color_type, &interlace_type, + &compression_type, &filter_type)) { + PNG_CLEANUP + return 0; + } + + // This is going to be too slow. + if (width && height > 100000000 / width) { + PNG_CLEANUP +#ifdef HAS_DUMMY_CRASH + #ifdef __aarch64__ + asm volatile (".word 0xf7f0a000\n"); + #else + asm("ud2"); + #endif +#endif + return 0; + } + + // Set several transforms that browsers typically use: + png_set_gray_to_rgb(png_handler.png_ptr); + png_set_expand(png_handler.png_ptr); + png_set_packing(png_handler.png_ptr); + png_set_scale_16(png_handler.png_ptr); + png_set_tRNS_to_alpha(png_handler.png_ptr); + + int passes = png_set_interlace_handling(png_handler.png_ptr); + + png_read_update_info(png_handler.png_ptr, png_handler.info_ptr); + + png_handler.row_ptr = png_malloc( + png_handler.png_ptr, png_get_rowbytes(png_handler.png_ptr, + png_handler.info_ptr)); + + for (int pass = 0; pass < passes; ++pass) { + for (png_uint_32 y = 0; y < height; ++y) { + png_read_row(png_handler.png_ptr, + static_cast(png_handler.row_ptr), nullptr); + } + } + + png_read_end(png_handler.png_ptr, png_handler.end_info_ptr); + + PNG_CLEANUP + return 0; +} + +int main() { + + uint8_t buf [10] = {0}; + LLVMFuzzerTestOneInput(buf, 10); + +} diff --git a/fuzzers/qemu_launcher/libpng_harness b/fuzzers/qemu_launcher/libpng_harness new file mode 100755 index 0000000000..d431945aee Binary files /dev/null and b/fuzzers/qemu_launcher/libpng_harness differ diff --git a/fuzzers/qemu_launcher/src/main.rs b/fuzzers/qemu_launcher/src/main.rs new file mode 100644 index 0000000000..d3a5f5e670 --- /dev/null +++ b/fuzzers/qemu_launcher/src/main.rs @@ -0,0 +1,201 @@ +use core::time::Duration; +use std::{env, path::PathBuf, process}; + +use libafl::{ + bolts::{ + current_nanos, + launcher::Launcher, + rands::StdRand, + shmem::{ShMemProvider, StdShMemProvider}, + tuples::tuple_list, + }, + corpus::{ + Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, + QueueCorpusScheduler, + }, + events::EventConfig, + executors::{ExitKind, TimeoutExecutor}, + feedback_or, feedback_or_fast, + feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + fuzzer::{Fuzzer, StdFuzzer}, + inputs::{BytesInput, HasTargetBytes}, + monitors::MultiMonitor, + mutators::scheduled::{havoc_mutations, StdScheduledMutator}, + observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, + stages::StdMutationalStage, + state::{HasCorpus, StdState}, + Error, +}; +use libafl_qemu::{ + edges, edges::QemuEdgeCoverageHelper, elf::EasyElf, emu, MmapPerms, QemuExecutor, Regs, +}; + +pub fn main() { + // Hardcoded parameters + let timeout = Duration::from_secs(1); + let broker_port = 1337; + let cores = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + let corpus_dirs = [PathBuf::from("./corpus")]; + let objective_dir = PathBuf::from("./crashes"); + + // Initialize QEMU + let args: Vec = env::args().collect(); + let env: Vec<(String, String)> = env::vars().collect(); + emu::init(&args, &env); + + let mut elf_buffer = Vec::new(); + let elf = EasyElf::from_file(emu::binary_path(), &mut elf_buffer).unwrap(); + + let test_one_input_ptr = elf + .resolve_symbol("LLVMFuzzerTestOneInput", emu::load_addr()) + .expect("Symbol LLVMFuzzerTestOneInput not found"); + println!("LLVMFuzzerTestOneInput @ {:#x}", test_one_input_ptr); + + emu::set_breakpoint(test_one_input_ptr); // LLVMFuzzerTestOneInput + emu::run(); + + println!( + "Break at {:#x}", + emu::read_reg::<_, u64>(Regs::Rip).unwrap() + ); + + // Get the return address + let stack_ptr: u64 = emu::read_reg(Regs::Rsp).unwrap(); + let mut ret_addr = [0u64]; + emu::read_mem(stack_ptr, &mut ret_addr); + let ret_addr = ret_addr[0]; + + println!("Stack pointer = {:#x}", stack_ptr); + println!("Return address = {:#x}", ret_addr); + + emu::remove_breakpoint(test_one_input_ptr); // LLVMFuzzerTestOneInput + emu::set_breakpoint(ret_addr); // LLVMFuzzerTestOneInput ret addr + + let input_addr = emu::map_private(0, 4096, MmapPerms::ReadWrite).unwrap(); + println!("Placing input at {:#x}", input_addr); + + // The wrapped harness function, calling out to the LLVM-style harness + let mut harness = |input: &BytesInput| { + let target = input.target_bytes(); + let mut buf = target.as_slice(); + let mut len = buf.len(); + if len > 4096 { + buf = &buf[0..4096]; + len = 4096; + } + + emu::write_mem(input_addr, buf); + + emu::write_reg(Regs::Rdi, input_addr).unwrap(); + emu::write_reg(Regs::Rsi, len).unwrap(); + emu::write_reg(Regs::Rip, test_one_input_ptr).unwrap(); + emu::write_reg(Regs::Rsp, stack_ptr).unwrap(); + + emu::run(); + + ExitKind::Ok + }; + + let mut run_client = |state: Option<_>, mut mgr, _core_id| { + // Create an observation channel using the coverage map + let edges = unsafe { &mut edges::EDGES_MAP }; + let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM }; + let edges_observer = + HitcountsMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter)); + + // Create an observation channel to keep track of the execution time + let time_observer = TimeObserver::new("time"); + + // The state of the edges feedback. + let feedback_state = MapFeedbackState::with_observer(&edges_observer); + + // Feedback to rate the interestingness of an input + // This one is composed by two Feedbacks in OR + let feedback = feedback_or!( + // New maximization map feedback linked to the edges observer and the feedback state + MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + // Time feedback, this one does not need a feedback state + TimeFeedback::new_with_observer(&time_observer) + ); + + // A feedback to choose if an input is a solution or not + let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + + // If not restarting, create a State from scratch + let mut state = state.unwrap_or_else(|| { + StdState::new( + // RNG + StdRand::with_seed(current_nanos()), + // Corpus that will be evolved, we keep it in memory for performance + InMemoryCorpus::new(), + // Corpus in which we store solutions (crashes in this example), + // on disk so the user can get them after stopping the fuzzer + OnDiskCorpus::new(objective_dir.clone()).unwrap(), + // States of the feedbacks. + // They are the data related to the feedbacks that you want to persist in the State. + tuple_list!(feedback_state), + ) + }); + + // A minimization+queue policy to get testcasess from the corpus + let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); + + // A fuzzer with feedbacks and a corpus scheduler + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); + + // Create a QEMU in-process executor + let executor = QemuExecutor::new( + &mut harness, + // The QEMU helpers define common hooks like coverage tracking hooks + tuple_list!(QemuEdgeCoverageHelper::new()), + tuple_list!(edges_observer, time_observer), + &mut fuzzer, + &mut state, + &mut mgr, + ) + .expect("Failed to create QemuExecutor"); + + // Wrap the executor to keep track of the timeout + let mut executor = TimeoutExecutor::new(executor, timeout); + + if state.corpus().count() < 1 { + state + .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &corpus_dirs) + .unwrap_or_else(|_| { + println!("Failed to load initial corpus at {:?}", &corpus_dirs); + process::exit(0); + }); + println!("We imported {} inputs from disk.", state.corpus().count()); + } + + // Setup an havoc mutator with a mutational stage + let mutator = StdScheduledMutator::new(havoc_mutations()); + let mut stages = tuple_list!(StdMutationalStage::new(mutator)); + + fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; + Ok(()) + }; + + // The shared memory allocator + let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); + + // The stats reporter for the broker + let monitor = MultiMonitor::new(|s| println!("{}", s)); + + // Build and run a Launcher + match Launcher::builder() + .shmem_provider(shmem_provider) + .broker_port(broker_port) + .configuration(EventConfig::from_build_id()) + .monitor(monitor) + .run_client(&mut run_client) + .cores(&cores) + .stdout_file(Some("/dev/null")) + .build() + .launch() + { + Ok(()) => (), + Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."), + Err(err) => panic!("Failed to run launcher: {:?}", err), + } +} diff --git a/fuzzers/tutorial/Cargo.toml b/fuzzers/tutorial/Cargo.toml index bf96d69025..7f122440e0 100644 --- a/fuzzers/tutorial/Cargo.toml +++ b/fuzzers/tutorial/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tutorial" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index ed37ce0fe4..528cd5ce9d 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi ", "Dominik Maier "] description = "Slot your own fuzzers together and extend their features using Rust" documentation = "https://docs.rs/libafl" @@ -59,7 +59,7 @@ typed-builder = "0.9.0" # Implement the builder pattern at compiletime ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown intervaltree = { git = "https://github.com/andreafioraldi/rust-intervaltree", version = "0.2.6", default-features = false, features = ["serde"] } -libafl_derive = { version = "0.6.1", optional = true, path = "../libafl_derive" } +libafl_derive = { version = "0.7.0", optional = true, path = "../libafl_derive" } serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } # an easy way to debug print SerdeAnyMap miniz_oxide = { version = "0.4.4", optional = true} core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs", rev = "6648a7a", optional = true } diff --git a/libafl_cc/Cargo.toml b/libafl_cc/Cargo.toml index 8c34aa1324..a5bb7cebeb 100644 --- a/libafl_cc/Cargo.toml +++ b/libafl_cc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_cc" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi "] description = "Commodity library to wrap compilers and link LibAFL" documentation = "https://docs.rs/libafl_cc" diff --git a/libafl_concolic/symcc_libafl/Cargo.toml b/libafl_concolic/symcc_libafl/Cargo.toml index 190bf8832d..1942c70d3f 100644 --- a/libafl_concolic/symcc_libafl/Cargo.toml +++ b/libafl_concolic/symcc_libafl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "symcc_libafl" -version = "0.1.0" +version = "0.7.0" edition = "2021" authors = ["Julius Hohnerlein ", "Andrea Fioraldi ", "Dominik Maier "] description = "Meta package for symcc_runtime" diff --git a/libafl_concolic/symcc_runtime/Cargo.toml b/libafl_concolic/symcc_runtime/Cargo.toml index 25aef24d70..b1ca50e98a 100644 --- a/libafl_concolic/symcc_runtime/Cargo.toml +++ b/libafl_concolic/symcc_runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "symcc_runtime" -version = "0.1.2" +version = "0.7.0" edition = "2021" authors = ["Julius Hohnerlein ", "Andrea Fioraldi ", "Dominik Maier "] description = "Build Concolic Tracing tools based on SymCC in Rust" @@ -21,7 +21,7 @@ no-cpp-runtime = [] unchecked_unwrap = "3" ctor = "0.1" libc = "0.2" -libafl = {path = "../../libafl", version="0.6", default-features=false, features=["std"]} +libafl = {path = "../../libafl", version="0.7", default-features=false, features=["std"]} [build-dependencies] cmake = "0.1" @@ -29,4 +29,4 @@ bindgen = "0.59" regex = "1" lazy_static = "1.4" which = "4.1" -symcc_libafl = {path = "../symcc_libafl", version="0.1"} +symcc_libafl = {path = "../symcc_libafl", version="0.7"} diff --git a/libafl_derive/Cargo.toml b/libafl_derive/Cargo.toml index 816ea2db74..8100c62d94 100644 --- a/libafl_derive/Cargo.toml +++ b/libafl_derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_derive" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi "] description = "Derive proc-macro crate for LibAFL" documentation = "https://docs.rs/libafl_derive" diff --git a/libafl_frida/Cargo.toml b/libafl_frida/Cargo.toml index fc489015f2..a862bdbe05 100644 --- a/libafl_frida/Cargo.toml +++ b/libafl_frida/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_frida" -version = "0.6.1" +version = "0.7.0" authors = ["s1341 "] description = "Frida backend library for LibAFL" documentation = "https://docs.rs/libafl_frida" @@ -19,8 +19,8 @@ cmplog = [] cc = { version = "1.0", features = ["parallel"] } [dependencies] -libafl = { path = "../libafl", version = "0.6.1", features = ["std", "libafl_derive"] } -libafl_targets = { path = "../libafl_targets", version = "0.6.1", features = ["std", "sancov_cmplog"] } +libafl = { path = "../libafl", version = "0.7.0", features = ["std", "libafl_derive"] } +libafl_targets = { path = "../libafl_targets", version = "0.7.0", features = ["std", "sancov_cmplog"] } nix = "0.23.0" libc = "0.2" hashbrown = "0.11" diff --git a/libafl_qemu/Cargo.toml b/libafl_qemu/Cargo.toml index 3ebd715ed0..afc2cabf68 100644 --- a/libafl_qemu/Cargo.toml +++ b/libafl_qemu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_qemu" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi "] description = "QEMU user backend library for LibAFL" documentation = "https://docs.rs/libafl_qemu" @@ -15,8 +15,8 @@ python = ["pyo3", "pyo3-build-config"] default = [] [dependencies] -libafl = { path = "../libafl", version = "0.6.1" } -libafl_targets = { path = "../libafl_targets", version = "0.6.1" } +libafl = { path = "../libafl", version = "0.7.0" } +libafl_targets = { path = "../libafl_targets", version = "0.7.0" } serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible num-traits = "0.2" diff --git a/libafl_sugar/Cargo.toml b/libafl_sugar/Cargo.toml index d16b5540cf..631e837d37 100644 --- a/libafl_sugar/Cargo.toml +++ b/libafl_sugar/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_sugar" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi "] description = "Sugar builders to create common fuzzers with LibAFL" documentation = "https://docs.rs/libafl_sugar" @@ -19,9 +19,9 @@ default = [] pyo3-build-config = { version = "0.14.5", optional = true } [dependencies] -libafl = { path = "../libafl", version = "0.6.1" } -libafl_targets = { path = "../libafl_targets", version = "0.6.1" } -libafl_qemu = { path = "../libafl_qemu", version = "0.6.1" } +libafl = { path = "../libafl", version = "0.7.0" } +libafl_targets = { path = "../libafl_targets", version = "0.7.0" } +libafl_qemu = { path = "../libafl_qemu", version = "0.7.0" } typed-builder = "0.9.0" # Implement the builder pattern at compiletime #pyo3 = { version = "0.14.3", features = ["extension-module"], optional = true } pyo3 = { version = "0.14.3", optional = true } diff --git a/libafl_targets/Cargo.toml b/libafl_targets/Cargo.toml index 40e837fa88..6168b13539 100644 --- a/libafl_targets/Cargo.toml +++ b/libafl_targets/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libafl_targets" -version = "0.6.1" +version = "0.7.0" authors = ["Andrea Fioraldi "] description = "Common code for target instrumentation that can be used combined with LibAFL" documentation = "https://docs.rs/libafl_targets" @@ -28,6 +28,6 @@ cc = { version = "1.0", features = ["parallel"] } [dependencies] rangemap = "0.1.10" -libafl = { path = "../libafl", version = "0.6.1", features = [] } +libafl = { path = "../libafl", version = "0.7.0", features = [] } serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib # serde-big-array = "0.3.2"