Implement coverage accounting (BB metric atm) (#507)
* bb accounting llvm pass * bb metric * accoutning corpus scheduler * fix warnings * alloc * clippy * fix dockerfile * clippy * coverage accounting example * finish CoverageAccountingCorpusScheduler * fmt * --libs in llvm-config * merge
This commit is contained in:
parent
6810e6085b
commit
dd002a081b
@ -43,9 +43,9 @@ COPY libafl_sugar/Cargo.toml libafl_sugar/
|
|||||||
COPY scripts/dummy.rs libafl_sugar/src/lib.rs
|
COPY scripts/dummy.rs libafl_sugar/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_cc/Cargo.toml libafl_cc/Cargo.toml
|
COPY libafl_cc/Cargo.toml libafl_cc/Cargo.toml
|
||||||
COPY scripts/dummy.rs libafl_cc/src/lib.rs
|
|
||||||
COPY libafl_cc/build.rs libafl_cc/build.rs
|
COPY libafl_cc/build.rs libafl_cc/build.rs
|
||||||
COPY libafl_cc/src/cmplog-routines-pass.cc libafl_cc/src/cmplog-routines-pass.cc
|
COPY libafl_cc/src libafl_cc/src
|
||||||
|
COPY scripts/dummy.rs libafl_cc/src/lib.rs
|
||||||
|
|
||||||
COPY libafl_targets/Cargo.toml libafl_targets/build.rs libafl_targets/
|
COPY libafl_targets/Cargo.toml libafl_targets/build.rs libafl_targets/
|
||||||
COPY libafl_targets/src libafl_targets/src
|
COPY libafl_targets/src libafl_targets/src
|
||||||
|
1
fuzzers/libfuzzer_libpng_accounting/.gitignore
vendored
Normal file
1
fuzzers/libfuzzer_libpng_accounting/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
libpng-*
|
32
fuzzers/libfuzzer_libpng_accounting/Cargo.toml
Normal file
32
fuzzers/libfuzzer_libpng_accounting/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "libfuzzer_libpng_launcher"
|
||||||
|
version = "0.7.1"
|
||||||
|
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
which = { version = "4.0.2" }
|
||||||
|
num_cpus = "1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libafl = { path = "../../libafl/", features = ["std", "derive", "llmp_compression", "introspection"] }
|
||||||
|
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "libfuzzer"] }
|
||||||
|
# TODO Include it only when building cc
|
||||||
|
libafl_cc = { path = "../../libafl_cc/" }
|
||||||
|
clap = { version = "3.0", features = ["derive"] }
|
||||||
|
mimalloc = { version = "*", default-features = false }
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "libfuzzer_libpng"
|
||||||
|
crate-type = ["staticlib"]
|
50
fuzzers/libfuzzer_libpng_accounting/Makefile
Normal file
50
fuzzers/libfuzzer_libpng_accounting/Makefile
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
FUZZER_NAME="fuzzer_libpng"
|
||||||
|
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/libafl_cxx: src/* src/bin/*
|
||||||
|
# Build the libpng libfuzzer library
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
libafl_cxx: target/release/libafl_cxx
|
||||||
|
|
||||||
|
libafl_cc: target/release/libafl_cxx
|
||||||
|
|
||||||
|
libpng-1.6.37/.libs/libpng16.a: libpng-1.6.37 libafl_cc
|
||||||
|
cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes
|
||||||
|
$(MAKE) -C libpng-1.6.37 CC="$(PROJECT_DIR)/target/release/libafl_cc" CXX="$(PROJECT_DIR)/target/release/libafl_cxx"
|
||||||
|
|
||||||
|
|
||||||
|
fuzzer: libpng-1.6.37/.libs/libpng16.a libafl_cxx
|
||||||
|
# Build the libpng libfuzzer library
|
||||||
|
cargo build --release
|
||||||
|
|
||||||
|
# Build the libpng harness
|
||||||
|
target/release/libafl_cxx \
|
||||||
|
$(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
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm ./$(FUZZER_NAME)
|
||||||
|
$(MAKE) -C libpng-1.6.37 clean
|
||||||
|
|
||||||
|
run: all
|
||||||
|
./$(FUZZER_NAME) --cores 0 --input ./corpus &
|
||||||
|
|
||||||
|
short_test: all
|
||||||
|
rm -rf libafl_unix_shmem_server || true
|
||||||
|
timeout 10s ./$(FUZZER_NAME) --cores 0 --input ./corpus &
|
||||||
|
|
||||||
|
test: all
|
||||||
|
timeout 60s ./$(FUZZER_NAME) --cores 0 --input ./corpus &
|
47
fuzzers/libfuzzer_libpng_accounting/README.md
Normal file
47
fuzzers/libfuzzer_libpng_accounting/README.md
Normal file
@ -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.
|
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty.png
Normal file
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_alpha.png
Normal file
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_alpha.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 376 B |
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_gamma.png
Normal file
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_gamma.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 228 B |
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_icc.png
Normal file
BIN
fuzzers/libfuzzer_libpng_accounting/corpus/not_kitty_icc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 427 B |
197
fuzzers/libfuzzer_libpng_accounting/harness.cc
Normal file
197
fuzzers/libfuzzer_libpng_accounting/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;
|
||||||
|
}
|
||||||
|
|
36
fuzzers/libfuzzer_libpng_accounting/src/bin/libafl_cc.rs
Normal file
36
fuzzers/libfuzzer_libpng_accounting/src/bin/libafl_cc.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if args.len() > 1 {
|
||||||
|
let mut dir = env::current_exe().unwrap();
|
||||||
|
let wrapper_name = dir.file_name().unwrap().to_str().unwrap();
|
||||||
|
|
||||||
|
let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() {
|
||||||
|
"cc" => false,
|
||||||
|
"++" | "pp" | "xx" => true,
|
||||||
|
_ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir),
|
||||||
|
};
|
||||||
|
|
||||||
|
dir.pop();
|
||||||
|
|
||||||
|
let mut cc = ClangWrapper::new();
|
||||||
|
if let Some(code) = cc
|
||||||
|
.cpp(is_cpp)
|
||||||
|
// silence the compiler wrapper output, needed for some configure scripts.
|
||||||
|
.silence(true)
|
||||||
|
.parse_args(&args)
|
||||||
|
.expect("Failed to parse the command line")
|
||||||
|
.link_staticlib(&dir, "libfuzzer_libpng")
|
||||||
|
.add_arg("-fsanitize-coverage=trace-pc-guard")
|
||||||
|
.add_pass(LLVMPasses::CoverageAccounting)
|
||||||
|
.run()
|
||||||
|
.expect("Failed to run the wrapped compiler")
|
||||||
|
{
|
||||||
|
std::process::exit(code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("LibAFL CC: No Arguments given");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
pub mod libafl_cc;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
libafl_cc::main()
|
||||||
|
}
|
272
fuzzers/libfuzzer_libpng_accounting/src/lib.rs
Normal file
272
fuzzers/libfuzzer_libpng_accounting/src/lib.rs
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
|
||||||
|
//! The example harness is built for libpng.
|
||||||
|
//! In this example, you will see the use of the `launcher` feature.
|
||||||
|
//! The `launcher` will spawn new processes for each cpu core.
|
||||||
|
use mimalloc::MiMalloc;
|
||||||
|
#[global_allocator]
|
||||||
|
static GLOBAL: MiMalloc = MiMalloc;
|
||||||
|
|
||||||
|
use clap::{self, StructOpt};
|
||||||
|
use core::time::Duration;
|
||||||
|
use std::{env, net::SocketAddr, path::PathBuf};
|
||||||
|
|
||||||
|
use libafl::{
|
||||||
|
bolts::{
|
||||||
|
current_nanos,
|
||||||
|
launcher::Launcher,
|
||||||
|
os::Cores,
|
||||||
|
rands::StdRand,
|
||||||
|
shmem::{ShMemProvider, StdShMemProvider},
|
||||||
|
tuples::{tuple_list, Merge},
|
||||||
|
AsSlice,
|
||||||
|
},
|
||||||
|
corpus::{
|
||||||
|
Corpus, CoverageAccountingCorpusScheduler, InMemoryCorpus, OnDiskCorpus,
|
||||||
|
QueueCorpusScheduler,
|
||||||
|
},
|
||||||
|
events::EventConfig,
|
||||||
|
executors::{inprocess::InProcessExecutor, 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, tokens_mutations, StdScheduledMutator},
|
||||||
|
mutators::token_mutations::Tokens,
|
||||||
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
|
stages::mutational::StdMutationalStage,
|
||||||
|
state::{HasCorpus, HasMetadata, StdState},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libafl_targets::{
|
||||||
|
libfuzzer_initialize, libfuzzer_test_one_input, ACCOUNTING_MEMOP_MAP, EDGES_MAP, MAX_EDGES_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Parse a millis string to a [`Duration`]. Used for arg parsing.
|
||||||
|
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
|
||||||
|
Ok(Duration::from_millis(time.parse()?))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The commandline args this fuzzer accepts
|
||||||
|
#[derive(Debug, StructOpt)]
|
||||||
|
#[clap(
|
||||||
|
name = "libfuzzer_libpng_launcher",
|
||||||
|
about = "A libfuzzer-like fuzzer for libpng with llmp-multithreading support and a launcher",
|
||||||
|
author = "Andrea Fioraldi <andreafioraldi@gmail.com>, Dominik Maier <domenukk@gmail.com>"
|
||||||
|
)]
|
||||||
|
struct Opt {
|
||||||
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str = Cores::from_cmdline),
|
||||||
|
help = "Spawn a client in each of the provided cores. Broker runs in the 0th core. 'all' to select all available cores. 'none' to run a client without binding to any core. eg: '1,2-4,6' selects the cores 1,2,3,4,6.",
|
||||||
|
name = "CORES"
|
||||||
|
)]
|
||||||
|
cores: Cores,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
short = 'p',
|
||||||
|
long,
|
||||||
|
help = "Choose the broker TCP port, default is 1337",
|
||||||
|
name = "PORT",
|
||||||
|
default_value = "1337"
|
||||||
|
)]
|
||||||
|
broker_port: u16,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
parse(try_from_str),
|
||||||
|
short = 'a',
|
||||||
|
long,
|
||||||
|
help = "Specify a remote broker",
|
||||||
|
name = "REMOTE"
|
||||||
|
)]
|
||||||
|
remote_broker_addr: Option<SocketAddr>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
parse(try_from_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set an initial corpus directory",
|
||||||
|
name = "INPUT"
|
||||||
|
)]
|
||||||
|
input: Vec<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
parse(try_from_str),
|
||||||
|
help = "Set the output directory, default is ./out",
|
||||||
|
name = "OUTPUT",
|
||||||
|
default_value = "./out"
|
||||||
|
)]
|
||||||
|
output: PathBuf,
|
||||||
|
|
||||||
|
#[clap(
|
||||||
|
parse(try_from_str = timeout_from_millis_str),
|
||||||
|
short,
|
||||||
|
long,
|
||||||
|
help = "Set the exeucution timeout in milliseconds, default is 10000",
|
||||||
|
name = "TIMEOUT",
|
||||||
|
default_value = "10000"
|
||||||
|
)]
|
||||||
|
timeout: Duration,
|
||||||
|
/*
|
||||||
|
/// This fuzzer has hard-coded tokens
|
||||||
|
#[clap(
|
||||||
|
parse(from_os_str),
|
||||||
|
short = "x",
|
||||||
|
long,
|
||||||
|
help = "Feed the fuzzer with an user-specified list of tokens (often called \"dictionary\"",
|
||||||
|
name = "TOKENS",
|
||||||
|
multiple = true
|
||||||
|
)]
|
||||||
|
tokens: Vec<PathBuf>,
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The main fn, `no_mangle` as it is a C symbol
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn libafl_main() {
|
||||||
|
// Registry the metadata types used in this fuzzer
|
||||||
|
// Needed only on no_std
|
||||||
|
//RegistryBuilder::register::<Tokens>();
|
||||||
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
let broker_port = opt.broker_port;
|
||||||
|
let cores = opt.cores;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Workdir: {:?}",
|
||||||
|
env::current_dir().unwrap().to_string_lossy().to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
||||||
|
|
||||||
|
let monitor = MultiMonitor::new(|s| println!("{}", s));
|
||||||
|
|
||||||
|
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
||||||
|
// Create an observation channel using the coverage map
|
||||||
|
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };
|
||||||
|
let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges));
|
||||||
|
|
||||||
|
// 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(&opt.output).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),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
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::from(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 = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
|
||||||
|
let mut stages = tuple_list!(StdMutationalStage::new(mutator));
|
||||||
|
|
||||||
|
// A minimization+queue policy to get testcasess from the corpus
|
||||||
|
let scheduler = CoverageAccountingCorpusScheduler::new(
|
||||||
|
&mut state,
|
||||||
|
QueueCorpusScheduler::new(),
|
||||||
|
unsafe { &ACCOUNTING_MEMOP_MAP },
|
||||||
|
);
|
||||||
|
|
||||||
|
// A fuzzer with feedbacks and a corpus scheduler
|
||||||
|
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 target = input.target_bytes();
|
||||||
|
let buf = target.as_slice();
|
||||||
|
libfuzzer_test_one_input(buf);
|
||||||
|
ExitKind::Ok
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
|
||||||
|
let mut executor = TimeoutExecutor::new(
|
||||||
|
InProcessExecutor::new(
|
||||||
|
&mut harness,
|
||||||
|
tuple_list!(edges_observer, time_observer),
|
||||||
|
&mut fuzzer,
|
||||||
|
&mut state,
|
||||||
|
&mut restarting_mgr,
|
||||||
|
)?,
|
||||||
|
// 10 seconds timeout
|
||||||
|
opt.timeout,
|
||||||
|
);
|
||||||
|
|
||||||
|
// The actual target run starts here.
|
||||||
|
// Call LLVMFUzzerInitialize() if present.
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
if libfuzzer_initialize(&args) == -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 fuzzer, &mut executor, &mut restarting_mgr, &opt.input)
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
panic!("Failed to load initial corpus at {:?} {:?}", &opt.input, e)
|
||||||
|
});
|
||||||
|
println!("We imported {} inputs from disk.", state.corpus().count());
|
||||||
|
}
|
||||||
|
|
||||||
|
fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut restarting_mgr)?;
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
match Launcher::builder()
|
||||||
|
.shmem_provider(shmem_provider)
|
||||||
|
.configuration(EventConfig::from_name("default"))
|
||||||
|
.monitor(monitor)
|
||||||
|
.run_client(&mut run_client)
|
||||||
|
.cores(&cores)
|
||||||
|
.broker_port(broker_port)
|
||||||
|
.remote_broker_addr(opt.remote_broker_addr)
|
||||||
|
//.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),
|
||||||
|
}
|
||||||
|
}
|
@ -31,7 +31,6 @@ use libafl::{
|
|||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
monitors::tui::TuiMonitor,
|
monitors::tui::TuiMonitor,
|
||||||
monitors::MultiMonitor,
|
|
||||||
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
@ -142,7 +141,6 @@ pub fn libafl_main() {
|
|||||||
|
|
||||||
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
||||||
|
|
||||||
//let monitor = MultiMonitor::new(|s| println!("{}", s));
|
|
||||||
let monitor = TuiMonitor::new("Test fuzzer on libpng".into(), true);
|
let monitor = TuiMonitor::new("Test fuzzer on libpng".into(), true);
|
||||||
|
|
||||||
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut restarting_mgr, _core_id| {
|
||||||
|
Binary file not shown.
291
libafl/src/corpus/accounting.rs
Normal file
291
libafl/src/corpus/accounting.rs
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
//! Coverage accounting corpus scheduler, more details at <https://www.ndss-symposium.org/wp-content/uploads/2020/02/24422-paper.pdf>
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt},
|
||||||
|
corpus::{
|
||||||
|
minimizer::{
|
||||||
|
IsFavoredMetadata, LenTimeMulFavFactor, MinimizerCorpusScheduler,
|
||||||
|
DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||||
|
},
|
||||||
|
Corpus, CorpusScheduler, Testcase,
|
||||||
|
},
|
||||||
|
feedbacks::MapIndexesMetadata,
|
||||||
|
inputs::Input,
|
||||||
|
state::{HasCorpus, HasMetadata, HasRand},
|
||||||
|
Error,
|
||||||
|
};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AccountingIndexesMetadata {
|
||||||
|
/// The list of indexes.
|
||||||
|
pub list: Vec<usize>,
|
||||||
|
/// A refcount used to know when remove this meta
|
||||||
|
pub tcref: isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_serdeany!(AccountingIndexesMetadata);
|
||||||
|
|
||||||
|
impl AsSlice<usize> for AccountingIndexesMetadata {
|
||||||
|
/// Convert to a slice
|
||||||
|
fn as_slice(&self) -> &[usize] {
|
||||||
|
self.list.as_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl AsMutSlice<usize> for AccountingIndexesMetadata {
|
||||||
|
/// Convert to a slice
|
||||||
|
fn as_mut_slice(&mut self) -> &mut [usize] {
|
||||||
|
self.list.as_mut_slice()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasRefCnt for AccountingIndexesMetadata {
|
||||||
|
fn refcnt(&self) -> isize {
|
||||||
|
self.tcref
|
||||||
|
}
|
||||||
|
|
||||||
|
fn refcnt_mut(&mut self) -> &mut isize {
|
||||||
|
&mut self.tcref
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AccountingIndexesMetadata {
|
||||||
|
/// Creates a new [`struct@AccountingIndexesMetadata`].
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(list: Vec<usize>) -> Self {
|
||||||
|
Self { list, tcref: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`struct@AccountingIndexesMetadata`] specifying the refcount.
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_tcref(list: Vec<usize>, tcref: isize) -> Self {
|
||||||
|
Self { list, tcref }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A state metadata holding a map of favoreds testcases for each map entry
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TopAccountingMetadata {
|
||||||
|
/// map index -> corpus index
|
||||||
|
pub map: HashMap<usize, usize>,
|
||||||
|
/// If changed sicne the previous add to the corpus
|
||||||
|
pub changed: bool,
|
||||||
|
/// The max accounting seen so far
|
||||||
|
pub max_accounting: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
crate::impl_serdeany!(TopAccountingMetadata);
|
||||||
|
|
||||||
|
impl TopAccountingMetadata {
|
||||||
|
/// Creates a new [`struct@TopAccountingMetadata`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(acc_len: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
map: HashMap::default(),
|
||||||
|
changed: false,
|
||||||
|
max_accounting: vec![0; acc_len],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A minimizer scheduler using coverage accounting
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CoverageAccountingCorpusScheduler<'a, CS, I, S>
|
||||||
|
where
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
I: Input + HasLen,
|
||||||
|
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||||
|
{
|
||||||
|
accounting_map: &'a [u32],
|
||||||
|
skip_non_favored_prob: u64,
|
||||||
|
inner: MinimizerCorpusScheduler<CS, LenTimeMulFavFactor<I>, I, MapIndexesMetadata, S>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CS, I, S> CorpusScheduler<I, S> for CoverageAccountingCorpusScheduler<'a, CS, I, S>
|
||||||
|
where
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
I: Input + HasLen,
|
||||||
|
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||||
|
{
|
||||||
|
fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
||||||
|
self.update_accounting_score(state, idx)?;
|
||||||
|
self.inner.on_add(state, idx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase<I>) -> Result<(), Error> {
|
||||||
|
self.inner.on_replace(state, idx, testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_remove(
|
||||||
|
&self,
|
||||||
|
state: &mut S,
|
||||||
|
idx: usize,
|
||||||
|
testcase: &Option<Testcase<I>>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
self.inner.on_remove(state, idx, testcase)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(&self, state: &mut S) -> Result<usize, Error> {
|
||||||
|
if state
|
||||||
|
.metadata()
|
||||||
|
.get::<TopAccountingMetadata>()
|
||||||
|
.map_or(false, |x| x.changed)
|
||||||
|
{
|
||||||
|
self.accounting_cull(state)?;
|
||||||
|
} else {
|
||||||
|
self.inner.cull(state)?;
|
||||||
|
}
|
||||||
|
let mut idx = self.inner.base().next(state)?;
|
||||||
|
while {
|
||||||
|
let has = !state
|
||||||
|
.corpus()
|
||||||
|
.get(idx)?
|
||||||
|
.borrow()
|
||||||
|
.has_metadata::<IsFavoredMetadata>();
|
||||||
|
has
|
||||||
|
} && state.rand_mut().below(100) < self.skip_non_favored_prob
|
||||||
|
{
|
||||||
|
idx = self.inner.base().next(state)?;
|
||||||
|
}
|
||||||
|
Ok(idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CS, I, S> CoverageAccountingCorpusScheduler<'a, CS, I, S>
|
||||||
|
where
|
||||||
|
CS: CorpusScheduler<I, S>,
|
||||||
|
I: Input + HasLen,
|
||||||
|
S: HasCorpus<I> + HasMetadata + HasRand,
|
||||||
|
{
|
||||||
|
/// Update the `Corpus` score
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
#[allow(clippy::cast_possible_wrap)]
|
||||||
|
pub fn update_accounting_score(&self, state: &mut S, idx: usize) -> Result<(), Error> {
|
||||||
|
let mut indexes = vec![];
|
||||||
|
let mut new_favoreds = vec![];
|
||||||
|
{
|
||||||
|
for idx in 0..self.accounting_map.len() {
|
||||||
|
if self.accounting_map[idx] == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
indexes.push(idx);
|
||||||
|
|
||||||
|
let mut equal_score = false;
|
||||||
|
{
|
||||||
|
let top_acc = state.metadata().get::<TopAccountingMetadata>().unwrap();
|
||||||
|
|
||||||
|
if let Some(old_idx) = top_acc.map.get(&idx) {
|
||||||
|
if top_acc.max_accounting[idx] > self.accounting_map[idx] {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if top_acc.max_accounting[idx] >= self.accounting_map[idx] {
|
||||||
|
equal_score = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut old = state.corpus().get(*old_idx)?.borrow_mut();
|
||||||
|
let must_remove = {
|
||||||
|
let old_meta = old.metadata_mut().get_mut::<AccountingIndexesMetadata>().ok_or_else(|| {
|
||||||
|
Error::KeyNotFound(format!(
|
||||||
|
"AccountingIndexesMetadata, needed by CoverageAccountingCorpusScheduler, not found in testcase #{}",
|
||||||
|
old_idx
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
*old_meta.refcnt_mut() -= 1;
|
||||||
|
old_meta.refcnt() <= 0
|
||||||
|
};
|
||||||
|
|
||||||
|
if must_remove {
|
||||||
|
drop(old.metadata_mut().remove::<AccountingIndexesMetadata>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let top_acc = state
|
||||||
|
.metadata_mut()
|
||||||
|
.get_mut::<TopAccountingMetadata>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// if its accounting is equal to others', it's not favored
|
||||||
|
if equal_score {
|
||||||
|
top_acc.map.remove(&idx);
|
||||||
|
} else if top_acc.max_accounting[idx] < self.accounting_map[idx] {
|
||||||
|
new_favoreds.push(idx);
|
||||||
|
|
||||||
|
top_acc.max_accounting[idx] = self.accounting_map[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_favoreds.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
state.corpus().get(idx)?.borrow_mut().metadata_mut().insert(
|
||||||
|
AccountingIndexesMetadata::with_tcref(indexes, new_favoreds.len() as isize),
|
||||||
|
);
|
||||||
|
|
||||||
|
let top_acc = state
|
||||||
|
.metadata_mut()
|
||||||
|
.get_mut::<TopAccountingMetadata>()
|
||||||
|
.unwrap();
|
||||||
|
top_acc.changed = true;
|
||||||
|
|
||||||
|
for elem in new_favoreds {
|
||||||
|
top_acc.map.insert(elem, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cull the `Corpus`
|
||||||
|
#[allow(clippy::unused_self)]
|
||||||
|
pub fn accounting_cull(&self, state: &mut S) -> Result<(), Error> {
|
||||||
|
let top_rated = match state.metadata().get::<TopAccountingMetadata>() {
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(val) => val,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (_key, idx) in &top_rated.map {
|
||||||
|
let mut entry = state.corpus().get(*idx)?.borrow_mut();
|
||||||
|
if entry.fuzzed() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.add_metadata(IsFavoredMetadata {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`CoverageAccountingCorpusScheduler`] that wraps a `base` [`CorpusScheduler`]
|
||||||
|
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||||
|
pub fn new(state: &mut S, base: CS, accounting_map: &'a [u32]) -> Self {
|
||||||
|
state.add_metadata(TopAccountingMetadata::new(accounting_map.len()));
|
||||||
|
Self {
|
||||||
|
accounting_map,
|
||||||
|
inner: MinimizerCorpusScheduler::new(base),
|
||||||
|
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`CoverageAccountingCorpusScheduler`] that wraps a `base` [`CorpusScheduler`]
|
||||||
|
/// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`).
|
||||||
|
pub fn with_skip_prob(
|
||||||
|
state: &mut S,
|
||||||
|
base: CS,
|
||||||
|
skip_non_favored_prob: u64,
|
||||||
|
accounting_map: &'a [u32],
|
||||||
|
) -> Self {
|
||||||
|
state.add_metadata(TopAccountingMetadata::new(accounting_map.len()));
|
||||||
|
Self {
|
||||||
|
accounting_map,
|
||||||
|
inner: MinimizerCorpusScheduler::with_skip_prob(base, skip_non_favored_prob),
|
||||||
|
skip_non_favored_prob,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -257,6 +257,11 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the base scheduler
|
||||||
|
pub fn base(&self) -> &CS {
|
||||||
|
&self.base
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new [`MinimizerCorpusScheduler`] that wraps a `base` [`CorpusScheduler`]
|
/// Creates a new [`MinimizerCorpusScheduler`] that wraps a `base` [`CorpusScheduler`]
|
||||||
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
|
||||||
pub fn new(base: CS) -> Self {
|
pub fn new(base: CS) -> Self {
|
||||||
|
@ -19,6 +19,9 @@ pub use cached::CachedOnDiskCorpus;
|
|||||||
pub mod queue;
|
pub mod queue;
|
||||||
pub use queue::QueueCorpusScheduler;
|
pub use queue::QueueCorpusScheduler;
|
||||||
|
|
||||||
|
pub mod accounting;
|
||||||
|
pub use accounting::*;
|
||||||
|
|
||||||
pub mod minimizer;
|
pub mod minimizer;
|
||||||
pub use minimizer::{
|
pub use minimizer::{
|
||||||
FavFactor, IndexesLenTimeMinimizerCorpusScheduler, IsFavoredMetadata,
|
FavFactor, IndexesLenTimeMinimizerCorpusScheduler, IsFavoredMetadata,
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// An entry in the Testcase Corpus
|
/// An entry in the Testcase Corpus
|
||||||
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
#[serde(bound = "I: serde::de::DeserializeOwned")]
|
||||||
pub struct Testcase<I>
|
pub struct Testcase<I>
|
||||||
where
|
where
|
||||||
@ -31,6 +31,8 @@ where
|
|||||||
cached_len: Option<usize>,
|
cached_len: Option<usize>,
|
||||||
/// Number of executions done at discovery time
|
/// Number of executions done at discovery time
|
||||||
executions: usize,
|
executions: usize,
|
||||||
|
/// If it has been fuzzed
|
||||||
|
fuzzed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> HasMetadata for Testcase<I>
|
impl<I> HasMetadata for Testcase<I>
|
||||||
@ -152,6 +154,18 @@ where
|
|||||||
&mut self.executions
|
&mut self.executions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get if it was fuzzed
|
||||||
|
#[inline]
|
||||||
|
pub fn fuzzed(&self) -> bool {
|
||||||
|
self.fuzzed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set if it was fuzzed
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fuzzed(&mut self, fuzzed: bool) {
|
||||||
|
self.fuzzed = fuzzed;
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new Testcase instace given an input
|
/// Create a new Testcase instace given an input
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new<T>(input: T) -> Self
|
pub fn new<T>(input: T) -> Self
|
||||||
@ -160,11 +174,7 @@ where
|
|||||||
{
|
{
|
||||||
let mut slf = Testcase {
|
let mut slf = Testcase {
|
||||||
input: Some(input.into()),
|
input: Some(input.into()),
|
||||||
filename: None,
|
..Testcase::default()
|
||||||
metadata: SerdeAnyMap::new(),
|
|
||||||
exec_time: None,
|
|
||||||
cached_len: None,
|
|
||||||
executions: 0,
|
|
||||||
};
|
};
|
||||||
slf.input.as_mut().unwrap().wrapped_as_testcase();
|
slf.input.as_mut().unwrap().wrapped_as_testcase();
|
||||||
slf
|
slf
|
||||||
@ -177,10 +187,7 @@ where
|
|||||||
Testcase {
|
Testcase {
|
||||||
input: Some(input),
|
input: Some(input),
|
||||||
filename: Some(filename),
|
filename: Some(filename),
|
||||||
metadata: SerdeAnyMap::new(),
|
..Testcase::default()
|
||||||
exec_time: None,
|
|
||||||
cached_len: None,
|
|
||||||
executions: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,18 +197,19 @@ where
|
|||||||
input.wrapped_as_testcase();
|
input.wrapped_as_testcase();
|
||||||
Testcase {
|
Testcase {
|
||||||
input: Some(input),
|
input: Some(input),
|
||||||
filename: None,
|
|
||||||
metadata: SerdeAnyMap::new(),
|
|
||||||
exec_time: None,
|
|
||||||
cached_len: None,
|
|
||||||
executions,
|
executions,
|
||||||
|
..Testcase::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new, empty, [`Testcase`].
|
impl<I> Default for Testcase<I>
|
||||||
#[must_use]
|
where
|
||||||
|
I: Input,
|
||||||
|
{
|
||||||
|
/// Create a new default Testcase
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn default() -> Self {
|
fn default() -> Self {
|
||||||
Testcase {
|
Testcase {
|
||||||
input: None,
|
input: None,
|
||||||
filename: None,
|
filename: None,
|
||||||
@ -209,6 +217,7 @@ where
|
|||||||
exec_time: None,
|
exec_time: None,
|
||||||
cached_len: None,
|
cached_len: None,
|
||||||
executions: 0,
|
executions: 0,
|
||||||
|
fuzzed: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,7 @@ fn find_llvm_config() -> String {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
let out_dir = Path::new(&out_dir);
|
let out_dir = Path::new(&out_dir);
|
||||||
@ -80,6 +81,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
|
println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
|
||||||
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE");
|
println!("cargo:rerun-if-env-changed=LIBAFL_EDGES_MAP_SIZE");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
|
|
||||||
let mut custom_flags = vec![];
|
let mut custom_flags = vec![];
|
||||||
|
|
||||||
@ -91,6 +93,11 @@ fn main() {
|
|||||||
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE");
|
.expect("Could not parse LIBAFL_EDGES_MAP_SIZE");
|
||||||
custom_flags.push(format!("-DLIBAFL_EDGES_MAP_SIZE={}", edges_map_size));
|
custom_flags.push(format!("-DLIBAFL_EDGES_MAP_SIZE={}", edges_map_size));
|
||||||
|
|
||||||
|
let acc_map_size: usize = option_env!("LIBAFL_ACCOUNTING_MAP_SIZE")
|
||||||
|
.map_or(Ok(65536), str::parse)
|
||||||
|
.expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
|
custom_flags.push(format!("-DLIBAFL_ACCOUNTING_MAP_SIZE={}", acc_map_size));
|
||||||
|
|
||||||
let llvm_config = find_llvm_config();
|
let llvm_config = find_llvm_config();
|
||||||
|
|
||||||
if let Ok(output) = Command::new(&llvm_config).args(&["--bindir"]).output() {
|
if let Ok(output) = Command::new(&llvm_config).args(&["--bindir"]).output() {
|
||||||
@ -99,7 +106,6 @@ fn main() {
|
|||||||
.expect("Invalid llvm-config output")
|
.expect("Invalid llvm-config output")
|
||||||
.trim(),
|
.trim(),
|
||||||
);
|
);
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
clang_constants_file,
|
clang_constants_file,
|
||||||
"// These constants are autogenerated by build.rs
|
"// These constants are autogenerated by build.rs
|
||||||
@ -111,10 +117,14 @@ fn main() {
|
|||||||
|
|
||||||
/// The size of the edges map
|
/// The size of the edges map
|
||||||
pub const EDGES_MAP_SIZE: usize = {};
|
pub const EDGES_MAP_SIZE: usize = {};
|
||||||
|
|
||||||
|
/// The size of the accounting maps
|
||||||
|
pub const ACCOUNTING_MAP_SIZE: usize = {};
|
||||||
",
|
",
|
||||||
llvm_bindir.join("clang"),
|
llvm_bindir.join("clang"),
|
||||||
llvm_bindir.join("clang++"),
|
llvm_bindir.join("clang++"),
|
||||||
edges_map_size
|
edges_map_size,
|
||||||
|
acc_map_size
|
||||||
)
|
)
|
||||||
.expect("Could not write file");
|
.expect("Could not write file");
|
||||||
|
|
||||||
@ -126,6 +136,7 @@ fn main() {
|
|||||||
|
|
||||||
let output = Command::new(&llvm_config)
|
let output = Command::new(&llvm_config)
|
||||||
.args(&["--ldflags"])
|
.args(&["--ldflags"])
|
||||||
|
.args(&["--libs"])
|
||||||
.output()
|
.output()
|
||||||
.expect("Failed to execute llvm-config");
|
.expect("Failed to execute llvm-config");
|
||||||
let ldflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output");
|
let ldflags = str::from_utf8(&output.stdout).expect("Invalid llvm-config output");
|
||||||
@ -140,11 +151,13 @@ fn main() {
|
|||||||
ldflags.push("dynamic_lookup");
|
ldflags.push("dynamic_lookup");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=src/common-llvm.h");
|
||||||
println!("cargo:rerun-if-changed=src/cmplog-routines-pass.cc");
|
println!("cargo:rerun-if-changed=src/cmplog-routines-pass.cc");
|
||||||
println!("cargo:rerun-if-changed=src/afl-coverage-pass.cc");
|
println!("cargo:rerun-if-changed=src/afl-coverage-pass.cc");
|
||||||
println!("cargo:rerun-if-changed=src/autotokens-pass.cc");
|
println!("cargo:rerun-if-changed=src/autotokens-pass.cc");
|
||||||
|
println!("cargo:rerun-if-changed=src/coverage-accounting-pass.cc");
|
||||||
|
|
||||||
let _ = Command::new(llvm_bindir.join("clang++"))
|
assert!(Command::new(llvm_bindir.join("clang++"))
|
||||||
.args(&cxxflags)
|
.args(&cxxflags)
|
||||||
.args(&custom_flags)
|
.args(&custom_flags)
|
||||||
.arg(src_dir.join("cmplog-routines-pass.cc"))
|
.arg(src_dir.join("cmplog-routines-pass.cc"))
|
||||||
@ -152,9 +165,10 @@ fn main() {
|
|||||||
.args(&["-fPIC", "-shared", "-o"])
|
.args(&["-fPIC", "-shared", "-o"])
|
||||||
.arg(out_dir.join(format!("cmplog-routines-pass.{}", dll_extension())))
|
.arg(out_dir.join(format!("cmplog-routines-pass.{}", dll_extension())))
|
||||||
.status()
|
.status()
|
||||||
.expect("Failed to compile cmplog-routines-pass.cc");
|
.expect("Failed to compile cmplog-routines-pass.cc")
|
||||||
|
.success());
|
||||||
|
|
||||||
let _ = Command::new(llvm_bindir.join("clang++"))
|
assert!(Command::new(llvm_bindir.join("clang++"))
|
||||||
.args(&cxxflags)
|
.args(&cxxflags)
|
||||||
.args(&custom_flags)
|
.args(&custom_flags)
|
||||||
.arg(src_dir.join("afl-coverage-pass.cc"))
|
.arg(src_dir.join("afl-coverage-pass.cc"))
|
||||||
@ -162,9 +176,10 @@ fn main() {
|
|||||||
.args(&["-fPIC", "-shared", "-o"])
|
.args(&["-fPIC", "-shared", "-o"])
|
||||||
.arg(out_dir.join(format!("afl-coverage-pass.{}", dll_extension())))
|
.arg(out_dir.join(format!("afl-coverage-pass.{}", dll_extension())))
|
||||||
.status()
|
.status()
|
||||||
.expect("Failed to compile afl-coverage-pass.cc");
|
.expect("Failed to compile afl-coverage-pass.cc")
|
||||||
|
.success());
|
||||||
|
|
||||||
let _ = Command::new(llvm_bindir.join("clang++"))
|
assert!(Command::new(llvm_bindir.join("clang++"))
|
||||||
.args(&cxxflags)
|
.args(&cxxflags)
|
||||||
.args(&custom_flags)
|
.args(&custom_flags)
|
||||||
.arg(src_dir.join("autotokens-pass.cc"))
|
.arg(src_dir.join("autotokens-pass.cc"))
|
||||||
@ -172,7 +187,19 @@ fn main() {
|
|||||||
.args(&["-fPIC", "-shared", "-o"])
|
.args(&["-fPIC", "-shared", "-o"])
|
||||||
.arg(out_dir.join(format!("autotokens-pass.{}", dll_extension())))
|
.arg(out_dir.join(format!("autotokens-pass.{}", dll_extension())))
|
||||||
.status()
|
.status()
|
||||||
.expect("Failed to compile autotokens-pass.cc");
|
.expect("Failed to compile autotokens-pass.cc")
|
||||||
|
.success());
|
||||||
|
|
||||||
|
assert!(Command::new(llvm_bindir.join("clang++"))
|
||||||
|
.args(&cxxflags)
|
||||||
|
.args(&custom_flags)
|
||||||
|
.arg(src_dir.join("coverage-accounting-pass.cc"))
|
||||||
|
.args(&ldflags)
|
||||||
|
.args(&["-fPIC", "-shared", "-o"])
|
||||||
|
.arg(out_dir.join(format!("coverage-accounting-pass.{}", dll_extension())))
|
||||||
|
.status()
|
||||||
|
.expect("Failed to compile coverage-accounting-pass.cc")
|
||||||
|
.success());
|
||||||
} else {
|
} else {
|
||||||
write!(
|
write!(
|
||||||
clang_constants_file,
|
clang_constants_file,
|
||||||
|
@ -26,33 +26,16 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include "common-llvm.h"
|
||||||
#include <stdlib.h>
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "llvm/Config/llvm-config.h"
|
|
||||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
|
||||||
typedef long double max_align_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR >= 7 /* use new pass manager */
|
|
||||||
//#define USE_NEW_PM 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/IR/IRBuilder.h"
|
#include "llvm/IR/IRBuilder.h"
|
||||||
#ifdef USE_NEW_PM
|
|
||||||
#include "llvm/Passes/PassPlugin.h"
|
|
||||||
#include "llvm/Passes/PassBuilder.h"
|
|
||||||
#include "llvm/IR/PassManager.h"
|
|
||||||
#else
|
|
||||||
#include "llvm/IR/LegacyPassManager.h"
|
|
||||||
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
||||||
#endif
|
|
||||||
#include "llvm/IR/BasicBlock.h"
|
#include "llvm/IR/BasicBlock.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/Support/Debug.h"
|
#include "llvm/Support/Debug.h"
|
||||||
@ -77,8 +60,6 @@ typedef uint32_t prev_loc_t;
|
|||||||
|
|
||||||
#define MAP_SIZE LIBAFL_EDGES_MAP_SIZE
|
#define MAP_SIZE LIBAFL_EDGES_MAP_SIZE
|
||||||
|
|
||||||
#define FATAL(...) do { fprintf(stderr, "FATAL: " __VA_ARGS__); exit(1); } while (0)
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false), cl::NotHidden);
|
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false), cl::NotHidden);
|
||||||
@ -156,36 +137,6 @@ llvmGetPassPluginInfo() {
|
|||||||
char AFLCoverage::ID = 0;
|
char AFLCoverage::ID = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32_t RandBelow(uint32_t max) {
|
|
||||||
return (uint32_t)rand() % (max +1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* needed up to 3.9.0 */
|
|
||||||
#if LLVM_VERSION_MAJOR == 3 && \
|
|
||||||
(LLVM_VERSION_MINOR < 9 || \
|
|
||||||
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
|
|
||||||
static uint64_t PowerOf2Ceil(unsigned in) {
|
|
||||||
|
|
||||||
uint64_t in64 = in - 1;
|
|
||||||
in64 |= (in64 >> 1);
|
|
||||||
in64 |= (in64 >> 2);
|
|
||||||
in64 |= (in64 >> 4);
|
|
||||||
in64 |= (in64 >> 8);
|
|
||||||
in64 |= (in64 >> 16);
|
|
||||||
in64 |= (in64 >> 32);
|
|
||||||
return in64 + 1;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
|
||||||
#if LLVM_VERSION_MAJOR > 4 || \
|
|
||||||
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
|
||||||
#define HAVE_VECTOR_INTRINSICS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USE_NEW_PM
|
#ifdef USE_NEW_PM
|
||||||
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||||
#else
|
#else
|
||||||
|
@ -33,6 +33,8 @@ pub enum LLVMPasses {
|
|||||||
AFLCoverage,
|
AFLCoverage,
|
||||||
/// The Autotoken pass
|
/// The Autotoken pass
|
||||||
AutoTokens,
|
AutoTokens,
|
||||||
|
/// The Coverage Accouting (BB metric) pass
|
||||||
|
CoverageAccounting,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LLVMPasses {
|
impl LLVMPasses {
|
||||||
@ -47,6 +49,8 @@ impl LLVMPasses {
|
|||||||
LLVMPasses::AutoTokens => {
|
LLVMPasses::AutoTokens => {
|
||||||
PathBuf::from(env!("OUT_DIR")).join(format!("autotokens-pass.{}", dll_extension()))
|
PathBuf::from(env!("OUT_DIR")).join(format!("autotokens-pass.{}", dll_extension()))
|
||||||
}
|
}
|
||||||
|
LLVMPasses::CoverageAccounting => PathBuf::from(env!("OUT_DIR"))
|
||||||
|
.join(format!("coverage-accounting-pass.{}", dll_extension())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
55
libafl_cc/src/common-llvm.h
Normal file
55
libafl_cc/src/common-llvm.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef LIBAFL_COMMON_LLVM_H
|
||||||
|
#define LIBAFL_COMMON_LLVM_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "llvm/Config/llvm-config.h"
|
||||||
|
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||||
|
typedef long double max_align_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR >= 7 /* use new pass manager */
|
||||||
|
//#define USE_NEW_PM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* #if LLVM_VERSION_STRING >= "4.0.1" */
|
||||||
|
#if LLVM_VERSION_MAJOR > 4 || \
|
||||||
|
(LLVM_VERSION_MAJOR == 4 && LLVM_VERSION_PATCH >= 1)
|
||||||
|
#define HAVE_VECTOR_INTRINSICS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
#include "llvm/Passes/PassPlugin.h"
|
||||||
|
#include "llvm/Passes/PassBuilder.h"
|
||||||
|
#include "llvm/IR/PassManager.h"
|
||||||
|
#else
|
||||||
|
#include "llvm/IR/LegacyPassManager.h"
|
||||||
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FATAL(...) do { fprintf(stderr, "FATAL: " __VA_ARGS__); exit(1); } while (0)
|
||||||
|
|
||||||
|
static uint32_t RandBelow(uint32_t max) {
|
||||||
|
return (uint32_t)rand() % (max +1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* needed up to 3.9.0 */
|
||||||
|
#if LLVM_VERSION_MAJOR == 3 && \
|
||||||
|
(LLVM_VERSION_MINOR < 9 || \
|
||||||
|
(LLVM_VERSION_MINOR == 9 && LLVM_VERSION_PATCH < 1))
|
||||||
|
static uint64_t PowerOf2Ceil(unsigned in) {
|
||||||
|
|
||||||
|
uint64_t in64 = in - 1;
|
||||||
|
in64 |= (in64 >> 1);
|
||||||
|
in64 |= (in64 >> 2);
|
||||||
|
in64 |= (in64 >> 4);
|
||||||
|
in64 |= (in64 >> 8);
|
||||||
|
in64 |= (in64 >> 16);
|
||||||
|
in64 |= (in64 >> 32);
|
||||||
|
return in64 + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // LIBAFL_COMMON_LLVM_H
|
272
libafl_cc/src/coverage-accounting-pass.cc
Normal file
272
libafl_cc/src/coverage-accounting-pass.cc
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
american fuzzy lop++ - LLVM-mode instrumentation pass
|
||||||
|
---------------------------------------------------
|
||||||
|
|
||||||
|
Written by Laszlo Szekeres <lszekeres@google.com>,
|
||||||
|
Adrian Herrera <adrian.herrera@anu.edu.au>,
|
||||||
|
Michal Zalewski
|
||||||
|
|
||||||
|
LLVM integration design comes from Laszlo Szekeres. C bits copied-and-pasted
|
||||||
|
from afl-as.c are Michal's fault.
|
||||||
|
|
||||||
|
NGRAM previous location coverage comes from Adrian Herrera.
|
||||||
|
|
||||||
|
Copyright 2015, 2016 Google Inc. All rights reserved.
|
||||||
|
Copyright 2019-2020 AFLplusplus Project. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at:
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
This library is plugged into LLVM when invoking clang through afl-clang-fast.
|
||||||
|
It tells the compiler to add code roughly equivalent to the bits discussed
|
||||||
|
in ../afl-as.h.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common-llvm.h"
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
#include "llvm/IR/IRBuilder.h"
|
||||||
|
#include "llvm/IR/BasicBlock.h"
|
||||||
|
#include "llvm/IR/Module.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
#include "llvm/Support/MathExtras.h"
|
||||||
|
|
||||||
|
#if LLVM_VERSION_MAJOR > 3 || \
|
||||||
|
(LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4)
|
||||||
|
#include "llvm/IR/DebugInfo.h"
|
||||||
|
#include "llvm/IR/CFG.h"
|
||||||
|
#else
|
||||||
|
#include "llvm/DebugInfo.h"
|
||||||
|
#include "llvm/Support/CFG.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef uint32_t prev_loc_t;
|
||||||
|
|
||||||
|
#define MAP_SIZE LIBAFL_ACCOUNTING_MAP_SIZE
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
static cl::opt<bool> Debug("debug", cl::desc("Debug prints"), cl::init(false), cl::NotHidden);
|
||||||
|
static cl::opt<uint32_t> InstRatio("inst_ratio", cl::desc("Instrumentation ratio in percentage"), cl::init(100), cl::NotHidden);
|
||||||
|
static cl::opt<bool> ThreadSafe("thread_safe", cl::desc("Use the thread safe instrumentation"), cl::init(false), cl::NotHidden);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
class AFLCoverage : public PassInfoMixin<AFLCoverage> {
|
||||||
|
public:
|
||||||
|
AFLCoverage() {
|
||||||
|
#else
|
||||||
|
class AFLCoverage : public ModulePass {
|
||||||
|
public:
|
||||||
|
static char ID;
|
||||||
|
AFLCoverage() : ModulePass(ID) {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// initInstrumentList();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
|
||||||
|
#else
|
||||||
|
bool runOnModule(Module &M) override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t map_size = MAP_SIZE;
|
||||||
|
uint32_t function_minimum_size = 1;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
|
||||||
|
llvmGetPassPluginInfo() {
|
||||||
|
return {
|
||||||
|
LLVM_PLUGIN_API_VERSION, "AFLCoverageAccounting", "v0.1",
|
||||||
|
/* lambda to insert our pass into the pass pipeline. */
|
||||||
|
[](PassBuilder &PB) {
|
||||||
|
#if 1
|
||||||
|
using OptimizationLevel = typename PassBuilder::OptimizationLevel;
|
||||||
|
PB.registerOptimizerLastEPCallback(
|
||||||
|
[](ModulePassManager &MPM, OptimizationLevel OL) {
|
||||||
|
MPM.addPass(AFLCoverage());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
/* TODO LTO registration */
|
||||||
|
#else
|
||||||
|
using PipelineElement = typename PassBuilder::PipelineElement;
|
||||||
|
PB.registerPipelineParsingCallback(
|
||||||
|
[](StringRef Name, ModulePassManager &MPM, ArrayRef<PipelineElement>) {
|
||||||
|
if ( Name == "AFLCoverageAccounting" ) {
|
||||||
|
MPM.addPass(AFLCoverage());
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
char AFLCoverage::ID = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
PreservedAnalyses AFLCoverage::run(Module &M, ModuleAnalysisManager &MAM) {
|
||||||
|
#else
|
||||||
|
bool AFLCoverage::runOnModule(Module &M) {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LLVMContext &C = M.getContext();
|
||||||
|
|
||||||
|
IntegerType *Int32Ty = IntegerType::getInt32Ty(C);
|
||||||
|
uint32_t rand_seed;
|
||||||
|
unsigned int cur_loc = 0;
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
auto PA = PreservedAnalyses::all();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Setup random() so we get Actually Random(TM) */
|
||||||
|
rand_seed = time(NULL);
|
||||||
|
srand(rand_seed);
|
||||||
|
|
||||||
|
/* Decide instrumentation ratio */
|
||||||
|
|
||||||
|
if (!InstRatio || InstRatio > 100)
|
||||||
|
FATAL("Bad value of the instrumentation ratio (must be between 1 and 100)");
|
||||||
|
|
||||||
|
/* Get globals for the SHM region and the previous location. Note that
|
||||||
|
__afl_acc_prev_loc is thread-local. */
|
||||||
|
|
||||||
|
GlobalVariable *AFLMemOpPtr =
|
||||||
|
new GlobalVariable(M, PointerType::get(Int32Ty, 0), false,
|
||||||
|
GlobalValue::ExternalLinkage, 0, "__afl_acc_memop_ptr");
|
||||||
|
|
||||||
|
GlobalVariable *AFLPrevLoc;
|
||||||
|
|
||||||
|
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
|
AFLPrevLoc = new GlobalVariable(
|
||||||
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc");
|
||||||
|
#else
|
||||||
|
AFLPrevLoc = new GlobalVariable(
|
||||||
|
M, Int32Ty, false, GlobalValue::ExternalLinkage, 0, "__afl_acc_prev_loc", 0,
|
||||||
|
GlobalVariable::GeneralDynamicTLSModel, 0, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Instrument all the things! */
|
||||||
|
|
||||||
|
int inst_blocks = 0;
|
||||||
|
// scanForDangerousFunctions(&M);
|
||||||
|
|
||||||
|
for (auto &F : M) {
|
||||||
|
|
||||||
|
int has_calls = 0;
|
||||||
|
if (Debug)
|
||||||
|
fprintf(stderr, "FUNCTION: %s (%zu)\n", F.getName().str().c_str(),
|
||||||
|
F.size());
|
||||||
|
|
||||||
|
// if (!isInInstrumentList(&F)) { continue; }
|
||||||
|
|
||||||
|
if (F.size() < function_minimum_size) { continue; }
|
||||||
|
|
||||||
|
std::list<Value *> todo;
|
||||||
|
for (auto &BB : F) {
|
||||||
|
|
||||||
|
BasicBlock::iterator IP = BB.getFirstInsertionPt();
|
||||||
|
IRBuilder<> IRB(&(*IP));
|
||||||
|
|
||||||
|
if (RandBelow(100) >= InstRatio) continue;
|
||||||
|
|
||||||
|
// Start with 1 to implicitly track edge coverage too
|
||||||
|
uint32_t MemCnt = 1;
|
||||||
|
|
||||||
|
for (auto &I : BB) {
|
||||||
|
if (I.mayReadFromMemory() || I.mayWriteToMemory())
|
||||||
|
++MemCnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make up cur_loc */
|
||||||
|
|
||||||
|
cur_loc = RandBelow(map_size);
|
||||||
|
|
||||||
|
ConstantInt *CurLoc = ConstantInt::get(Int32Ty, cur_loc);
|
||||||
|
|
||||||
|
/* Load prev_loc */
|
||||||
|
|
||||||
|
LoadInst *PrevLoc = IRB.CreateLoad(AFLPrevLoc);
|
||||||
|
PrevLoc->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
|
||||||
|
/* Load SHM pointer */
|
||||||
|
|
||||||
|
LoadInst *MemReadPtr = IRB.CreateLoad(AFLMemOpPtr);
|
||||||
|
MemReadPtr->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
Value *MemReadPtrIdx = IRB.CreateGEP(MemReadPtr, IRB.CreateXor(PrevLoc, CurLoc));
|
||||||
|
|
||||||
|
/* Update bitmap */
|
||||||
|
|
||||||
|
LoadInst *MemReadCount = IRB.CreateLoad(MemReadPtrIdx);
|
||||||
|
MemReadCount->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
Value *MemReadIncr = IRB.CreateAdd(MemReadCount, ConstantInt::get(Int32Ty, MemCnt));
|
||||||
|
IRB.CreateStore(MemReadIncr, MemReadPtrIdx)
|
||||||
|
->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
|
||||||
|
/* Update prev_loc */
|
||||||
|
|
||||||
|
StoreInst * Store = IRB.CreateStore(ConstantInt::get(Int32Ty, cur_loc >> 1),
|
||||||
|
AFLPrevLoc);
|
||||||
|
Store->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(C, None));
|
||||||
|
|
||||||
|
inst_blocks++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Debug) {
|
||||||
|
|
||||||
|
if (!inst_blocks)
|
||||||
|
fprintf(stderr, "No instrumentation targets found.\n");
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Instrumented %d locations (ratio %u%%).\n", inst_blocks, (unsigned)InstRatio);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_NEW_PM
|
||||||
|
return PA;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef USE_NEW_PM
|
||||||
|
static void registerAFLPass(const PassManagerBuilder &,
|
||||||
|
legacy::PassManagerBase &PM) {
|
||||||
|
|
||||||
|
PM.add(new AFLCoverage());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterStandardPasses RegisterAFLPass(
|
||||||
|
PassManagerBuilder::EP_OptimizerLast, registerAFLPass);
|
||||||
|
|
||||||
|
static RegisterStandardPasses RegisterAFLPass0(
|
||||||
|
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLPass);
|
||||||
|
#endif
|
@ -23,6 +23,9 @@ fn main() {
|
|||||||
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")
|
||||||
|
.map_or(Ok(65536), str::parse)
|
||||||
|
.expect("Could not parse LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
constants_file,
|
constants_file,
|
||||||
@ -36,8 +39,10 @@ fn main() {
|
|||||||
pub const CMPLOG_MAP_W: usize = {};
|
pub const CMPLOG_MAP_W: usize = {};
|
||||||
/// The height of the `CmpLog` map
|
/// The height of the `CmpLog` map
|
||||||
pub const CMPLOG_MAP_H: usize = {};
|
pub const CMPLOG_MAP_H: usize = {};
|
||||||
|
/// The size of the accounting maps
|
||||||
|
pub const ACCOUNTING_MAP_SIZE: usize = {};
|
||||||
",
|
",
|
||||||
edges_map_size, cmp_map_size, cmplog_map_w, cmplog_map_h
|
edges_map_size, cmp_map_size, cmplog_map_w, cmplog_map_h, acc_map_size
|
||||||
)
|
)
|
||||||
.expect("Could not write file");
|
.expect("Could not write file");
|
||||||
|
|
||||||
@ -45,6 +50,7 @@ fn main() {
|
|||||||
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");
|
||||||
|
println!("cargo:rerun-if-env-changed=LIBAFL_ACCOUNTING_MAP_SIZE");
|
||||||
|
|
||||||
//std::env::set_var("CC", "clang");
|
//std::env::set_var("CC", "clang");
|
||||||
//std::env::set_var("CXX", "clang++");
|
//std::env::set_var("CXX", "clang++");
|
||||||
@ -95,6 +101,7 @@ fn main() {
|
|||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file(src_dir.join("coverage.c"))
|
.file(src_dir.join("coverage.c"))
|
||||||
.define("EDGES_MAP_SIZE", Some(&*format!("{}", edges_map_size)))
|
.define("EDGES_MAP_SIZE", Some(&*format!("{}", edges_map_size)))
|
||||||
|
.define("ACCOUNTING_MAP_SIZE", Some(&*format!("{}", acc_map_size)))
|
||||||
.compile("coverage");
|
.compile("coverage");
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=src/cmplog.h");
|
println!("cargo:rerun-if-changed=src/cmplog.h");
|
||||||
|
@ -9,9 +9,10 @@ typedef uint32_t prev_loc_t;
|
|||||||
#define CTX_MAX_K 32U
|
#define CTX_MAX_K 32U
|
||||||
|
|
||||||
extern uint8_t __afl_area_ptr_local[EDGES_MAP_SIZE];
|
extern uint8_t __afl_area_ptr_local[EDGES_MAP_SIZE];
|
||||||
|
|
||||||
uint8_t* __afl_area_ptr = __afl_area_ptr_local;
|
uint8_t* __afl_area_ptr = __afl_area_ptr_local;
|
||||||
|
|
||||||
|
extern uint32_t __afl_acc_memop_ptr_local[ACCOUNTING_MAP_SIZE];
|
||||||
|
uint32_t* __afl_acc_memop_ptr = __afl_acc_memop_ptr_local;
|
||||||
|
|
||||||
// Weak symbols, LLVM Passes overwrites them if we really use it
|
// Weak symbols, LLVM Passes overwrites them if we really use it
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -23,9 +24,8 @@ uint8_t* __token_start = &__start_libafl_token;
|
|||||||
uint8_t* __token_stop = &__stop_libafl_token;
|
uint8_t* __token_stop = &__stop_libafl_token;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//#if defined(__ANDROID__) || defined(__HAIKU__)
|
//#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||||
MAYBE_THREAD_LOCAL prev_loc_t __afl_prev_loc[NGRAM_SIZE_MAX];
|
MAYBE_THREAD_LOCAL prev_loc_t __afl_prev_loc[NGRAM_SIZE_MAX];
|
||||||
MAYBE_THREAD_LOCAL prev_loc_t __afl_prev_caller[CTX_MAX_K];
|
MAYBE_THREAD_LOCAL prev_loc_t __afl_prev_caller[CTX_MAX_K];
|
||||||
MAYBE_THREAD_LOCAL uint32_t __afl_prev_ctx;
|
MAYBE_THREAD_LOCAL uint32_t __afl_prev_ctx;
|
||||||
|
MAYBE_THREAD_LOCAL prev_loc_t __afl_acc_prev_loc;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Coverage maps as static mut array
|
//! Coverage maps as static mut array
|
||||||
|
|
||||||
use crate::EDGES_MAP_SIZE;
|
use crate::{ACCOUNTING_MAP_SIZE, EDGES_MAP_SIZE};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use libafl::{mutators::Tokens, Error};
|
use libafl::{mutators::Tokens, Error};
|
||||||
|
|
||||||
@ -9,6 +9,11 @@ use libafl::{mutators::Tokens, Error};
|
|||||||
pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
pub static mut __afl_area_ptr_local: [u8; EDGES_MAP_SIZE] = [0; EDGES_MAP_SIZE];
|
||||||
pub use __afl_area_ptr_local as EDGES_MAP;
|
pub use __afl_area_ptr_local as EDGES_MAP;
|
||||||
|
|
||||||
|
/// The map for accounting mem writes.
|
||||||
|
#[no_mangle]
|
||||||
|
pub static mut __afl_acc_memop_ptr_local: [u32; ACCOUNTING_MAP_SIZE] = [0; ACCOUNTING_MAP_SIZE];
|
||||||
|
pub use __afl_acc_memop_ptr_local as ACCOUNTING_MEMOP_MAP;
|
||||||
|
|
||||||
/// The max count of edges tracked.
|
/// The max count of edges tracked.
|
||||||
pub static mut MAX_EDGES_NUM: usize = 0;
|
pub static mut MAX_EDGES_NUM: usize = 0;
|
||||||
|
|
||||||
@ -16,6 +21,9 @@ extern "C" {
|
|||||||
/// The area pointer points to the edges map.
|
/// The area pointer points to the edges map.
|
||||||
pub static mut __afl_area_ptr: *mut u8;
|
pub static mut __afl_area_ptr: *mut u8;
|
||||||
|
|
||||||
|
/// The area pointer points to the accounting mem operations map.
|
||||||
|
pub static mut __afl_acc_memop_ptr: *mut u32;
|
||||||
|
|
||||||
/// Start of libafl token section
|
/// Start of libafl token section
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub static __token_start: *const u8;
|
pub static __token_start: *const u8;
|
||||||
@ -24,6 +32,7 @@ extern "C" {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub static __token_stop: *const u8;
|
pub static __token_stop: *const u8;
|
||||||
}
|
}
|
||||||
|
pub use __afl_acc_memop_ptr as ACCOUNTING_MEMOP_MAP_PTR;
|
||||||
pub use __afl_area_ptr as EDGES_MAP_PTR;
|
pub use __afl_area_ptr as EDGES_MAP_PTR;
|
||||||
|
|
||||||
/// Return Tokens from the compile-time token section
|
/// Return Tokens from the compile-time token section
|
||||||
|
Loading…
x
Reference in New Issue
Block a user