playing around with builds

This commit is contained in:
Dominik Maier 2020-12-21 12:39:29 +01:00
parent 7effca9837
commit 245e44b9d5
8 changed files with 519 additions and 3 deletions

View File

@ -14,7 +14,6 @@ use afl::engines::Engine;
use afl::engines::Fuzzer; use afl::engines::Fuzzer;
use afl::engines::State; use afl::engines::State;
use afl::engines::StdFuzzer; use afl::engines::StdFuzzer;
use afl::events::shmem::AflShmem;
use afl::events::{LlmpEventManager, SimpleStats}; use afl::events::{LlmpEventManager, SimpleStats};
use afl::executors::inmemory::InMemoryExecutor; use afl::executors::inmemory::InMemoryExecutor;
use afl::executors::{Executor, ExitKind}; use afl::executors::{Executor, ExitKind};
@ -81,7 +80,7 @@ pub extern "C" fn afl_libfuzzer_main() {
) )
.get_matches(); .get_matches();
let statstime = value_t!(matches, "statstime", u32).unwrap_or(5); let _ = value_t!(matches, "statstime", u32).unwrap_or(5);
let broker_port = value_t!(matches, "port", u16).unwrap_or(1337); let broker_port = value_t!(matches, "port", u16).unwrap_or(1337);
let workdir = if matches.is_present("workdir") { let workdir = if matches.is_present("workdir") {
@ -141,7 +140,7 @@ pub extern "C" fn afl_libfuzzer_main() {
match input { match input {
Some(x) => state Some(x) => state
.load_initial_inputs(&mut corpus, &mut generator, &mut engine, &mut mgr, &x) .load_initial_inputs(&mut corpus, &mut generator, &mut engine, &mut mgr, &x)
.expect("Failed to load initial corpus"), .expect(&format!("Failed to load initial corpus at {:?}", &x)),
None => (), None => (),
} }

View File

@ -0,0 +1,25 @@
[package]
name = "libfuzzer"
version = "0.1.0"
authors = ["Andrea Fioraldi <andreafioraldi@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
[dependencies]
clap = "2.32.0"
afl = { path = "../../afl/" }
[lib]
crate-type = ["staticlib", "cdylib"]

View File

@ -0,0 +1,43 @@
// build.rs
use std::env;
use std::path::Path;
use std::process::Command;
fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let out_dir = out_dir.to_string_lossy();
println!("cargo:rerun-if-changed=./runtime/rt.c",);
Command::new("clang")
.args(&["-c", "./runtime/rt.c", "-o"])
.arg(&format!("{:?}/rt.o", out_dir))
.status()
.unwrap();
Command::new("ar")
.args(&["crus", "librt.a", "librt.o"])
.current_dir(&Path::new(out_dir.as_ref()))
.status()
.unwrap();
println!("cargo:rerun-if-changed=harness.c");
Command::new("clang")
.args(&["-c", "./harness.c", "-I./libpng-1.6.37", "-o"])
.arg(&format!("{}/harness.o", out_dir))
.status()
.unwrap();
Command::new("ar")
.args(&["crus", "harness.a", "harness.o"])
.current_dir(&Path::new(out_dir.as_ref()))
.status()
.unwrap();
println!("cargo:rustc-link-search=native={}", out_dir);
println!("cargo:rustc-link-lib=static=libpng16");
println!("cargo:rustc-link-lib=static=harness");
println!("cargo:rustc-link-lib=static=rt");
println!("cargo:rerun-if-changed=libpng16.a");
println!("cargo:rerun-if-changed=build.rs");
}

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python3
import subprocess
import sys
import os
script_dir = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
is_cxx = "++" in sys.argv[0]
def cc_exec(args):
if os.getenv("AFL_CC"):
cc_name = os.environ["AFL_CC"]
else:
cc_name = "clang"
if is_cxx:
if os.getenv("AFL_CXX"):
cc_name = os.environ["AFL_CXX"]
else:
cc_name = "clang++"
argv = [cc_name] + args
#print(" ".join(argv))
return subprocess.run(argv)
def common_opts():
return [
"-g",
]
def cc_mode():
args = common_opts()
args += sys.argv[1:]
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
if os.getenv("AFL_USE_ASAN"):
args += ["-fsanitize=address"]
if os.getenv("AFL_USE_MSAN"):
args += ["-fsanitize=memory"]
if os.getenv("AFL_USE_UBSAN"):
args += [
"-fsanitize=undefined",
"-fsanitize-undefined-trap-on-error",
"-fno-sanitize-recover=all",
]
return cc_exec(args)
def ld_mode():
args = common_opts()
args += sys.argv[1:]
args += [
os.path.join(script_dir, "runtime", "rt.o"),
os.path.join(script_dir, "target", "release", "liblibfuzzer.a"),
]
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
if os.getenv("AFL_USE_ASAN"):
args += ["-fsanitize=address"]
if os.getenv("AFL_USE_MSAN"):
args += ["-fsanitize=memory"]
if os.getenv("AFL_USE_UBSAN"):
args += [
"-fsanitize=undefined",
"-fsanitize-undefined-trap-on-error",
"-fno-sanitize-recover=all",
]
args += ["-pthread", "-ldl"] # for Rust
return cc_exec(args)
def is_ld_mode():
return not ("--version" in sys.argv or "--target-help" in sys.argv or
"-c" in sys.argv or "-E" in sys.argv or "-S" in sys.argv or
"-shared" in sys.argv)
#print("\x1b[0;36m" + os.path.basename(sys.argv[0]) + " 1.0a\x1b[0m by <andreafioraldi@gmail.com>")
if len(sys.argv) <= 1:
cc_exec(sys.argv[1:])
elif is_ld_mode():
ld_mode()
else:
cc_mode()

View File

@ -0,0 +1,24 @@
/* An in mmeory fuzzing example. Fuzzer for libpng library */
#include <stdio.h>
#include <stdint.h>
#include "png.h"
/* The actual harness. Using PNG for our example. */
int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len) {
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_set_user_limits(png_ptr, 65535, 65535);
png_infop info_ptr = png_create_info_struct(png_ptr);
png_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
if (setjmp(png_jmpbuf(png_ptr))) return 0;
png_set_progressive_read_fn(png_ptr, NULL, NULL, NULL, NULL);
png_process_data(png_ptr, info_ptr, (uint8_t *)input, len);
return 0;
}

View File

@ -0,0 +1,10 @@
CC ?= clang
all: rt.o
rt.o: rt.c
$(CC) -c rt.c
clean:
rm -f rt.o

View File

@ -0,0 +1,153 @@
#include <stdio.h>
#include <stdint.h>
#define MAP_SIZE 65536
int orig_argc;
char **orig_argv;
char **orig_envp;
uint8_t __lafl_dummy_map[MAP_SIZE];
uint8_t *__lafl_edges_map = __lafl_dummy_map;
uint8_t *__lafl_cmp_map = __lafl_dummy_map;
uint32_t __lafl_max_edges_size = 0;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
__lafl_edges_map[*guard]++;
}
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
if (start == stop || *start) return;
*(start++) = (++__lafl_max_edges_size) & (MAP_SIZE -1);
while (start < stop) {
*start = (++__lafl_max_edges_size) & (MAP_SIZE -1);
start++;
}
}
#define MAX(a, b) \
({ \
\
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; \
\
})
#if defined(__APPLE__)
#pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1
#pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2
#pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4
#pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8
#else
void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__sanitizer_cov_trace_cmp1")));
void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp2")));
void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp4")));
void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp8")));
#endif
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcountll(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
uintptr_t rt = (uintptr_t)__builtin_return_address(0);
if (cases[1] == 64) {
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = rt + i;
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcountll(~(val ^ cases[i + 2]))));
}
} else {
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = rt + i;
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(val ^ cases[i + 2]))));
}
}
}
static void afl_libfuzzer_copy_args(int argc, char** argv, char** envp) {
orig_argc = argc;
orig_argv = argv;
orig_envp = envp;
}
__attribute__((section(".init_array"))) void (* p_afl_libfuzzer_copy_args)(int,char*[],char*[]) = &afl_libfuzzer_copy_args;
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
void afl_libfuzzer_main();
int afl_libfuzzer_init() {
if (LLVMFuzzerInitialize)
return LLVMFuzzerInitialize(&orig_argc, &orig_argv);
else
return 0;
}
int main(int argc, char** argv) {
afl_libfuzzer_main();
return 0;
}

View File

@ -0,0 +1,174 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate clap;
extern crate alloc;
use clap::{App, Arg};
use std::env;
use std::path::PathBuf;
use afl::corpus::Corpus;
use afl::corpus::InMemoryCorpus;
use afl::engines::Engine;
use afl::engines::Fuzzer;
use afl::engines::State;
use afl::engines::StdFuzzer;
use afl::events::{LlmpEventManager, SimpleStats};
use afl::executors::inmemory::InMemoryExecutor;
use afl::executors::{Executor, ExitKind};
use afl::feedbacks::MaxMapFeedback;
use afl::generators::RandPrintablesGenerator;
use afl::mutators::scheduled::HavocBytesMutator;
use afl::mutators::HasMaxSize;
use afl::observers::StdMapObserver;
use afl::stages::mutational::StdMutationalStage;
use afl::tuples::tuple_list;
use afl::utils::StdRand;
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_max_edges_size: u32;
}
fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
unsafe {
LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len());
}
ExitKind::Ok
}
const NAME_COV_MAP: &str = "cov_map";
#[no_mangle]
pub extern "C" fn afl_libfuzzer_main() {
let matches = App::new("libAFLrs fuzzer harness")
.about("libAFLrs fuzzer harness help options.")
.arg(
Arg::with_name("port")
.short("p")
.value_name("PORT")
.takes_value(true)
.help("Broker TCP port to use."),
)
.arg(
Arg::with_name("dictionary")
.short("x")
.value_name("DICTIONARY")
.takes_value(true)
.multiple(true)
.help("Dictionary file to use, can be specified multiple times."),
)
.arg(
Arg::with_name("statstime")
.short("T")
.value_name("STATSTIME")
.takes_value(true)
.help("How often to print statistics in seconds [default: 5, disable: 0]"),
)
.arg(Arg::with_name("workdir")
.help("Where to write the corpus, also reads the data on start. If more than one is supplied the first will be the work directory, all others will just be initially read from.")
.multiple(true)
.value_name("WORKDIR")
)
.get_matches();
let _ = value_t!(matches, "statstime", u32).unwrap_or(5);
let broker_port = value_t!(matches, "port", u16).unwrap_or(1337);
let workdir = if matches.is_present("workdir") {
matches.value_of("workdir").unwrap().to_string()
} else {
env::current_dir().unwrap().to_string_lossy().to_string()
};
let mut dictionary: Option<Vec<PathBuf>> = None;
if matches.is_present("dictionary") {
dictionary = Some(values_t!(matches, "dictionary", PathBuf).unwrap_or_else(|e| e.exit()));
}
let mut input: Option<Vec<PathBuf>> = None;
if matches.is_present("workdir") {
input = Some(values_t!(matches, "workdir", PathBuf).unwrap_or_else(|e| e.exit()));
}
if dictionary != None || input != None {
println!("Information: the first process started is the broker and only processes the \'-p PORT\' option if present.");
}
println!("Workdir: {:?}", workdir);
let mut rand = StdRand::new(0);
let mut corpus = InMemoryCorpus::new();
let mut generator = RandPrintablesGenerator::new(32);
let stats = SimpleStats::new(|s| println!("{}", s));
let mut mgr = LlmpEventManager::new_on_port_std(broker_port, stats).unwrap();
if mgr.is_broker() {
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
mgr.broker_loop().unwrap();
}
println!("We're a client, let's fuzz :)");
let edges_observer =
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe {
__lafl_max_edges_size as usize
});
let edges_feedback = MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer);
let executor = InMemoryExecutor::new("Libfuzzer", harness, tuple_list!(edges_observer));
let mut state = State::new(tuple_list!(edges_feedback));
let mut engine = Engine::new(executor);
// Call LLVMFUzzerInitialize() if present.
unsafe {
if afl_libfuzzer_init() == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1")
}
}
match input {
Some(x) => state
.load_initial_inputs(&mut corpus, &mut generator, &mut engine, &mut mgr, &x)
.expect(&format!("Failed to load initial corpus at {:?}", &x)),
None => (),
}
if corpus.count() < 1 {
println!("Generating random inputs");
state
.generate_initial_inputs(
&mut rand,
&mut corpus,
&mut generator,
&mut engine,
&mut mgr,
4,
)
.expect("Failed to generate initial inputs");
}
println!("We have {} inputs.", corpus.count());
let mut mutator = HavocBytesMutator::new_default();
mutator.set_max_size(4096);
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
fuzzer
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut mgr)
.expect("Fuzzer fatal error");
#[cfg(feature = "std")]
println!("OK");
}