Merge branch 'dev' of github.com:AFLplusplus/libAFLrs into dev
This commit is contained in:
commit
73ceb928ae
@ -13,4 +13,5 @@ members = [
|
|||||||
#example fuzzers
|
#example fuzzers
|
||||||
"fuzzers/libfuzzer_libpng",
|
"fuzzers/libfuzzer_libpng",
|
||||||
"fuzzers/libfuzzer_libmozjpeg",
|
"fuzzers/libfuzzer_libmozjpeg",
|
||||||
|
"fuzzers/libfuzzer_libpng_cmpalloc",
|
||||||
]
|
]
|
||||||
|
@ -23,7 +23,7 @@ We're still working on the documentation. In the meantime, you can watch the Vid
|
|||||||
|
|
||||||
+ ~~Minset corpus scheduler~~ still doc missing
|
+ ~~Minset corpus scheduler~~ still doc missing
|
||||||
+ Win32 shared mem and crash handler to have Windows in-process executor
|
+ Win32 shared mem and crash handler to have Windows in-process executor
|
||||||
+ Other feedbacks examples (e.g. maximize allocations to spot OOMs)
|
+ ~~Other feedbacks examples (e.g. maximize allocations to spot OOMs)~~
|
||||||
+ Other objectives examples (e.g. execution of a given program point)
|
+ Other objectives examples (e.g. execution of a given program point)
|
||||||
+ ~~A macro crate with derive directives (e.g. for SerdeAny impl)~~ just `derive(SerdeAny)`, missing doc.
|
+ ~~A macro crate with derive directives (e.g. for SerdeAny impl)~~ just `derive(SerdeAny)`, missing doc.
|
||||||
+ Good documentation
|
+ Good documentation
|
||||||
|
2
TODO.md
2
TODO.md
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
- [x] ~~Minset corpus scheduler~~ still doc missing
|
- [x] ~~Minset corpus scheduler~~ still doc missing
|
||||||
- [ ] Win32 shared mem and crash handler to have Windows in-process executor
|
- [ ] Win32 shared mem and crash handler to have Windows in-process executor
|
||||||
- [ ] Other feedbacks examples (e.g. maximize allocations to spot OOMs)
|
- [x] Other feedbacks examples (e.g. maximize allocations to spot OOMs)
|
||||||
- [ ] Other objectives examples (e.g. execution of a given program point)
|
- [ ] Other objectives examples (e.g. execution of a given program point)
|
||||||
- [ ] Objective-Specific Corpuses (named per objective)
|
- [ ] Objective-Specific Corpuses (named per objective)
|
||||||
- [x] A macro crate with derive directives (e.g. for SerdeAny impl).
|
- [x] A macro crate with derive directives (e.g. for SerdeAny impl).
|
||||||
|
1
fuzzers/libfuzzer_libpng_cmpalloc/.gitignore
vendored
Normal file
1
fuzzers/libfuzzer_libpng_cmpalloc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
libpng-*
|
31
fuzzers/libfuzzer_libpng_cmpalloc/Cargo.toml
Normal file
31
fuzzers/libfuzzer_libpng_cmpalloc/Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[package]
|
||||||
|
name = "libfuzzer_libpng_cmpalloc"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
|
||||||
|
#[profile.release]
|
||||||
|
#lto = true
|
||||||
|
#codegen-units = 1
|
||||||
|
#opt-level = 3
|
||||||
|
#debug = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
num_cpus = "1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/" }
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "libfuzzer_libpng_cmpalloc"
|
||||||
|
path = "./src/fuzzer.rs"
|
||||||
|
test = false
|
||||||
|
bench = false
|
28
fuzzers/libfuzzer_libpng_cmpalloc/README.md
Normal file
28
fuzzers/libfuzzer_libpng_cmpalloc/README.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Libfuzzer for libpng (cmp+alloc)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The difference between the normal Libfuzzer for libpng example here is that this fuzzer is not just using edge coverage as feedback but also comparisons values (-value-profile like) and allocations sizes.
|
||||||
|
This is an example how multiple feedbacks can be combined in a fuzzer.
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
To build this example, run `cargo build --example libfuzzer_libpng_cmpalloc --release`.
|
||||||
|
This will call (the build.rs)[./builld.rs], which in turn downloads a libpng archive from the web.
|
||||||
|
Then, it will link (the fuzzer)[./src/fuzzer.rs] against (the C++ harness)[./harness.cc] and the instrumented `libpng`.
|
||||||
|
Afterwards, the fuzzer will be ready to run, from `../../target/examples/libfuzzer_libpng_cmpalloc`.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
Each following execution will run a fuzzer client.
|
||||||
|
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).
|
||||||
|
|
||||||
|
For convenience, you may just run `./test.sh` in this folder to test it.
|
109
fuzzers/libfuzzer_libpng_cmpalloc/build.rs
Normal file
109
fuzzers/libfuzzer_libpng_cmpalloc/build.rs
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// build.rs
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
env,
|
||||||
|
path::Path,
|
||||||
|
process::{exit, Command},
|
||||||
|
};
|
||||||
|
|
||||||
|
const LIBPNG_URL: &str =
|
||||||
|
"https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz";
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if cfg!(windows) {
|
||||||
|
println!("cargo:warning=Skipping libpng example on Windows");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
let cwd = env::current_dir().unwrap().to_string_lossy().to_string();
|
||||||
|
let out_dir = out_dir.to_string_lossy().to_string();
|
||||||
|
let out_dir_path = Path::new(&out_dir);
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=../libfuzzer_runtime/rt.c",);
|
||||||
|
println!("cargo:rerun-if-changed=harness.cc");
|
||||||
|
|
||||||
|
let libpng = format!("{}/libpng-1.6.37", &out_dir);
|
||||||
|
let libpng_path = Path::new(&libpng);
|
||||||
|
let libpng_tar = format!("{}/libpng-1.6.37.tar.xz", &cwd);
|
||||||
|
|
||||||
|
// Enforce clang for its -fsanitize-coverage support.
|
||||||
|
std::env::set_var("CC", "clang");
|
||||||
|
std::env::set_var("CXX", "clang++");
|
||||||
|
let ldflags = match env::var("LDFLAGS") {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(_) => "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !libpng_path.is_dir() {
|
||||||
|
if !Path::new(&libpng_tar).is_file() {
|
||||||
|
println!("cargo:warning=Libpng not found, downloading...");
|
||||||
|
// Download libpng
|
||||||
|
Command::new("wget")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(LIBPNG_URL)
|
||||||
|
.arg("-O")
|
||||||
|
.arg(&libpng_tar)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
Command::new("tar")
|
||||||
|
.current_dir(&out_dir_path)
|
||||||
|
.arg("-xvf")
|
||||||
|
.arg(&libpng_tar)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
Command::new(format!("{}/configure", &libpng))
|
||||||
|
.current_dir(&libpng_path)
|
||||||
|
.args(&[
|
||||||
|
"--disable-shared",
|
||||||
|
&format!("--host={}", env::var("TARGET").unwrap())[..],
|
||||||
|
])
|
||||||
|
.env("CC", "clang")
|
||||||
|
.env("CXX", "clang++")
|
||||||
|
.env(
|
||||||
|
"CFLAGS",
|
||||||
|
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||||
|
)
|
||||||
|
.env(
|
||||||
|
"CXXFLAGS",
|
||||||
|
"-O3 -g -D_DEFAULT_SOURCE -fPIE -fsanitize-coverage=trace-pc-guard",
|
||||||
|
)
|
||||||
|
.env(
|
||||||
|
"LDFLAGS",
|
||||||
|
format!("-g -fPIE -fsanitize-coverage=trace-pc-guard {}", ldflags),
|
||||||
|
)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
Command::new("make")
|
||||||
|
.current_dir(&libpng_path)
|
||||||
|
.status()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
cc::Build::new()
|
||||||
|
.file("../libfuzzer_runtime/rt.c")
|
||||||
|
.compile("libfuzzer-sys");
|
||||||
|
|
||||||
|
cc::Build::new()
|
||||||
|
.include(&libpng_path)
|
||||||
|
.cpp(true)
|
||||||
|
.flag("-fsanitize-coverage=trace-pc-guard")
|
||||||
|
// .define("HAS_DUMMY_CRASH", "1")
|
||||||
|
.file("./harness.cc")
|
||||||
|
.compile("libfuzzer-harness");
|
||||||
|
|
||||||
|
println!("cargo:rustc-link-search=native={}", &out_dir);
|
||||||
|
println!("cargo:rustc-link-search=native={}/.libs", &libpng);
|
||||||
|
println!("cargo:rustc-link-lib=static=png16");
|
||||||
|
|
||||||
|
//Deps for libpng: -pthread -lz -lm
|
||||||
|
println!("cargo:rustc-link-lib=dylib=m");
|
||||||
|
println!("cargo:rustc-link-lib=dylib=z");
|
||||||
|
|
||||||
|
//For the C++ harness
|
||||||
|
//must by dylib for android
|
||||||
|
println!("cargo:rustc-link-lib=dylib=stdc++");
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
}
|
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty.png
Normal file
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_alpha.png
Normal file
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 376 B |
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_gamma.png
Normal file
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_gamma.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 228 B |
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_icc.png
Normal file
BIN
fuzzers/libfuzzer_libpng_cmpalloc/corpus/not_kitty_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 B |
197
fuzzers/libfuzzer_libpng_cmpalloc/harness.cc
Normal file
197
fuzzers/libfuzzer_libpng_cmpalloc/harness.cc
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// 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 <string.h>" 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 <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#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<BufState*>(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<unsigned char> 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_bytep>(png_handler.row_ptr), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
png_read_end(png_handler.png_ptr, png_handler.end_info_ptr);
|
||||||
|
|
||||||
|
PNG_CLEANUP
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
199
fuzzers/libfuzzer_libpng_cmpalloc/src/fuzzer.rs
Normal file
199
fuzzers/libfuzzer_libpng_cmpalloc/src/fuzzer.rs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
|
//! The example harness is built for libpng.
|
||||||
|
|
||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libafl::{
|
||||||
|
bolts::{shmem::UnixShMem, tuples::tuple_list},
|
||||||
|
corpus::{
|
||||||
|
Corpus, InMemoryCorpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus,
|
||||||
|
QueueCorpusScheduler,
|
||||||
|
},
|
||||||
|
events::setup_restarting_mgr,
|
||||||
|
executors::{inprocess::InProcessExecutor, Executor, ExitKind},
|
||||||
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||||
|
fuzzer::{Fuzzer, HasCorpusScheduler, StdFuzzer},
|
||||||
|
inputs::Input,
|
||||||
|
mutators::{scheduled::HavocBytesMutator, token_mutations::Tokens},
|
||||||
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
|
stages::mutational::StdMutationalStage,
|
||||||
|
state::{HasCorpus, HasMetadata, State},
|
||||||
|
stats::SimpleStats,
|
||||||
|
utils::{current_nanos, StdRand},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
const MAP_SIZE: usize = 16 * 1024;
|
||||||
|
|
||||||
|
/// We will interact with a C++ target, so use external c functionality
|
||||||
|
#[cfg(unix)]
|
||||||
|
extern "C" {
|
||||||
|
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||||
|
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
|
||||||
|
|
||||||
|
// afl_libfuzzer_init calls LLVMFUzzerInitialize()
|
||||||
|
fn afl_libfuzzer_init() -> i32;
|
||||||
|
|
||||||
|
static __lafl_edges_map: *mut u8;
|
||||||
|
static __lafl_cmp_map: *mut u8;
|
||||||
|
static __lafl_alloc_map: *mut usize;
|
||||||
|
static __lafl_max_edges_size: u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The wrapped harness function, calling out to the LLVM-style harness
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn harness<E, I>(_executor: &E, buf: &[u8]) -> ExitKind
|
||||||
|
where
|
||||||
|
E: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
// println!("{:?}", buf);
|
||||||
|
unsafe {
|
||||||
|
LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len());
|
||||||
|
}
|
||||||
|
ExitKind::Ok
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main fn, usually parsing parameters, and starting the fuzzer
|
||||||
|
pub fn main() {
|
||||||
|
// Registry the metadata types used in this fuzzer
|
||||||
|
// Needed only on no_std
|
||||||
|
//RegistryBuilder::register::<Tokens>();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Workdir: {:?}",
|
||||||
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
|
);
|
||||||
|
fuzz(
|
||||||
|
vec![PathBuf::from("./corpus")],
|
||||||
|
PathBuf::from("./crashes"),
|
||||||
|
1337,
|
||||||
|
)
|
||||||
|
.expect("An error occurred while fuzzing");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Not supported on windows right now
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn fuzz(_corpus_dirs: Vec<PathBuf>, _objective_dir: PathBuf, _broker_port: u16) -> Result<(), ()> {
|
||||||
|
todo!("Example not supported on Windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The actual fuzzer
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
|
||||||
|
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
|
||||||
|
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||||
|
|
||||||
|
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
|
||||||
|
let (state, mut restarting_mgr) =
|
||||||
|
match setup_restarting_mgr::<_, _, UnixShMem, _>(stats, broker_port) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => match err {
|
||||||
|
Error::ShuttingDown => {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("Failed to setup the restarter: {}", err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let edges_observer = HitcountsMapObserver::new(unsafe {
|
||||||
|
StdMapObserver::new_from_ptr("edges", __lafl_edges_map, __lafl_max_edges_size as usize)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create an observation channel using the cmp map
|
||||||
|
let cmps_observer = unsafe { StdMapObserver::new_from_ptr("cmps", __lafl_cmp_map, MAP_SIZE) };
|
||||||
|
|
||||||
|
// Create an observation channel using the allocations map
|
||||||
|
let allocs_observer =
|
||||||
|
unsafe { StdMapObserver::new_from_ptr("allocs", __lafl_alloc_map, MAP_SIZE) };
|
||||||
|
|
||||||
|
// If not restarting, create a State from scratch
|
||||||
|
let mut state = state.unwrap_or_else(|| {
|
||||||
|
State::new(
|
||||||
|
// RNG
|
||||||
|
StdRand::with_seed(current_nanos()),
|
||||||
|
// Corpus that will be evolved, we keep it in memory for performance
|
||||||
|
InMemoryCorpus::new(),
|
||||||
|
// Feedbacks to rate the interestingness of an input
|
||||||
|
tuple_list!(
|
||||||
|
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||||
|
MaxMapFeedback::new_with_observer(&cmps_observer),
|
||||||
|
MaxMapFeedback::new_with_observer(&allocs_observer),
|
||||||
|
TimeFeedback::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).unwrap(),
|
||||||
|
// Feedbacks to recognize an input as solution
|
||||||
|
tuple_list!(CrashFeedback::new()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("We're a client, let's fuzz :)");
|
||||||
|
|
||||||
|
// Create a PNG dictionary if not existing
|
||||||
|
if state.metadata().get::<Tokens>().is_none() {
|
||||||
|
state.add_metadata(Tokens::new(vec![
|
||||||
|
vec![137, 80, 78, 71, 13, 10, 26, 10], // PNG header
|
||||||
|
"IHDR".as_bytes().to_vec(),
|
||||||
|
"IDAT".as_bytes().to_vec(),
|
||||||
|
"PLTE".as_bytes().to_vec(),
|
||||||
|
"IEND".as_bytes().to_vec(),
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a basic mutator with a mutational stage
|
||||||
|
let mutator = HavocBytesMutator::default();
|
||||||
|
let stage = StdMutationalStage::new(mutator);
|
||||||
|
|
||||||
|
// A fuzzer with just one stage and a minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new());
|
||||||
|
let fuzzer = StdFuzzer::new(scheduler, tuple_list!(stage));
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with just one observer for edge coverage
|
||||||
|
let mut executor = InProcessExecutor::new(
|
||||||
|
"in-process(edges,cmps,allocs)",
|
||||||
|
harness,
|
||||||
|
tuple_list!(
|
||||||
|
edges_observer,
|
||||||
|
cmps_observer,
|
||||||
|
allocs_observer,
|
||||||
|
TimeObserver::new("time")
|
||||||
|
),
|
||||||
|
&mut state,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// The actual target run starts here.
|
||||||
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
unsafe {
|
||||||
|
if afl_libfuzzer_init() == -1 {
|
||||||
|
println!("Warning: LLVMFuzzerInitialize failed with -1")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// In case the corpus is empty (on first run), reset
|
||||||
|
if state.corpus().count() < 1 {
|
||||||
|
state
|
||||||
|
.load_initial_inputs(
|
||||||
|
&mut executor,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
fuzzer.scheduler(),
|
||||||
|
&corpus_dirs,
|
||||||
|
)
|
||||||
|
.expect(&format!(
|
||||||
|
"Failed to load initial corpus at {:?}",
|
||||||
|
&corpus_dirs
|
||||||
|
));
|
||||||
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(&mut state, &mut executor, &mut restarting_mgr)?;
|
||||||
|
|
||||||
|
// Never reached
|
||||||
|
Ok(())
|
||||||
|
}
|
17
fuzzers/libfuzzer_libpng_cmpalloc/test.sh
Executable file
17
fuzzers/libfuzzer_libpng_cmpalloc/test.sh
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p ./crashes
|
||||||
|
|
||||||
|
cargo build --example libfuzzer_libpng --release || exit 1
|
||||||
|
cp ../../target/release/examples/libfuzzer_libpng ./.libfuzzer_test.elf
|
||||||
|
|
||||||
|
# The broker
|
||||||
|
RUST_BACKTRACE=full taskset 0 ./.libfuzzer_test.elf &
|
||||||
|
# Give the broker time to spawn
|
||||||
|
sleep 2
|
||||||
|
echo "Spawning client"
|
||||||
|
# The 1st fuzzer client, pin to cpu 0x1
|
||||||
|
RUST_BACKTRACE=full taskset 1 ./.libfuzzer_test.elf 2>/dev/null
|
||||||
|
|
||||||
|
killall .libfuzzer_test.elf
|
||||||
|
rm -rf ./.libfuzzer_test.elf
|
@ -3,7 +3,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define MAP_SIZE 65536
|
#define MAP_SIZE (16*1024)
|
||||||
|
|
||||||
int orig_argc;
|
int orig_argc;
|
||||||
char **orig_argv;
|
char **orig_argv;
|
||||||
@ -156,9 +156,10 @@ void *calloc(size_t nmemb, size_t size) {
|
|||||||
k &= MAP_SIZE - 1;
|
k &= MAP_SIZE - 1;
|
||||||
__lafl_alloc_map[k] = MAX(__lafl_alloc_map[k], size);
|
__lafl_alloc_map[k] = MAX(__lafl_alloc_map[k], size);
|
||||||
|
|
||||||
void *result = realloc(NULL, size);
|
void *ret = NULL;
|
||||||
memset(result, 0, size);
|
posix_memalign(&ret, 1<<6, size);
|
||||||
return result;
|
memset(ret, 0, size);
|
||||||
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user