mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-12 18:18:07 +00:00
Initial integration
This commit is contained in:
@ -75,6 +75,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/types.h>
|
||||
#include "asanfuzz.h"
|
||||
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || defined(__DragonFly__)
|
||||
@ -610,7 +611,12 @@ typedef struct afl_state {
|
||||
u8 *var_bytes; /* Bytes that appear to be variable */
|
||||
|
||||
#define N_FUZZ_SIZE (1 << 21)
|
||||
#define N_FUZZ_SIZE_BITMAP (1 << 29)
|
||||
u32 *n_fuzz;
|
||||
u8 *n_fuzz_dup;
|
||||
u8 *classified_n_fuzz;
|
||||
u8 *simplitied_n_fuzz;
|
||||
|
||||
|
||||
volatile u8 stop_soon, /* Ctrl-C pressed? */
|
||||
clear_screen; /* Window resized? */
|
||||
@ -728,6 +734,14 @@ typedef struct afl_state {
|
||||
char *cmplog_binary;
|
||||
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
|
||||
|
||||
/* ASAN Fuzing */
|
||||
char *san_binary[MAX_EXTRA_SAN_BINARY];
|
||||
afl_forkserver_t san_fsrvs[MAX_EXTRA_SAN_BINARY];
|
||||
u8 san_binary_length; /* 0 means extra san binaries not given */
|
||||
u8 no_saving_crash_seed;
|
||||
u32 san_case_status;
|
||||
enum SanitizerAbstraction san_abstraction;
|
||||
|
||||
/* Custom mutators */
|
||||
struct custom_mutator *mutator;
|
||||
|
||||
|
50
include/asanfuzz.h
Normal file
50
include/asanfuzz.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
american fuzzy lop++ - cmplog header
|
||||
------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de>,
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>,
|
||||
Dominik Maier <mail@dmnk.co>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2023 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:
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Shared code to handle the shared memory. This is used by the fuzzer
|
||||
as well the other components like afl-tmin, afl-showmap, etc...
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _AFL_ASAMFUZZ_H
|
||||
#define _AFL_ASAMFUZZ_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// new_bits for describe_op
|
||||
// new_bits value 1, 2 and 0x80 are already used!
|
||||
#define SAN_CRASH_ONLY (1 << 4)
|
||||
#define NON_COV_INCREASE_BUG (1 << 5)
|
||||
|
||||
enum SanitizerAbstraction {
|
||||
UNIQUE_TRACE = 0, // Feed all unique trace to sanitizers, the most sensitive
|
||||
SIMPLIFY_TRACE,
|
||||
COVERAGE_INCREASE // Feed all coverage increasing cases to sanitizers, the least sensitive
|
||||
};
|
||||
|
||||
/* Execs the child */
|
||||
|
||||
struct afl_forkserver;
|
||||
void sanfuzz_exec_child(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
#endif
|
||||
|
@ -97,6 +97,12 @@
|
||||
/* Maximum allowed fails per CMP value. Default: 96 */
|
||||
#define CMPLOG_FAIL_MAX 96
|
||||
|
||||
/*
|
||||
* Effective fuzzing with selective feeding inputs
|
||||
*/
|
||||
|
||||
#define MAX_EXTRA_SAN_BINARY 4
|
||||
|
||||
/* -------------------------------------*/
|
||||
/* Now non-cmplog configuration options */
|
||||
/* -------------------------------------*/
|
||||
@ -504,6 +510,9 @@
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
/* ASAN SHM ID */
|
||||
#define AFL_ASAN_FUZZ_SHM_ENV_VAR "__AFL_ASAN_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
|
@ -72,6 +72,22 @@ inline void classify_counts(afl_forkserver_t *fsrv) {
|
||||
|
||||
}
|
||||
|
||||
inline void classify_counts_mem(u64* mem, u32 size) {
|
||||
|
||||
u32 i = (size >> 3);
|
||||
|
||||
while (i--) {
|
||||
|
||||
/* Optimize for sparse bitmaps. */
|
||||
|
||||
if (unlikely(*mem)) { *mem = classify_word(*mem); }
|
||||
|
||||
mem++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Updates the virgin bits, then reflects whether a new count or a new tuple is
|
||||
* seen in ret. */
|
||||
inline void discover_word(u8 *ret, u64 *current, u64 *virgin) {
|
||||
|
@ -357,9 +357,9 @@ static inline const char *colorfilter(const char *x) {
|
||||
do { \
|
||||
\
|
||||
if (res < 0) \
|
||||
PFATAL(x); \
|
||||
ABORT(x); \
|
||||
else \
|
||||
FATAL(x); \
|
||||
ABORT(x); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
|
@ -117,8 +117,8 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_USE_UBSAN", "AFL_UBSAN_VERBOSE", "AFL_USE_TSAN", "AFL_USE_CFISAN",
|
||||
"AFL_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
|
||||
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME", NULL
|
||||
|
||||
"AFL_PRINT_FILENAMES", "AFL_PIZZA_MODE", "AFL_NO_FASTRESUME",
|
||||
"AFL_SAN_ABSTRACTION", "AFL_SAN_NO_INST", "AFL_SAN_RECOVER", NULL
|
||||
};
|
||||
|
||||
extern char *afl_environment_variables[];
|
||||
|
@ -159,6 +159,8 @@ typedef struct afl_forkserver {
|
||||
|
||||
bool debug; /* debug mode? */
|
||||
|
||||
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented? */
|
||||
|
||||
bool uses_crash_exitcode; /* Custom crash exitcode specified? */
|
||||
u8 crash_exitcode; /* The crash exitcode specified */
|
||||
|
||||
@ -167,6 +169,7 @@ typedef struct afl_forkserver {
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
|
||||
char *cmplog_binary; /* the name of the cmplog binary */
|
||||
char *asanfuzz_binary; /* the name of the ASAN binary */
|
||||
|
||||
/* persistent mode replay functionality */
|
||||
u32 persistent_record; /* persistent replay setting */
|
||||
|
@ -33,6 +33,8 @@
|
||||
u32 hash32(u8 *key, u32 len, u32 seed);
|
||||
u64 hash64(u8 *key, u32 len, u64 seed);
|
||||
|
||||
u32 hash32_xxh32(u8 *key, u32 len, u32 seed);
|
||||
|
||||
#if 0
|
||||
|
||||
The following code is disabled because xxh3 is 30% faster
|
||||
|
@ -51,6 +51,7 @@ typedef struct sharedmem {
|
||||
size_t map_size; /* actual allocated size */
|
||||
|
||||
int cmplog_mode;
|
||||
int sanfuzz_mode;
|
||||
int shmemfuzz_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
|
@ -327,8 +327,14 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
|
||||
|
||||
};
|
||||
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
|
||||
} else {
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -380,8 +386,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
} else {
|
||||
if (debug) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
|
@ -261,8 +261,16 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
|
||||
|
||||
};
|
||||
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
// TODO: Support LTO or llvm classic?
|
||||
// Note we still need afl-compiler-rt so we just disable the instrumentation here.
|
||||
if (!getenv("AFL_SAN_NO_INST")) {
|
||||
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
|
||||
return PreservedAnalyses::none();
|
||||
} else {
|
||||
if (getenv("AFL_DEBUG")) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
}
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
}
|
||||
|
@ -223,6 +223,22 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
#if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (debug) {
|
||||
fprintf(stderr, "Intrument disabled\n");
|
||||
}
|
||||
return PA;
|
||||
}
|
||||
#else
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (debug) {
|
||||
fprintf(stderr, "Intrument disabled\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-llvm-pass" VERSION cRST
|
||||
|
33
src/afl-cc.c
33
src/afl-cc.c
@ -246,6 +246,13 @@ static inline void insert_object(aflcc_state_t *aflcc, u8 *obj, u8 *fmt,
|
||||
|
||||
/* Insert params into the new argv, make clang load the pass. */
|
||||
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (debug) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#if LLVM_MAJOR >= 11 /* use new pass manager */
|
||||
#if LLVM_MAJOR < 16
|
||||
@ -2063,6 +2070,10 @@ void add_sanitizers(aflcc_state_t *aflcc, char **envp) {
|
||||
|
||||
aflcc->have_cfisan = 1;
|
||||
|
||||
if (getenv("AFL_SAN_RECOVER")) {
|
||||
cc_params[cc_par_cnt++] = "-fsanitize-recover=all";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -2079,7 +2090,12 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
* anyway.
|
||||
*/
|
||||
if (aflcc->have_rust_asanrt) { return; }
|
||||
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (debug) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
/* If llvm-config doesn't figure out LLVM_MAJOR, just
|
||||
go on anyway and let compiler complain if doesn't work. */
|
||||
|
||||
@ -2091,10 +2107,11 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
"pcguard instrumentation with pc-table requires LLVM 6.0.1+"
|
||||
" otherwise the compiler will fail");
|
||||
#endif
|
||||
|
||||
if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
|
||||
|
||||
insert_param(aflcc,
|
||||
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
|
||||
"-fsanitize-coverage=trace-pc-guard,bb,no-prune,pc-table");
|
||||
|
||||
} else {
|
||||
|
||||
@ -2113,11 +2130,17 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
|
||||
*/
|
||||
void add_optimized_pcguard(aflcc_state_t *aflcc) {
|
||||
|
||||
if (getenv("AFL_SAN_NO_INST")) {
|
||||
if (debug) {
|
||||
DEBUGF("Instrument disabled\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#if LLVM_MAJOR >= 13
|
||||
#if defined __ANDROID__ || ANDROID
|
||||
|
||||
insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
|
||||
aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
|
||||
aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;
|
||||
|
||||
#else
|
||||
|
||||
|
@ -1918,18 +1918,21 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target(
|
||||
must prevent any earlier operations from venturing into that
|
||||
territory. */
|
||||
|
||||
/* If the binary is not instrumented, we don't care about the coverage. Make it a bit faster */
|
||||
if (!fsrv->san_but_not_instrumented) {
|
||||
#ifdef __linux__
|
||||
if (likely(!fsrv->nyx_mode)) {
|
||||
|
||||
memset(fsrv->trace_bits, 0, fsrv->map_size);
|
||||
MEM_BARRIER();
|
||||
memset(fsrv->trace_bits, 0, fsrv->map_size);
|
||||
MEM_BARRIER();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
memset(fsrv->trace_bits, 0, fsrv->map_size);
|
||||
MEM_BARRIER();
|
||||
memset(fsrv->trace_bits, 0, fsrv->map_size);
|
||||
MEM_BARRIER();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* we have the fork server (or faux server) up and running
|
||||
First, tell it if the previous run timed out. */
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "asanfuzz.h"
|
||||
#if !defined NAME_MAX
|
||||
#define NAME_MAX _XOPEN_NAME_MAX
|
||||
#endif
|
||||
@ -297,6 +300,9 @@ void minimize_bits(afl_state_t *afl, u8 *dst, u8 *src) {
|
||||
u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
|
||||
|
||||
u8 is_timeout = 0;
|
||||
u8 san_crash_only = (afl->san_case_status & SAN_CRASH_ONLY);
|
||||
u8 non_cov_incr = (afl->san_case_status & NON_COV_INCREASE_BUG);
|
||||
|
||||
|
||||
if (new_bits & 0xf0) {
|
||||
|
||||
@ -388,6 +394,10 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
|
||||
|
||||
if (new_bits == 2) { strcat(ret, ",+cov"); }
|
||||
|
||||
if (san_crash_only) { strcat(ret, ",+san"); }
|
||||
|
||||
if (non_cov_incr) { strcat(ret, ",+noncov"); }
|
||||
|
||||
if (unlikely(strlen(ret) >= max_description_len))
|
||||
FATAL("describe string is too long");
|
||||
|
||||
@ -452,6 +462,19 @@ void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
static void bitmap_set(u8* map, u32 index) {
|
||||
map[index / 8] |= (1u << ( index % 8 ));
|
||||
}
|
||||
|
||||
// static u8 bitmap_clear(u8* map, u32 index) {
|
||||
// map[index / 8] &= ~(1u << (index % 8));
|
||||
// }
|
||||
|
||||
static u8 bitmap_read(u8* map, u32 index) {
|
||||
return (map[index / 8] >> (index % 8)) & 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check if the result of an execve() during routine fuzzing is interesting,
|
||||
save or queue the input test case for further analysis if so. Returns 1 if
|
||||
entry is saved, 0 otherwise. */
|
||||
@ -484,6 +507,22 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
need_hash = 1;
|
||||
s32 fd;
|
||||
u64 cksum = 0;
|
||||
u32 cksum_simplified = 0, cksum_unique = 0;
|
||||
u8 san_fault = 0;
|
||||
u8 san_idx = 0;
|
||||
u8 feed_san = 0;
|
||||
u8 crashed = 0;
|
||||
|
||||
afl->san_case_status = 0;
|
||||
|
||||
/* Mask out var bytes */
|
||||
if (unlikely(afl->san_binary_length)) {
|
||||
for (u32 i = 0; i < afl->fsrv.map_size; i++) {
|
||||
if (afl->var_bytes[i] && afl->fsrv.trace_bits[i]) {
|
||||
afl->fsrv.trace_bits[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update path frequency. */
|
||||
|
||||
@ -503,29 +542,96 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
|
||||
}
|
||||
|
||||
/* Only "normal" inputs seem interested to us */
|
||||
if (likely(fault == afl->crash_mode)) {
|
||||
|
||||
if (unlikely(afl->san_binary_length) && likely(afl->san_abstraction == SIMPLIFY_TRACE)) {
|
||||
memcpy(afl->san_fsrvs[0].trace_bits, afl->fsrv.trace_bits, afl->fsrv.map_size);
|
||||
classify_counts_mem((u64*)afl->san_fsrvs[0].trace_bits, afl->fsrv.map_size);
|
||||
simplify_trace(afl, afl->san_fsrvs[0].trace_bits);
|
||||
|
||||
// cksum_simplified = hash64(afl->san_fsrvs[0].trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
cksum_simplified = hash32_xxh32(afl->san_fsrvs[0].trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
|
||||
if ( unlikely(!bitmap_read(afl->simplitied_n_fuzz, cksum_simplified))) {
|
||||
feed_san = 1;
|
||||
bitmap_set(afl->simplitied_n_fuzz, cksum_simplified);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (unlikely(afl->san_binary_length) && unlikely(afl->san_abstraction == COVERAGE_INCREASE)) {
|
||||
|
||||
/* Check if the input increase the coverage */
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
if (unlikely(new_bits)) {
|
||||
feed_san = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(afl->san_binary_length) && likely(afl->san_abstraction == UNIQUE_TRACE)) {
|
||||
cksum_unique = hash32_xxh32(afl->fsrv.trace_bits, afl->fsrv.map_size, HASH_CONST);
|
||||
if (unlikely(!bitmap_read(afl->n_fuzz_dup, cksum) && fault == afl->crash_mode)) {
|
||||
feed_san = 1;
|
||||
bitmap_set(afl->n_fuzz_dup, cksum_unique);
|
||||
}
|
||||
}
|
||||
|
||||
if (feed_san) {
|
||||
/* The input seems interested to other sanitizers, feed it into extra binaries. */
|
||||
|
||||
for (san_idx = 0; san_idx < afl->san_binary_length; san_idx++) {
|
||||
|
||||
len = write_to_testcase(afl, &mem, len, 0);
|
||||
san_fault = fuzz_run_target(afl, &afl->san_fsrvs[san_idx], afl->san_fsrvs[san_idx].exec_tmout);
|
||||
|
||||
// DEBUGF("ASAN Result: %hhd\n", asan_fault);
|
||||
|
||||
if (unlikely(san_fault && fault == afl->crash_mode)) {
|
||||
/* sanitizers discovers distinct bugs! */
|
||||
afl->san_case_status |= SAN_CRASH_ONLY;
|
||||
}
|
||||
|
||||
if (san_fault == FSRV_RUN_CRASH) {
|
||||
/* Treat this execution as fault detected by ASAN */
|
||||
// fault = san_fault;
|
||||
|
||||
/* That's pretty enough, break to avoid more overhead. */
|
||||
break;
|
||||
} else {
|
||||
// or keep san_fault as ok
|
||||
san_fault = FSRV_RUN_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no crash, everything is fine. */
|
||||
if (likely(fault == afl->crash_mode)) {
|
||||
|
||||
/* Keep only if there are new bits in the map, add to queue for
|
||||
future fuzzing, etc. */
|
||||
|
||||
if (likely(classified)) {
|
||||
|
||||
new_bits = has_new_bits(afl, afl->virgin_bits);
|
||||
|
||||
} else {
|
||||
|
||||
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
|
||||
/* If we are in coverage increasing abstraction and have fed input to sanitizers, we are
|
||||
sure it has new bits.*/
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
if (unlikely(new_bits)) { classified = 1; }
|
||||
|
||||
}
|
||||
|
||||
if (likely(!new_bits)) {
|
||||
|
||||
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
|
||||
return 0;
|
||||
|
||||
if (san_fault == FSRV_RUN_OK) {
|
||||
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
|
||||
return 0;
|
||||
} else {
|
||||
afl->san_case_status |= NON_COV_INCREASE_BUG;
|
||||
fault = san_fault;
|
||||
classified = new_bits;
|
||||
goto may_save_fault;
|
||||
}
|
||||
}
|
||||
fault = san_fault;
|
||||
classified = new_bits;
|
||||
|
||||
save_to_queue:
|
||||
|
||||
@ -653,7 +759,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
|
||||
keeping = 1;
|
||||
|
||||
}
|
||||
|
||||
may_save_fault:
|
||||
switch (fault) {
|
||||
|
||||
case FSRV_RUN_TMOUT:
|
||||
|
@ -2332,7 +2332,7 @@ void setup_dirs_fds(afl_state_t *afl) {
|
||||
afl->fsrv.plot_file,
|
||||
"# relative_time, cycles_done, cur_item, corpus_count, "
|
||||
"pending_total, pending_favs, map_size, saved_crashes, "
|
||||
"saved_hangs, max_depth, execs_per_sec, total_execs, edges_found\n");
|
||||
"saved_hangs, max_depth, execs_per_sec, total_execs, edges_found, total_crashes, servers_count, san1_exec...\n");
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
#include "cmplog.h"
|
||||
#include "asanfuzz.h"
|
||||
|
||||
#ifdef PROFILING
|
||||
u64 time_spent_working = 0;
|
||||
|
43
src/afl-fuzz-sanfuzz.c
Normal file
43
src/afl-fuzz-sanfuzz.c
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
american fuzzy lop++ - cmplog execution routines
|
||||
------------------------------------------------
|
||||
|
||||
Originally written by Michal Zalewski
|
||||
|
||||
Forkserver design by Jann Horn <jannhorn@googlemail.com>
|
||||
|
||||
Now maintained by by Marc Heuse <mh@mh-sec.de>,
|
||||
Heiko Eißfeldt <heiko.eissfeldt@hexco.de> and
|
||||
Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2016, 2017 Google Inc. All rights reserved.
|
||||
Copyright 2019-2023 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:
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Shared code to handle the shared memory. This is used by the fuzzer
|
||||
as well the other components like afl-tmin, afl-showmap, etc...
|
||||
|
||||
*/
|
||||
|
||||
/* This file roughly folows afl-fuzz-asanfuzz */
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
void sanfuzz_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
if (!fsrv->qemu_mode && !fsrv->frida_mode && argv[0] != fsrv->asanfuzz_binary) {
|
||||
|
||||
argv[0] = fsrv->asanfuzz_binary;
|
||||
|
||||
}
|
||||
|
||||
execv(fsrv->target_path, argv);
|
||||
|
||||
}
|
@ -386,6 +386,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
"bitmap_cvg : %0.02f%%\n"
|
||||
"saved_crashes : %llu\n"
|
||||
"saved_hangs : %llu\n"
|
||||
"total_tmout : %llu\n"
|
||||
"last_find : %llu\n"
|
||||
"last_crash : %llu\n"
|
||||
"last_hang : %llu\n"
|
||||
@ -424,7 +425,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
afl->queued_discovered, afl->queued_imported, afl->queued_variable,
|
||||
afl->max_depth, afl->current_entry, afl->pending_favored,
|
||||
afl->pending_not_fuzzed, stability, bitmap_cvg, afl->saved_crashes,
|
||||
afl->saved_hangs, afl->last_find_time / 1000, afl->last_crash_time / 1000,
|
||||
afl->saved_hangs, afl->total_tmouts, afl->last_find_time / 1000, afl->last_crash_time / 1000,
|
||||
afl->last_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs,
|
||||
afl->fsrv.exec_tmout, afl->slowest_exec_ms,
|
||||
#ifndef __HAIKU__
|
||||
@ -458,6 +459,16 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
: "default",
|
||||
afl->orig_cmdline);
|
||||
|
||||
if (afl->san_binary_length) {
|
||||
for (u8 i = 0; i < afl->san_binary_length; i++) {
|
||||
fprintf(f,
|
||||
"extra_binary : %s\n"
|
||||
"total_execs : %llu\n",
|
||||
afl->san_binary[i],
|
||||
afl->san_fsrvs[i].total_execs);
|
||||
}
|
||||
}
|
||||
|
||||
/* ignore errors */
|
||||
|
||||
if (afl->debug) {
|
||||
@ -541,7 +552,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
afl->plot_prev_md == afl->max_depth &&
|
||||
afl->plot_prev_ed == afl->fsrv.total_execs) ||
|
||||
!afl->queue_cycle ||
|
||||
get_cur_time() - afl->start_time <= 60000))) {
|
||||
get_cur_time() - afl->start_time <= 1000))) {
|
||||
|
||||
return;
|
||||
|
||||
@ -565,12 +576,19 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
|
||||
fprintf(afl->fsrv.plot_file,
|
||||
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, "
|
||||
"%u\n",
|
||||
"%u, %llu, %u",
|
||||
((afl->prev_run_time + get_cur_time() - afl->start_time) / 1000),
|
||||
afl->queue_cycle - 1, afl->current_entry, afl->queued_items,
|
||||
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
|
||||
afl->saved_crashes, afl->saved_hangs, afl->max_depth, eps,
|
||||
afl->plot_prev_ed, t_bytes); /* ignore errors */
|
||||
afl->plot_prev_ed, t_bytes, afl->total_crashes, (u32)afl->san_binary_length); /* ignore errors */
|
||||
|
||||
|
||||
for (u32 i = 0; i < afl->san_binary_length; i++) {
|
||||
fprintf(afl->fsrv.plot_file, ", %llu", afl->san_fsrvs[i].total_execs);
|
||||
}
|
||||
|
||||
fprintf(afl->fsrv.plot_file, "\n");
|
||||
|
||||
fflush(afl->fsrv.plot_file);
|
||||
|
||||
|
145
src/afl-fuzz.c
145
src/afl-fuzz.c
@ -25,7 +25,9 @@
|
||||
*/
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include "alloc-inl.h"
|
||||
#include "cmplog.h"
|
||||
#include "asanfuzz.h"
|
||||
#include "common.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
@ -252,13 +254,15 @@ static void usage(u8 *argv0, int more_help) {
|
||||
" X=extreme transform solving, R=random colorization "
|
||||
"bytes.\n\n"
|
||||
"Fuzzing behavior settings:\n"
|
||||
" -Z - sequential queue selection instead of weighted "
|
||||
" -Z - sequential queue selection instead of weighted "
|
||||
"random\n"
|
||||
" -N - do not unlink the fuzzing input file (for devices "
|
||||
" -N - do not unlink the fuzzing input file (for devices "
|
||||
"etc.)\n"
|
||||
" -n - fuzz without instrumentation (non-instrumented mode)\n"
|
||||
" -x dict_file - fuzzer dictionary (see README.md, specify up to 4 "
|
||||
"times)\n\n"
|
||||
" -n - fuzz without instrumentation (non-instrumented mode)\n"
|
||||
" -x dict_file - fuzzer dictionary (see README.md, specify up to 4 "
|
||||
"times)\n"
|
||||
" -a san_binary - Specify the extra sanitizer instrumented binaries,\n"
|
||||
" can be specified multiple times.\n\n"
|
||||
|
||||
"Test settings:\n"
|
||||
" -s seed - use a fixed seed for the RNG\n"
|
||||
@ -549,6 +553,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
|
||||
extras_dir_cnt = 0 /*, have_p = 0*/;
|
||||
char *afl_preload;
|
||||
char *san_abstraction;
|
||||
char *frida_afl_preload = NULL;
|
||||
char **use_argv;
|
||||
|
||||
@ -607,7 +612,7 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
// still available: HjJkKqruvwz
|
||||
while ((opt = getopt(argc, argv,
|
||||
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
|
||||
"+aw:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
|
||||
"T:uUV:WXx:YzZ")) > 0) {
|
||||
|
||||
switch (opt) {
|
||||
@ -741,6 +746,17 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
case 'w' : {
|
||||
|
||||
if (afl->san_binary_length == MAX_EXTRA_SAN_BINARY) {
|
||||
FATAL("Only %d extra sanitizer instrumented binaries are supported.", MAX_EXTRA_SAN_BINARY);
|
||||
}
|
||||
|
||||
afl->shm.sanfuzz_mode = 1;
|
||||
afl->san_binary[afl->san_binary_length++] = optarg;
|
||||
break;
|
||||
}
|
||||
|
||||
case 's': {
|
||||
|
||||
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
|
||||
@ -1727,6 +1743,9 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
afl->n_fuzz_dup = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8));
|
||||
afl->simplitied_n_fuzz = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8));
|
||||
|
||||
if (get_afl_env("AFL_NO_FORKSRV")) { afl->no_forkserver = 1; }
|
||||
if (get_afl_env("AFL_NO_CPU_RED")) { afl->no_cpu_meter_red = 1; }
|
||||
if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
|
||||
@ -2396,6 +2415,10 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
if (!afl->fsrv.out_file) { setup_stdio_file(afl); }
|
||||
|
||||
for (u8 i = 0; i < afl->san_binary_length; i++) {
|
||||
check_binary(afl, afl->san_binary[i]);
|
||||
}
|
||||
|
||||
if (afl->cmplog_binary) {
|
||||
|
||||
if (afl->unicorn_mode) {
|
||||
@ -2554,6 +2577,109 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
san_abstraction = getenv("AFL_SAN_ABSTRACTION");
|
||||
if (!san_abstraction || !strcmp(san_abstraction, "unique_trace")) {
|
||||
afl->san_abstraction = UNIQUE_TRACE;
|
||||
} else if (!strcmp(san_abstraction, "coverage_increase")) {
|
||||
afl->san_abstraction = COVERAGE_INCREASE;
|
||||
} else if (!strcmp(san_abstraction, "simplify_trace")) {
|
||||
afl->san_abstraction = SIMPLIFY_TRACE;
|
||||
} else {
|
||||
WARNF("Unkown abstraction: %s, fallback to unique trace.\n", san_abstraction);
|
||||
afl->san_abstraction = UNIQUE_TRACE;
|
||||
}
|
||||
|
||||
afl->no_saving_crash_seed = false;
|
||||
|
||||
if (!afl->san_binary_length && san_abstraction) {
|
||||
WARNF("No extra sanitizer instrumented binaries are given, do you forget -a?\n");
|
||||
}
|
||||
|
||||
/* Maybe merge with cmplog but much cmplog code was already copy-paste style... */
|
||||
if (afl->san_binary_length) {
|
||||
|
||||
for (u8 i = 0; i < afl->san_binary_length; i++) {
|
||||
ACTF("Spawning forkserver for %s", afl->san_binary[i]);
|
||||
afl_fsrv_init_dup(&afl->san_fsrvs[i], &afl->fsrv);
|
||||
|
||||
/*
|
||||
* We don't really collect trace bits for sanitizer instrumented binary so we just allocate
|
||||
* some dummy memory here.
|
||||
*/
|
||||
afl->san_fsrvs[i].trace_bits = ck_alloc(afl->fsrv.map_size + 8); /* One more u64 according to afl_shm_init*/
|
||||
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
|
||||
afl->san_fsrvs[i].san_but_not_instrumented = 1;
|
||||
|
||||
afl->san_fsrvs[i].cs_mode = afl->fsrv.cs_mode;
|
||||
afl->san_fsrvs[i].qemu_mode = afl->fsrv.qemu_mode;
|
||||
afl->san_fsrvs[i].frida_mode = afl->fsrv.frida_mode;
|
||||
afl->san_fsrvs[i].asanfuzz_binary = afl->san_binary[i];
|
||||
afl->san_fsrvs[i].target_path = afl->san_binary[i];
|
||||
afl->san_fsrvs[i].init_child_func = sanfuzz_exec_child;
|
||||
|
||||
afl->san_fsrvs[i].child_kill_signal = afl->fsrv.child_kill_signal; // I believe cmplog also needs this.
|
||||
afl->san_fsrvs[i].fsrv_kill_signal = afl->fsrv.fsrv_kill_signal;
|
||||
|
||||
if ((map_size <= DEFAULT_SHMEM_SIZE ||
|
||||
afl->san_fsrvs[i].map_size < map_size) &&
|
||||
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
!afl->fsrv.frida_mode && !afl->unicorn_mode && !afl->fsrv.cs_mode &&
|
||||
!afl->afl_env.afl_skip_bin_check) {
|
||||
|
||||
afl->san_fsrvs[i].map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
|
||||
char vbuf[16];
|
||||
snprintf(vbuf, sizeof(vbuf), "%u", afl->san_fsrvs[i].map_size);
|
||||
setenv("AFL_MAP_SIZE", vbuf, 1);
|
||||
|
||||
}
|
||||
|
||||
u32 new_map_size =
|
||||
afl_fsrv_get_mapsize(&afl->san_fsrvs[i], afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
// only reinitialize when it needs to be larger
|
||||
if (map_size < new_map_size) {
|
||||
|
||||
OKF("Re-initializing maps to %u bytes due to SAN instrumented binary", new_map_size);
|
||||
|
||||
afl->virgin_bits = ck_realloc(afl->virgin_bits, new_map_size);
|
||||
afl->virgin_tmout = ck_realloc(afl->virgin_tmout, new_map_size);
|
||||
afl->virgin_crash = ck_realloc(afl->virgin_crash, new_map_size);
|
||||
afl->var_bytes = ck_realloc(afl->var_bytes, new_map_size);
|
||||
afl->top_rated =
|
||||
ck_realloc(afl->top_rated, new_map_size * sizeof(void *));
|
||||
afl->clean_trace = ck_realloc(afl->clean_trace, new_map_size);
|
||||
afl->clean_trace_custom =
|
||||
ck_realloc(afl->clean_trace_custom, new_map_size);
|
||||
afl->first_trace = ck_realloc(afl->first_trace, new_map_size);
|
||||
afl->map_tmp_buf = ck_realloc(afl->map_tmp_buf, new_map_size);
|
||||
|
||||
afl_fsrv_kill(&afl->fsrv);
|
||||
afl_fsrv_kill(&afl->san_fsrvs[i]);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
|
||||
afl->san_fsrvs[i].map_size = new_map_size; // non-cmplog stays the same
|
||||
map_size = new_map_size;
|
||||
|
||||
setenv("AFL_NO_AUTODICT", "1", 1); // loaded already
|
||||
afl->fsrv.trace_bits =
|
||||
afl_shm_init(&afl->shm, new_map_size, afl->non_instrumented_mode);
|
||||
ck_free(afl->san_fsrvs[i].trace_bits);
|
||||
afl->san_fsrvs[i].trace_bits = ck_alloc(afl->fsrv.map_size + 8);
|
||||
afl->san_fsrvs[i].map_size = afl->fsrv.map_size;
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
afl_fsrv_start(&afl->san_fsrvs[i], afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
}
|
||||
|
||||
OKF("forkserver for %s successfully started", afl->san_binary[i]);
|
||||
}
|
||||
|
||||
OKF("All forkservers for extra sanitizers instrumented binares are up and we have abstraction = %d", afl->san_abstraction);
|
||||
}
|
||||
|
||||
if (afl->cmplog_binary) {
|
||||
|
||||
ACTF("Spawning cmplog forkserver");
|
||||
@ -3450,6 +3576,13 @@ stop_fuzzing:
|
||||
|
||||
afl_fsrv_deinit(&afl->fsrv);
|
||||
|
||||
|
||||
|
||||
for (u8 i = 0; i < afl->san_binary_length; i++) {
|
||||
ck_free(afl->san_fsrvs[i].trace_bits);
|
||||
afl_fsrv_deinit(&afl->san_fsrvs[i]); // TODO: Is this necessary? cmplog fksrv seems never deinit-ed?
|
||||
}
|
||||
|
||||
/* remove tmpfile */
|
||||
if (!afl->in_place_resume && afl->fsrv.out_file) {
|
||||
|
||||
|
@ -425,3 +425,15 @@ char *sha1_hex_for_file(const char *fname, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
u32 hash32_xxh32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
#else
|
||||
inline u32 hash32_xxh32(u8 *key, u32 len, u32 seed) {
|
||||
|
||||
#endif
|
||||
|
||||
(void)seed;
|
||||
return (u32)XXH32(key, len, seed);
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user