Merge pull request #2288 from wtdcode/upstream

[RFC] Upstream "SAND: Decoupling Sanitization from Fuzzing for Low Overhead"
This commit is contained in:
van Hauser 2025-01-27 16:39:37 +01:00 committed by GitHub
commit 6a4b5807b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 736 additions and 130 deletions

View File

@ -230,6 +230,7 @@ Thank you! (For people sending pull requests - please add yourself to this list
Ruben ten Hove Joey Jiao Ruben ten Hove Joey Jiao
fuzzah @intrigus-lgtm fuzzah @intrigus-lgtm
Yaakov Saxon Sergej Schumilo Yaakov Saxon Sergej Schumilo
Ziqiao Kong
``` ```
</details> </details>

81
docs/SAND.md Normal file
View File

@ -0,0 +1,81 @@
# SAND: Decoupling Sanitization from Fuzzing for Low Overhead
- Authors: Ziqiao Kong, Shaohua Li, Heqing Huang, Zhendong Su
- Maintainer: [Ziqiao Kong](https://github.com/wtdcode)
- Preprint: [arXiv](https://arxiv.org/abs/2402.16497), accepted by ICSE 2025
- Main repo (for paper, reproduction, reference or cite): https://github.com/wtdcode/sand-aflpp
## Motivation
SAND introduces a new fuzzing workflow that can greatly reduce (or even eliminate) sanitizer overhead and combine different sanitizers in one fuzzing compaign.
The key point of SAND is that: sanitizing all inputs is wasting fuzzing power, because bug-triggering inputs are extremely rare (~1%). Obviously, not all inputs worth going through sanitizers. Therefore, if we can somehow "predict" if an input could trigger bugs (defined as "execution pattern"), we could greatly save fuzzing power by only sanitizing a small proportion of all inputs. That's exactly how SAND works.
## Usage
For a normal fuzzing workflow, we have:
1. Build target project with AFL_USE_ASAN=1 to get `target_asan`
2. Fuzz the target with `afl-fuzz -i seeds -o out -- ./target_asan`
For SAND fuzzing workflow, this is slightly different:
1. Build target project _without_ any sanitizers to get `target_native`, which we will define as a "native binary". It is usually done by using `afl-clang-fast/lto(++)` to compile your project _without_ `AFL_USE_ASAN/UBSAN/MSAN`.
2. Build target project with AFL_USE_ASAN=1 AFL_SAN_NO_INST=1 to get `target_asan`. Do note this step can be repeated for multiple sanitizers, like MSAN, UBSAN etc. It is also possible to have ASAN and UBSAN to build together.
3. Fuzz the target with `afl-fuzz -i seeds -o out -w ./target_asan -- ./target_native`. Note `-w` can be specified multiple times.
Then you get:
- almost the same performance as `afl-fuzz -i seeds -o out -- ./target_native`
- and the same bug-finding capability as `afl-fuzz -i seeds -o out -- ./target_asan`
## Example Workflow
Take [test-instr.c](../test-instr.c) as an example.
1. Build the native binary
```bash
afl-clang-fast test-instr.c -o ./native
```
Just like the normal building process, except using `afl-clang-fast`
2. Build the sanitizers-enabled binaries.
```bash
AFL_SAN_NO_INST=1 AFL_USE_UBSAN=1 AFL_USE_ASAN=1 afl-clang-fast test-instr.c -o ./asanubsan
AFL_SAN_NO_INST=1 AFL_USE_MSAN=1 afl-clang-fast test-instr.c -o ./msan
```
Do note `AFL_SAN_NO_INST=1` is crucial, this enables forkservers but disables pc instrumentation. Do not reuse sanitizers-enabled binaries built _without_ `AFL_SAN_NO_INST=1`. This will mess up SAND execution pattern.
3. Start fuzzing
```bash
mkdir /tmp/test
echo "a" > /tmp/test/a
AFL_NO_UI=1 AFL_SKIP_CPUFREQ=1 afl-fuzz -i /tmp/test -o /tmp/out -w ./asanubsan -w ./msan -- ./native @@
```
That's it!
## Tips
### Alternative execution patterns
By default, SAND uses the hash value of the simplified coverage map as execution pattern, i.e. if an input has a unique simplefied coverage map, it will be sent to sanitizers for inspection. This shall work for most cases. However, if you are strongly worried about missing bugs, try `AFL_SAN_ABSTRACTION=unique_trace afl-fuzz ...`, which filters inputs having a _unique coverage map_. Do note this significantly increases the number of inputs by 4-10 times, leading to much lower throughput. Alternatively, SAND also supports `AFL_SAN_ABSTRACTION=coverage_increase`, which essentially equals to running sanitizers on the corpus and thus having almost zero overhead, but at a cost of missing ~15% bugs in our evaluation.
### Run as many sanitizers as possible
Though we just used ASAN as an example, SAND works best if you provide more sanitizers, for example, UBSAN and MSAN.
You might do it via `afl-fuzz -i seeds -o out -w ./target_asan -w ./target_msan -w ./target_ubsan -- ./target_native`. Don't worry about the slow sanitizers like MSAN, SAND could still run very fast because only rather a few inputs are sanitized.
### Bugs types
The execution pattern evaluated in our papers is targeting the common bugs, as ASAN/MSAN/UBSAN catches. For other bug types, you probably need to define new execution patterns and re-evaluate.
### My throughput is greatly impacted
Generally, this is due to too many inputs going through sanitizers, for example, because of unstable targets. You could check stats from `plot_file` to confirm this. Try to switch execution patterns as stated above.

View File

@ -203,6 +203,9 @@ instances, so running more than one address sanitized target would be a waste.
*IF* you are running a saturated corpus, then you can run up to half of the *IF* you are running a saturated corpus, then you can run up to half of the
instances with sanitizers. instances with sanitizers.
An alternative but more effective approach is to use [SAND](./SAND.md) which could
combine different sanitizers at a much higher throughput.
The following sanitizers have built-in support in AFL++: The following sanitizers have built-in support in AFL++:
* ASAN = Address SANitizer, finds memory corruption vulnerabilities like * ASAN = Address SANitizer, finds memory corruption vulnerabilities like

View File

@ -75,6 +75,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/types.h> #include <sys/types.h>
#include "asanfuzz.h"
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \ #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(__NetBSD__) || defined(__DragonFly__) defined(__NetBSD__) || defined(__DragonFly__)
@ -610,7 +611,11 @@ typedef struct afl_state {
u8 *var_bytes; /* Bytes that appear to be variable */ u8 *var_bytes; /* Bytes that appear to be variable */
#define N_FUZZ_SIZE (1 << 21) #define N_FUZZ_SIZE (1 << 21)
#define N_FUZZ_SIZE_BITMAP (1 << 29)
u32 *n_fuzz; u32 *n_fuzz;
u8 *n_fuzz_dup;
u8 *classified_n_fuzz;
u8 *simplified_n_fuzz;
volatile u8 stop_soon, /* Ctrl-C pressed? */ volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen; /* Window resized? */ clear_screen; /* Window resized? */
@ -728,6 +733,13 @@ typedef struct afl_state {
char *cmplog_binary; char *cmplog_binary;
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */ 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 */
u32 san_case_status;
enum SanitizerAbstraction san_abstraction;
/* Custom mutators */ /* Custom mutators */
struct custom_mutator *mutator; struct custom_mutator *mutator;

50
include/asanfuzz.h Normal file
View 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 {
SIMPLIFY_TRACE = 0, // Feed all unique trace to sanitizers, the most sensitive
UNIQUE_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

View File

@ -97,6 +97,12 @@
/* Maximum allowed fails per CMP value. Default: 96 */ /* Maximum allowed fails per CMP value. Default: 96 */
#define CMPLOG_FAIL_MAX 96 #define CMPLOG_FAIL_MAX 96
/*
* Effective fuzzing with selective feeding inputs
*/
#define MAX_EXTRA_SAN_BINARY 4
/* -------------------------------------*/ /* -------------------------------------*/
/* Now non-cmplog configuration options */ /* Now non-cmplog configuration options */
/* -------------------------------------*/ /* -------------------------------------*/
@ -504,6 +510,9 @@
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID" #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 */ /* CPU Affinity lockfile env var */
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE" #define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"

View File

@ -72,6 +72,22 @@ inline void classify_counts(afl_forkserver_t *fsrv) {
} }
inline static 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 /* Updates the virgin bits, then reflects whether a new count or a new tuple is
* seen in ret. */ * seen in ret. */
inline void discover_word(u8 *ret, u64 *current, u64 *virgin) { inline void discover_word(u8 *ret, u64 *current, u64 *virgin) {

View File

@ -117,8 +117,8 @@ static char *afl_environment_variables[] = {
"AFL_USE_UBSAN", "AFL_UBSAN_VERBOSE", "AFL_USE_TSAN", "AFL_USE_CFISAN", "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_CFISAN_VERBOSE", "AFL_USE_LSAN", "AFL_WINE_PATH", "AFL_NO_SNAPSHOT",
"AFL_EXPAND_HAVOC_NOW", "AFL_USE_FASAN", "AFL_USE_QASAN", "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[]; extern char *afl_environment_variables[];

View File

@ -159,6 +159,8 @@ typedef struct afl_forkserver {
bool debug; /* debug mode? */ bool debug; /* debug mode? */
u8 san_but_not_instrumented; /* Is it sanitizer enabled but not instrumented? */
bool uses_crash_exitcode; /* Custom crash exitcode specified? */ bool uses_crash_exitcode; /* Custom crash exitcode specified? */
u8 crash_exitcode; /* The 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 */ u8 *shmem_fuzz; /* allocated memory for fuzzing */
char *cmplog_binary; /* the name of the cmplog binary */ char *cmplog_binary; /* the name of the cmplog binary */
char *asanfuzz_binary; /* the name of the ASAN binary */
/* persistent mode replay functionality */ /* persistent mode replay functionality */
u32 persistent_record; /* persistent replay setting */ u32 persistent_record; /* persistent replay setting */

View File

@ -51,6 +51,7 @@ typedef struct sharedmem {
size_t map_size; /* actual allocated size */ size_t map_size; /* actual allocated size */
int cmplog_mode; int cmplog_mode;
int sanfuzz_mode;
int shmemfuzz_mode; int shmemfuzz_mode;
struct cmp_map *cmp_map; struct cmp_map *cmp_map;

View File

@ -326,9 +326,15 @@ class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
.getPostDomTree(); .getPostDomTree();
}; };
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: private:
@ -380,8 +386,14 @@ PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
}; };
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback)) if (!getenv("AFL_SAN_NO_INST")) {
return PreservedAnalyses::none(); if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
return PreservedAnalyses::none();
} else {
if (debug) {
DEBUGF("Instrument disabled\n");
}
}
return PreservedAnalyses::all(); return PreservedAnalyses::all();

View File

@ -261,8 +261,16 @@ PreservedAnalyses ModuleSanitizerCoverageAFL::run(Module &M,
}; };
if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback)) // TODO: Support LTO or llvm classic?
return PreservedAnalyses::none(); // 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(); return PreservedAnalyses::all();
} }

View File

@ -223,6 +223,22 @@ bool AFLCoverage::runOnModule(Module &M) {
if (getenv("AFL_DEBUG")) debug = 1; 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 PreservedAnalyses::all();
}
#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) { if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
SAYF(cCYA "afl-llvm-pass" VERSION cRST SAYF(cCYA "afl-llvm-pass" VERSION cRST

View File

@ -247,6 +247,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. */ /* Insert params into the new argv, make clang load the pass. */
static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) { static inline void load_llvm_pass(aflcc_state_t *aflcc, u8 *pass) {
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
}
#if LLVM_MAJOR >= 11 /* use new pass manager */ #if LLVM_MAJOR >= 11 /* use new pass manager */
#if LLVM_MAJOR < 16 #if LLVM_MAJOR < 16
insert_param(aflcc, "-fexperimental-new-pass-manager"); insert_param(aflcc, "-fexperimental-new-pass-manager");
@ -2079,6 +2086,12 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
* anyway. * anyway.
*/ */
if (aflcc->have_rust_asanrt) { return; } if (aflcc->have_rust_asanrt) { return; }
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
}
/* If llvm-config doesn't figure out LLVM_MAJOR, just /* If llvm-config doesn't figure out LLVM_MAJOR, just
go on anyway and let compiler complain if doesn't work. */ go on anyway and let compiler complain if doesn't work. */
@ -2091,6 +2104,7 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
"pcguard instrumentation with pc-table requires LLVM 6.0.1+" "pcguard instrumentation with pc-table requires LLVM 6.0.1+"
" otherwise the compiler will fail"); " otherwise the compiler will fail");
#endif #endif
if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) { if (aflcc->instrument_opt_mode & INSTRUMENT_OPT_CODECOV) {
insert_param(aflcc, insert_param(aflcc,
@ -2113,9 +2127,15 @@ void add_native_pcguard(aflcc_state_t *aflcc) {
*/ */
void add_optimized_pcguard(aflcc_state_t *aflcc) { void add_optimized_pcguard(aflcc_state_t *aflcc) {
if (getenv("AFL_SAN_NO_INST")) {
if (!be_quiet) { DEBUGF("SAND: Coverage instrumentation disabled\n"); }
return;
}
#if LLVM_MAJOR >= 13 #if LLVM_MAJOR >= 13
#if defined __ANDROID__ || ANDROID #if defined __ANDROID__ || ANDROID
insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard"); insert_param(aflcc, "-fsanitize-coverage=trace-pc-guard");
aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE; aflcc->instrument_mode = INSTRUMENT_LLVMNATIVE;

View File

@ -1918,18 +1918,21 @@ fsrv_run_result_t __attribute__((hot)) afl_fsrv_run_target(
must prevent any earlier operations from venturing into that must prevent any earlier operations from venturing into that
territory. */ 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__ #ifdef __linux__
if (likely(!fsrv->nyx_mode)) { if (likely(!fsrv->nyx_mode)) {
memset(fsrv->trace_bits, 0, fsrv->map_size); memset(fsrv->trace_bits, 0, fsrv->map_size);
MEM_BARRIER(); MEM_BARRIER();
} }
#else #else
memset(fsrv->trace_bits, 0, fsrv->map_size); memset(fsrv->trace_bits, 0, fsrv->map_size);
MEM_BARRIER(); MEM_BARRIER();
#endif #endif
}
/* we have the fork server (or faux server) up and running /* we have the fork server (or faux server) up and running
First, tell it if the previous run timed out. */ First, tell it if the previous run timed out. */

View File

@ -25,6 +25,9 @@
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include <limits.h> #include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "asanfuzz.h"
#if !defined NAME_MAX #if !defined NAME_MAX
#define NAME_MAX _XOPEN_NAME_MAX #define NAME_MAX _XOPEN_NAME_MAX
#endif #endif
@ -297,6 +300,8 @@ 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 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
u8 is_timeout = 0; 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) { if (new_bits & 0xf0) {
@ -388,6 +393,10 @@ u8 *describe_op(afl_state_t *afl, u8 new_bits, size_t max_description_len) {
if (new_bits == 2) { strcat(ret, ",+cov"); } 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)) if (unlikely(strlen(ret) >= max_description_len))
FATAL("describe string is too long"); FATAL("describe string is too long");
@ -452,6 +461,18 @@ void write_crash_readme(afl_state_t *afl) {
} }
static inline void bitmap_set(u8 *map, u32 index) {
map[index / 8] |= (1u << (index % 8));
}
static inline 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, /* 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 save or queue the input test case for further analysis if so. Returns 1 if
entry is saved, 0 otherwise. */ entry is saved, 0 otherwise. */
@ -484,6 +505,12 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
need_hash = 1; need_hash = 1;
s32 fd; s32 fd;
u64 cksum = 0; u64 cksum = 0;
u32 cksum_simplified = 0, cksum_unique = 0;
u8 san_fault = 0;
u8 san_idx = 0;
u8 feed_san = 0;
afl->san_case_status = 0;
/* Update path frequency. */ /* Update path frequency. */
@ -503,30 +530,131 @@ 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);
// Note: Original SAND implementation used XXHASH32
cksum_simplified = hash32(afl->san_fsrvs[0].trace_bits,
afl->fsrv.map_size, HASH_CONST);
if (unlikely(!bitmap_read(afl->simplified_n_fuzz, cksum_simplified))) {
feed_san = 1;
bitmap_set(afl->simplified_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(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)) { if (likely(fault == afl->crash_mode)) {
/* Keep only if there are new bits in the map, add to queue for /* Keep only if there are new bits in the map, add to queue for
future fuzzing, etc. */ future fuzzing, etc. */
if (!unlikely(afl->san_abstraction == COVERAGE_INCREASE && feed_san)) {
if (likely(classified)) { /* 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(afl, afl->virgin_bits);
} else {
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits); new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
if (unlikely(new_bits)) { classified = 1; }
} }
if (likely(!new_bits)) { if (likely(!new_bits)) {
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; } if (san_fault == FSRV_RUN_OK) {
return 0;
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: save_to_queue:
#ifndef SIMPLE_FILES #ifndef SIMPLE_FILES
@ -654,6 +782,7 @@ u8 __attribute__((hot)) save_if_interesting(afl_state_t *afl, void *mem,
} }
may_save_fault:
switch (fault) { switch (fault) {
case FSRV_RUN_TMOUT: case FSRV_RUN_TMOUT:

View File

@ -2332,7 +2332,15 @@ void setup_dirs_fds(afl_state_t *afl) {
afl->fsrv.plot_file, afl->fsrv.plot_file,
"# relative_time, cycles_done, cur_item, corpus_count, " "# relative_time, cycles_done, cur_item, corpus_count, "
"pending_total, pending_favs, map_size, saved_crashes, " "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");
if (afl->san_binary_length) {
for (u8 i = 0; i < afl->san_binary_length; i++) {
fprintf(afl->fsrv.plot_file, ", sand_fsrv%u_exec", i);
}
}
fprintf(afl->fsrv.plot_file, "\n");
} else { } else {

View File

@ -33,6 +33,7 @@
#endif #endif
#include "cmplog.h" #include "cmplog.h"
#include "asanfuzz.h"
#ifdef PROFILING #ifdef PROFILING
u64 time_spent_working = 0; u64 time_spent_working = 0;

43
src/afl-fuzz-sanfuzz.c Normal file
View 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);
}

View File

@ -356,107 +356,122 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
1000; 1000;
if (!runtime_ms) { runtime_ms = 1; } if (!runtime_ms) { runtime_ms = 1; }
fprintf( fprintf(f,
f, "start_time : %llu\n"
"start_time : %llu\n" "last_update : %llu\n"
"last_update : %llu\n" "run_time : %llu\n"
"run_time : %llu\n" "fuzzer_pid : %u\n"
"fuzzer_pid : %u\n" "cycles_done : %llu\n"
"cycles_done : %llu\n" "cycles_wo_finds : %llu\n"
"cycles_wo_finds : %llu\n" "time_wo_finds : %llu\n"
"time_wo_finds : %llu\n" "fuzz_time : %llu\n"
"fuzz_time : %llu\n" "calibration_time : %llu\n"
"calibration_time : %llu\n" "cmplog_time : %llu\n"
"cmplog_time : %llu\n" "sync_time : %llu\n"
"sync_time : %llu\n" "trim_time : %llu\n"
"trim_time : %llu\n" "execs_done : %llu\n"
"execs_done : %llu\n" "execs_per_sec : %0.02f\n"
"execs_per_sec : %0.02f\n" "execs_ps_last_min : %0.02f\n"
"execs_ps_last_min : %0.02f\n" "corpus_count : %u\n"
"corpus_count : %u\n" "corpus_favored : %u\n"
"corpus_favored : %u\n" "corpus_found : %u\n"
"corpus_found : %u\n" "corpus_imported : %u\n"
"corpus_imported : %u\n" "corpus_variable : %u\n"
"corpus_variable : %u\n" "max_depth : %u\n"
"max_depth : %u\n" "cur_item : %u\n"
"cur_item : %u\n" "pending_favs : %u\n"
"pending_favs : %u\n" "pending_total : %u\n"
"pending_total : %u\n" "stability : %0.02f%%\n"
"stability : %0.02f%%\n" "bitmap_cvg : %0.02f%%\n"
"bitmap_cvg : %0.02f%%\n" "saved_crashes : %llu\n"
"saved_crashes : %llu\n" "saved_hangs : %llu\n"
"saved_hangs : %llu\n" "total_tmout : %llu\n"
"last_find : %llu\n" "last_find : %llu\n"
"last_crash : %llu\n" "last_crash : %llu\n"
"last_hang : %llu\n" "last_hang : %llu\n"
"execs_since_crash : %llu\n" "execs_since_crash : %llu\n"
"exec_timeout : %u\n" "exec_timeout : %u\n"
"slowest_exec_ms : %u\n" "slowest_exec_ms : %u\n"
"peak_rss_mb : %lu\n" "peak_rss_mb : %lu\n"
"cpu_affinity : %d\n" "cpu_affinity : %d\n"
"edges_found : %u\n" "edges_found : %u\n"
"total_edges : %u\n" "total_edges : %u\n"
"var_byte_count : %u\n" "var_byte_count : %u\n"
"havoc_expansion : %u\n" "havoc_expansion : %u\n"
"auto_dict_entries : %u\n" "auto_dict_entries : %u\n"
"testcache_size : %llu\n" "testcache_size : %llu\n"
"testcache_count : %u\n" "testcache_count : %u\n"
"testcache_evict : %u\n" "testcache_evict : %u\n"
"afl_banner : %s\n" "afl_banner : %s\n"
"afl_version : " VERSION "afl_version : " VERSION
"\n" "\n"
"target_mode : %s%s%s%s%s%s%s%s%s%s\n" "target_mode : %s%s%s%s%s%s%s%s%s%s\n"
"command_line : %s\n", "command_line : %s\n",
(afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000, (afl->start_time /*- afl->prev_run_time*/) / 1000, cur_time / 1000,
runtime_ms / 1000, (u32)getpid(), runtime_ms / 1000, (u32)getpid(),
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds, afl->queue_cycle ? (afl->queue_cycle - 1) : 0, afl->cycles_wo_finds,
afl->longest_find_time > cur_time - afl->last_find_time afl->longest_find_time > cur_time - afl->last_find_time
? afl->longest_find_time / 1000 ? afl->longest_find_time / 1000
: ((afl->start_time == 0 || afl->last_find_time == 0) : ((afl->start_time == 0 || afl->last_find_time == 0)
? 0 ? 0
: (cur_time - afl->last_find_time) / 1000), : (cur_time - afl->last_find_time) / 1000),
(runtime_ms - MIN(runtime_ms, overhead_ms)) / 1000, (runtime_ms - MIN(runtime_ms, overhead_ms)) / 1000,
afl->calibration_time_us / 1000000, afl->cmplog_time_us / 1000000, afl->calibration_time_us / 1000000, afl->cmplog_time_us / 1000000,
afl->sync_time_us / 1000000, afl->trim_time_us / 1000000, afl->sync_time_us / 1000000, afl->trim_time_us / 1000000,
afl->fsrv.total_execs, afl->fsrv.total_execs,
afl->fsrv.total_execs / ((double)(runtime_ms) / 1000), afl->fsrv.total_execs / ((double)(runtime_ms) / 1000),
afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored, afl->last_avg_execs_saved, afl->queued_items, afl->queued_favored,
afl->queued_discovered, afl->queued_imported, afl->queued_variable, afl->queued_discovered, afl->queued_imported, afl->queued_variable,
afl->max_depth, afl->current_entry, afl->pending_favored, afl->max_depth, afl->current_entry, afl->pending_favored,
afl->pending_not_fuzzed, stability, bitmap_cvg, afl->saved_crashes, 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_hang_time / 1000, afl->fsrv.total_execs - afl->last_crash_execs, afl->last_crash_time / 1000, afl->last_hang_time / 1000,
afl->fsrv.exec_tmout, afl->slowest_exec_ms, afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout,
afl->slowest_exec_ms,
#ifndef __HAIKU__ #ifndef __HAIKU__
#ifdef __APPLE__ #ifdef __APPLE__
(unsigned long int)(rus.ru_maxrss >> 20), (unsigned long int)(rus.ru_maxrss >> 20),
#else #else
(unsigned long int)(rus.ru_maxrss >> 10), (unsigned long int)(rus.ru_maxrss >> 10),
#endif #endif
#else #else
-1UL, -1UL,
#endif #endif
#ifdef HAVE_AFFINITY #ifdef HAVE_AFFINITY
afl->cpu_aff, afl->cpu_aff,
#else #else
-1, -1,
#endif #endif
t_bytes, afl->fsrv.real_map_size, afl->var_byte_count, afl->expand_havoc, t_bytes, afl->fsrv.real_map_size, afl->var_byte_count,
afl->a_extras_cnt, afl->q_testcase_cache_size, afl->expand_havoc, afl->a_extras_cnt, afl->q_testcase_cache_size,
afl->q_testcase_cache_count, afl->q_testcase_evictions, afl->use_banner, afl->q_testcase_cache_count, afl->q_testcase_evictions,
afl->unicorn_mode ? "unicorn" : "", afl->fsrv.qemu_mode ? "qemu " : "", afl->use_banner, afl->unicorn_mode ? "unicorn" : "",
afl->fsrv.cs_mode ? "coresight" : "", afl->fsrv.qemu_mode ? "qemu " : "",
afl->non_instrumented_mode ? " non_instrumented " : "", afl->fsrv.cs_mode ? "coresight" : "",
afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "", afl->non_instrumented_mode ? " non_instrumented " : "",
afl->persistent_mode ? "persistent " : "", afl->no_forkserver ? "no_fsrv " : "", afl->crash_mode ? "crash " : "",
afl->shmem_testcase_mode ? "shmem_testcase " : "", afl->persistent_mode ? "persistent " : "",
afl->deferred_mode ? "deferred " : "", afl->shmem_testcase_mode ? "shmem_testcase " : "",
(afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.cs_mode || afl->deferred_mode ? "deferred " : "",
afl->non_instrumented_mode || afl->no_forkserver || afl->crash_mode || (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.cs_mode ||
afl->persistent_mode || afl->deferred_mode) afl->non_instrumented_mode || afl->no_forkserver ||
? "" afl->crash_mode || afl->persistent_mode || afl->deferred_mode)
: "default", ? ""
afl->orig_cmdline); : "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 */ /* ignore errors */
@ -565,12 +580,21 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
fprintf(afl->fsrv.plot_file, fprintf(afl->fsrv.plot_file,
"%llu, %llu, %u, %u, %u, %u, %0.02f%%, %llu, %llu, %u, %0.02f, %llu, " "%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->prev_run_time + get_cur_time() - afl->start_time) / 1000),
afl->queue_cycle - 1, afl->current_entry, afl->queued_items, afl->queue_cycle - 1, afl->current_entry, afl->queued_items,
afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg, afl->pending_not_fuzzed, afl->pending_favored, bitmap_cvg,
afl->saved_crashes, afl->saved_hangs, afl->max_depth, eps, 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); fflush(afl->fsrv.plot_file);

View File

@ -25,7 +25,9 @@
*/ */
#include "afl-fuzz.h" #include "afl-fuzz.h"
#include "alloc-inl.h"
#include "cmplog.h" #include "cmplog.h"
#include "asanfuzz.h"
#include "common.h" #include "common.h"
#include <limits.h> #include <limits.h>
#include <stdlib.h> #include <stdlib.h>
@ -252,13 +254,17 @@ static void usage(u8 *argv0, int more_help) {
" X=extreme transform solving, R=random colorization " " X=extreme transform solving, R=random colorization "
"bytes.\n\n" "bytes.\n\n"
"Fuzzing behavior settings:\n" "Fuzzing behavior settings:\n"
" -Z - sequential queue selection instead of weighted " " -Z - sequential queue selection instead of weighted "
"random\n" "random\n"
" -N - do not unlink the fuzzing input file (for devices " " -N - do not unlink the fuzzing input file (for devices "
"etc.)\n" "etc.)\n"
" -n - fuzz without instrumentation (non-instrumented mode)\n" " -n - fuzz without instrumentation (non-instrumented "
" -x dict_file - fuzzer dictionary (see README.md, specify up to 4 " "mode)\n"
"times)\n\n" " -x dict_file - fuzzer dictionary (see README.md, specify up to 4 "
"times)\n"
" -w san_binary - Specify the extra sanitizer instrumented binaries,\n"
" can be specified multiple times.\n"
" Read docs/SAND.md for details.\n\n"
"Test settings:\n" "Test settings:\n"
" -s seed - use a fixed seed for the RNG\n" " -s seed - use a fixed seed for the RNG\n"
@ -549,6 +555,7 @@ int main(int argc, char **argv_orig, char **envp) {
u8 mem_limit_given = 0, exit_1 = 0, debug = 0, u8 mem_limit_given = 0, exit_1 = 0, debug = 0,
extras_dir_cnt = 0 /*, have_p = 0*/; extras_dir_cnt = 0 /*, have_p = 0*/;
char *afl_preload; char *afl_preload;
char *san_abstraction;
char *frida_afl_preload = NULL; char *frida_afl_preload = NULL;
char **use_argv; char **use_argv;
@ -606,9 +613,10 @@ int main(int argc, char **argv_orig, char **envp) {
afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing afl->shmem_testcase_mode = 1; // we always try to perform shmem fuzzing
// still available: HjJkKqruvwz // still available: HjJkKqruvwz
while ((opt = getopt(argc, argv, while (
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:" (opt = getopt(argc, argv,
"T:uUV:WXx:YzZ")) > 0) { "+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) { switch (opt) {
@ -741,6 +749,21 @@ 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': { case 's': {
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); } if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
@ -1727,6 +1750,9 @@ int main(int argc, char **argv_orig, char **envp) {
} }
afl->n_fuzz_dup = ck_alloc(N_FUZZ_SIZE_BITMAP * sizeof(u8));
afl->simplified_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_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_CPU_RED")) { afl->no_cpu_meter_red = 1; }
if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; } if (get_afl_env("AFL_NO_ARITH")) { afl->no_arith = 1; }
@ -2218,6 +2244,14 @@ int main(int argc, char **argv_orig, char **envp) {
} }
setup_cmdline_file(afl, argv + optind); setup_cmdline_file(afl, argv + optind);
// Let's check SAND sanitizers binaries a bit earlier
// so that we won't overwrite target_path.
// Lazymio: why does cmplog fsrv even work?!
for (u8 i = 0; i < afl->san_binary_length; i++) {
check_binary(afl, afl->san_binary[i]);
}
check_binary(afl, argv[optind]); check_binary(afl, argv[optind]);
u64 prev_target_hash = 0; u64 prev_target_hash = 0;
@ -2554,6 +2588,129 @@ int main(int argc, char **argv_orig, char **envp) {
} }
san_abstraction = getenv("AFL_SAN_ABSTRACTION");
if (!san_abstraction || !strcmp(san_abstraction, "simplify_trace")) {
afl->san_abstraction = SIMPLIFY_TRACE;
} else if (!strcmp(san_abstraction, "coverage_increase")) {
afl->san_abstraction = COVERAGE_INCREASE;
} else if (!strcmp(san_abstraction, "unique_trace")) {
afl->san_abstraction = UNIQUE_TRACE;
} else {
WARNF("Unkown abstraction: %s, fallback to unique trace.\n",
san_abstraction);
afl->san_abstraction = SIMPLIFY_TRACE;
}
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 SAND 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("SAND 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) { if (afl->cmplog_binary) {
ACTF("Spawning cmplog forkserver"); ACTF("Spawning cmplog forkserver");
@ -3450,6 +3607,16 @@ stop_fuzzing:
afl_fsrv_deinit(&afl->fsrv); 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]);
}
if (afl->cmplog_binary) {
afl_fsrv_deinit(&afl->cmplog_fsrv);
}
/* remove tmpfile */ /* remove tmpfile */
if (!afl->in_place_resume && afl->fsrv.out_file) { if (!afl->in_place_resume && afl->fsrv.out_file) {

View File

@ -423,5 +423,4 @@ char *sha1_hex_for_file(const char *fname, u32 len) {
ck_free(tmp); ck_free(tmp);
return hex; return hex;
} }