mirror of
https://github.com/AFLplusplus/AFLplusplus.git
synced 2025-06-24 06:42:42 +00:00
Compare commits
34 Commits
v4.20c
...
unusual_va
Author | SHA1 | Date | |
---|---|---|---|
1ce165147f | |||
f92ab77ab4 | |||
67be563672 | |||
3927f81e1d | |||
fa23e52459 | |||
b053ecd176 | |||
9b28c1dc36 | |||
b9189db55b | |||
f6ccdf13e0 | |||
b382566227 | |||
fd0311572e | |||
04a4e1b0b7 | |||
b17d03b8b0 | |||
5830ec4718 | |||
7b9fc8c6d3 | |||
4444b457d9 | |||
e76c563178 | |||
0b0d928374 | |||
9425acf073 | |||
fa84e71be2 | |||
46f95c8db9 | |||
6d1b0d9812 | |||
bede2597de | |||
c8f1366e3f | |||
703b545211 | |||
803bfabd2b | |||
4c583a2450 | |||
48bca6e51c | |||
afc2abd5d6 | |||
754c9d8b53 | |||
bfaf6ed790 | |||
a9ca2136ca | |||
a321d4102b | |||
db43ec9000 |
@ -305,8 +305,8 @@ ifeq "$(TEST_MMAP)" "1"
|
||||
LDFLAGS += -Wno-deprecated-declarations
|
||||
endif
|
||||
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so
|
||||
PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
|
||||
PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./afl-unusual-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./afl-llvm-lto-instrumentation.so ./SanitizerCoverageLTO.so ./afl-unusual-pass.so ./afl-unusual-rt.o ./afl-unusual-rt-32.o ./afl-unusual-rt-64.o
|
||||
|
||||
# If prerequisites are not given, warn, do not build anything, and exit with code 0
|
||||
ifeq "$(LLVMVER)" ""
|
||||
@ -433,6 +433,9 @@ endif
|
||||
./cmplog-instructions-pass.so: instrumentation/cmplog-instructions-pass.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
afl-unusual-pass.so: instrumentation/afl-unusual-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $^ -o $@ $(CLANG_LFL)
|
||||
|
||||
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
|
||||
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o
|
||||
|
||||
@ -453,6 +456,18 @@ document:
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-compiler-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-unusual-rt.o: instrumentation/afl-unusual-rt.o.c
|
||||
$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -fno-math-errno -ffast-math -O3 -Wno-unused-result -fPIC -c $< -o $@
|
||||
|
||||
./afl-unusual-rt-32.o: instrumentation/afl-unusual-rt.o.c
|
||||
@printf "[*] Building 32-bit variant of the runtime (-m32)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -fno-math-errno -ffast-math -O3 -Wno-unused-result -m32 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-unusual-rt-32.o afl-llvm-rt-32.o; else echo "failed (that's fine)"; fi
|
||||
|
||||
./afl-unusual-rt-64.o: instrumentation/afl-unusual-rt.o.c
|
||||
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
|
||||
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -fno-math-errno -ffast-math -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; ln -sf afl-unusual-rt-64.o afl-llvm-rt-64.o; else echo "failed (that's fine)"; fi
|
||||
|
||||
|
||||
.PHONY: test_build
|
||||
test_build: $(PROGS)
|
||||
@echo "[*] Testing the CC wrapper and instrumentation output..."
|
||||
@ -475,10 +490,13 @@ install: all
|
||||
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
|
||||
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
|
||||
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o ;fi
|
||||
@if [ -f ./afl-unusual-rt.o ]; then set -e; install -m 755 ./afl-unusual-rt.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-unusual-rt.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt.o ;fi
|
||||
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-lto-instrumentation.so ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
|
||||
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o ;fi
|
||||
@if [ -f ./afl-compiler-rt-64.o ]; then set -e; install -m 755 ./afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-compiler-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o ; fi
|
||||
@if [ -f ./afl-unusual-rt-32.o ]; then set -e; install -m 755 ./afl-unusual-rt-32.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-unusual-rt-32.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-32.o ;fi
|
||||
@if [ -f ./afl-unusual-rt-64.o ]; then set -e; install -m 755 ./afl-unusual-rt-64.o $${DESTDIR}$(HELPER_PATH); ln -sf afl-unusual-rt-64.o $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt-64.o ; fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; install -m 755 ./*.so $${DESTDIR}$(HELPER_PATH); fi
|
||||
@if [ -f ./compare-transform-pass.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-fast ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-fast++ ; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang++ ; fi
|
||||
@if [ -f ./SanitizerCoverageLTO.so ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto ; ln -sf ./afl-c++ $${DESTDIR}$(BIN_PATH)/afl-clang-lto++ ; fi
|
||||
|
Submodule custom_mutators/grammar_mutator/grammar_mutator updated: b79d51a8da...b3c4fcfa6a
@ -166,7 +166,8 @@ struct queue_entry {
|
||||
favored, /* Currently favored? */
|
||||
fs_redundant, /* Marked as redundant in the fs? */
|
||||
is_ascii, /* Is the input just ascii text? */
|
||||
disabled; /* Is disabled from fuzz selection */
|
||||
disabled, /* Is disabled from fuzz selection */
|
||||
has_unusual; /* Triggers an unusual value */
|
||||
|
||||
u32 bitmap_size, /* Number of bits set in bitmap */
|
||||
fuzz_level, /* Number of fuzzing iterations */
|
||||
@ -629,6 +630,9 @@ typedef struct afl_state {
|
||||
struct queue_entry **queue_buf;
|
||||
|
||||
struct queue_entry **top_rated; /* Top entries for bitmap bytes */
|
||||
struct queue_entry **top_rated_unusual; /* Top entries for unusual */
|
||||
|
||||
u8 *unusual_item_changed;
|
||||
|
||||
struct extra_data *extras; /* Extra tokens to fuzz with */
|
||||
u32 extras_cnt; /* Total number of tokens read */
|
||||
@ -644,6 +648,11 @@ typedef struct afl_state {
|
||||
char * cmplog_binary;
|
||||
afl_forkserver_t cmplog_fsrv; /* cmplog has its own little forkserver */
|
||||
|
||||
/* Unusual */
|
||||
|
||||
char * unusual_binary;
|
||||
afl_forkserver_t unusual_fsrv; /* unusual has its own little forkserver */
|
||||
|
||||
/* Custom mutators */
|
||||
struct custom_mutator *mutator;
|
||||
|
||||
@ -1056,7 +1065,7 @@ void minimize_bits(afl_state_t *, u8 *, u8 *);
|
||||
#ifndef SIMPLE_FILES
|
||||
u8 *describe_op(afl_state_t *, u8, size_t);
|
||||
#endif
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8);
|
||||
u8 save_if_interesting(afl_state_t *, void *, u32, u8, u8);
|
||||
u8 has_new_bits(afl_state_t *, u8 *);
|
||||
u8 has_new_bits_unclassified(afl_state_t *, u8 *);
|
||||
|
||||
@ -1081,6 +1090,13 @@ void maybe_update_plot_file(afl_state_t *, u32, double, double);
|
||||
void show_stats(afl_state_t *);
|
||||
void show_init_stats(afl_state_t *);
|
||||
|
||||
static inline u64 total_execs_all(afl_state_t *afl) {
|
||||
|
||||
return afl->fsrv.total_execs +
|
||||
/*afl->cmplog_fsrv.total_execs +*/ afl->unusual_fsrv.total_execs;
|
||||
|
||||
}
|
||||
|
||||
/* StatsD */
|
||||
|
||||
void statsd_setup_format(afl_state_t *afl);
|
||||
@ -1141,6 +1157,10 @@ void write_crash_readme(afl_state_t *afl);
|
||||
|
||||
u8 common_fuzz_cmplog_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
|
||||
|
||||
/* Unusual */
|
||||
|
||||
u8 common_fuzz_unusual_stuff(afl_state_t *afl, u8 *out_buf, u32 len);
|
||||
|
||||
/* RedQueen */
|
||||
u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len);
|
||||
|
||||
|
@ -462,6 +462,8 @@
|
||||
|
||||
#define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID"
|
||||
|
||||
#define UNUSUAL_SHM_ENV_VAR "__AFL_UNUSUAL_SHM_ID"
|
||||
|
||||
/* CPU Affinity lockfile env var */
|
||||
|
||||
#define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE"
|
||||
|
@ -204,6 +204,11 @@ static char *afl_environment_variables[] = {
|
||||
"AFL_USE_FASAN",
|
||||
"AFL_USE_QASAN",
|
||||
"AFL_PRINT_FILENAMES",
|
||||
"AFL_UNUSUAL_VALUES",
|
||||
"AFL_LLVM_UNUSUAL_VALUES",
|
||||
"AFL_NO_SINGLE_UNUSUAL_VALUES",
|
||||
"AFL_SKIP_START_LEARNING",
|
||||
"AFL_LLVM_RAND_SEED",
|
||||
NULL
|
||||
|
||||
};
|
||||
|
@ -97,6 +97,7 @@ typedef struct afl_forkserver {
|
||||
u8 *shmem_fuzz; /* allocated memory for fuzzing */
|
||||
|
||||
char *cmplog_binary; /* the name of the cmplog binary */
|
||||
char *unusual_binary; /* the name of the unusual binary */
|
||||
|
||||
/* persistent mode replay functionality */
|
||||
u32 persistent_record; /* persistent replay setting */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#define __AFL_SHAREDMEM_H
|
||||
|
||||
#include "types.h"
|
||||
#include "unusual.h"
|
||||
|
||||
typedef struct sharedmem {
|
||||
|
||||
@ -44,13 +45,15 @@ typedef struct sharedmem {
|
||||
#else
|
||||
s32 shm_id; /* ID of the SHM region */
|
||||
s32 cmplog_shm_id;
|
||||
s32 unusual_shm_id;
|
||||
#endif
|
||||
|
||||
u8 *map; /* shared memory region */
|
||||
u8 * map; /* shared memory region */
|
||||
struct unusual_values_state *unusual;
|
||||
|
||||
size_t map_size; /* actual allocated size */
|
||||
|
||||
int cmplog_mode;
|
||||
int cmplog_mode, unusual_mode;
|
||||
int shmemfuzz_mode;
|
||||
struct cmp_map *cmp_map;
|
||||
|
||||
|
105
include/unusual.h
Normal file
105
include/unusual.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
american fuzzy lop++ - unusual values header
|
||||
--------------------------------------------
|
||||
|
||||
Written by Andrea Fioraldi <andreafioraldi@gmail.com>
|
||||
|
||||
Copyright 2021 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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _AFL_UNUSUAL_H
|
||||
#define _AFL_UNUSUAL_H
|
||||
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include <string.h>
|
||||
|
||||
#define UNUSUAL_MAP_SIZE 65536
|
||||
|
||||
#define INV_ONEOF_MAX_NUM_VALS 8
|
||||
#define INV_EXECS_MIN_BOUND 32
|
||||
|
||||
enum {
|
||||
|
||||
INV_NONE = 0,
|
||||
INV_LT,
|
||||
INV_LE,
|
||||
INV_GT,
|
||||
INV_GE,
|
||||
INV_EQ,
|
||||
INV_NE,
|
||||
INV_ONEOF,
|
||||
INV_ALL,
|
||||
|
||||
// ptr invariants (reuse INV_EQ)
|
||||
INV_GE_PAGE, // greater equal than PAGE_SIZE
|
||||
INV_LT_PAGE, // greater than PAGE_SIZE
|
||||
INV_HEAP, // future use, maybe with sbrk(0)
|
||||
INV_STACK, // check if below __builtin_frame_address(0)
|
||||
|
||||
};
|
||||
|
||||
struct single_var_invariant {
|
||||
|
||||
u64 vals[INV_ONEOF_MAX_NUM_VALS];
|
||||
u8 num_vals;
|
||||
u8 execs;
|
||||
u8 invariant;
|
||||
|
||||
};
|
||||
|
||||
struct single_ptr_invariant {
|
||||
|
||||
u8 execs;
|
||||
u8 invariant;
|
||||
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) pair_vars_invariant {
|
||||
|
||||
u8 invariant;
|
||||
u8 execs;
|
||||
|
||||
};
|
||||
|
||||
struct unusual_values_state {
|
||||
|
||||
u8 map[UNUSUAL_MAP_SIZE / 8];
|
||||
u8 virgin[UNUSUAL_MAP_SIZE / 8];
|
||||
u8 crash[UNUSUAL_MAP_SIZE / 8];
|
||||
|
||||
struct single_var_invariant single_invariants[UNUSUAL_MAP_SIZE];
|
||||
struct pair_vars_invariant pair_invariants[UNUSUAL_MAP_SIZE];
|
||||
|
||||
u8 learning;
|
||||
|
||||
};
|
||||
|
||||
static inline void unusual_values_state_init(struct unusual_values_state *state) {
|
||||
|
||||
// memset(state->map, 0, UNUSUAL_MAP_SIZE / 8);
|
||||
memset(state->virgin, 0xff, UNUSUAL_MAP_SIZE / 8);
|
||||
memset(state->crash, 0xff, UNUSUAL_MAP_SIZE / 8);
|
||||
// state->learning = 1;
|
||||
|
||||
}
|
||||
|
||||
static inline void unusual_values_state_reset(struct unusual_values_state *state) {
|
||||
|
||||
memset(state->map, 0, UNUSUAL_MAP_SIZE / 8);
|
||||
|
||||
}
|
||||
|
||||
/* Execs the child */
|
||||
|
||||
struct afl_forkserver;
|
||||
void unusual_exec_child(struct afl_forkserver *fsrv, char **argv);
|
||||
|
||||
#endif
|
3822
instrumentation/RangeAnalysis.cpp
Normal file
3822
instrumentation/RangeAnalysis.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1489
instrumentation/RangeAnalysis.h
Normal file
1489
instrumentation/RangeAnalysis.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "types.h"
|
||||
#include "cmplog.h"
|
||||
#include "unusual.h"
|
||||
#include "llvm-alternative-coverage.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -32,6 +33,7 @@
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#ifndef __HAIKU__
|
||||
@ -83,15 +85,15 @@ extern ssize_t _kern_write(int fd, off_t pos, const void *buffer,
|
||||
size_t bufferSize);
|
||||
#endif // HAIKU
|
||||
|
||||
static u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
||||
static u8 * __afl_area_ptr_dummy = __afl_area_initial;
|
||||
static u8 * __afl_area_ptr_backup = __afl_area_initial;
|
||||
static u8 __afl_area_initial[MAP_INITIAL_SIZE];
|
||||
static u8 *__afl_area_ptr_dummy = __afl_area_initial;
|
||||
static u8 *__afl_area_ptr_backup = __afl_area_initial;
|
||||
|
||||
u8 * __afl_area_ptr = __afl_area_initial;
|
||||
u8 * __afl_dictionary;
|
||||
u8 * __afl_fuzz_ptr;
|
||||
static u32 __afl_fuzz_len_dummy;
|
||||
u32 *__afl_fuzz_len = &__afl_fuzz_len_dummy;
|
||||
u8 * __afl_area_ptr = __afl_area_initial;
|
||||
u8 * __afl_dictionary;
|
||||
u8 * __afl_fuzz_ptr;
|
||||
static u32 __afl_fuzz_len_dummy;
|
||||
u32 * __afl_fuzz_len = &__afl_fuzz_len_dummy;
|
||||
|
||||
u32 __afl_final_loc;
|
||||
u32 __afl_map_size = MAP_SIZE;
|
||||
@ -99,8 +101,8 @@ u32 __afl_dictionary_len;
|
||||
u64 __afl_map_addr;
|
||||
|
||||
// for the __AFL_COVERAGE_ON/__AFL_COVERAGE_OFF features to work:
|
||||
int __afl_selective_coverage __attribute__((weak));
|
||||
int __afl_selective_coverage_start_off __attribute__((weak));
|
||||
int __afl_selective_coverage __attribute__((weak));
|
||||
int __afl_selective_coverage_start_off __attribute__((weak));
|
||||
static int __afl_selective_coverage_temp = 1;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__HAIKU__)
|
||||
@ -118,6 +120,8 @@ int __afl_sharedmem_fuzzing __attribute__((weak));
|
||||
struct cmp_map *__afl_cmp_map;
|
||||
struct cmp_map *__afl_cmp_map_backup;
|
||||
|
||||
struct unusual_values_state *__afl_unusual __attribute__((weak));
|
||||
|
||||
/* Child pid? */
|
||||
|
||||
static s32 child_pid;
|
||||
@ -576,6 +580,26 @@ static void __afl_map_shm(void) {
|
||||
|
||||
}
|
||||
|
||||
id_str = getenv(UNUSUAL_SHM_ENV_VAR);
|
||||
|
||||
if (id_str) {
|
||||
|
||||
u32 shm_id = atoi(id_str);
|
||||
|
||||
// TODO set this for mmap too
|
||||
|
||||
__afl_unusual = (struct unusual_values_state *)shmat(shm_id, NULL, 0);
|
||||
|
||||
if (!__afl_unusual || __afl_unusual == (void *)-1) {
|
||||
|
||||
perror("shmat for unusual");
|
||||
send_forkserver_error(FS_ERROR_SHM_OPEN);
|
||||
_exit(1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* unmap SHM. */
|
||||
@ -1015,6 +1039,7 @@ static void __afl_start_forkserver(void) {
|
||||
|
||||
close(FORKSRV_FD);
|
||||
close(FORKSRV_FD + 1);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
@ -133,9 +133,20 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
u32 rand_seed;
|
||||
unsigned int cur_loc = 0;
|
||||
|
||||
/* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
|
||||
gettimeofday(&tv, &tz);
|
||||
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
|
||||
if (getenv("AFL_LLVM_RAND_SEED")) {
|
||||
|
||||
std::fstream seed_file(getenv("AFL_LLVM_RAND_SEED"), std::ios_base::in);
|
||||
seed_file >> rand_seed;
|
||||
seed_file.close();
|
||||
|
||||
} else {
|
||||
|
||||
/* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
|
||||
gettimeofday(&tv, &tz);
|
||||
rand_seed = tv.tv_sec ^ tv.tv_usec ^ getpid();
|
||||
|
||||
}
|
||||
|
||||
AFL_SR(rand_seed);
|
||||
|
||||
/* Show a banner */
|
||||
@ -676,7 +687,7 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
todo.push_back(MapPtrIdx);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
*/
|
||||
IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
@ -947,6 +958,15 @@ bool AFLCoverage::runOnModule(Module &M) {
|
||||
|
||||
*/
|
||||
|
||||
if (getenv("AFL_LLVM_RAND_SEED")) {
|
||||
|
||||
std::fstream seed_file(getenv("AFL_LLVM_RAND_SEED"),
|
||||
std::ios_base::out | std::ios::trunc);
|
||||
seed_file << AFL_R((u32)-1);
|
||||
seed_file.close();
|
||||
|
||||
}
|
||||
|
||||
/* Say something nice. */
|
||||
|
||||
if (!be_quiet) {
|
||||
|
720
instrumentation/afl-unusual-pass.so.cc
Normal file
720
instrumentation/afl-unusual-pass.so.cc
Normal file
@ -0,0 +1,720 @@
|
||||
#define AFL_LLVM_PASS
|
||||
|
||||
#include "config.h"
|
||||
#include "debug.h"
|
||||
#include "unusual.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 5
|
||||
typedef long double max_align_t;
|
||||
#endif
|
||||
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Transforms/IPO/PassManagerBuilder.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
|
||||
|
||||
#include "afl-llvm-common.h"
|
||||
//#include "RangeAnalysis.h"
|
||||
|
||||
using namespace llvm;
|
||||
//using namespace RangeAnalysis;
|
||||
|
||||
/*
|
||||
static size_t TypeSizeToSizeIndex(uint32_t TypeSize) {
|
||||
|
||||
if (TypeSize == 1) TypeSize = 8;
|
||||
size_t Res = countTrailingZeros(TypeSize / 8);
|
||||
return Res;
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
struct AFLUnusual {
|
||||
|
||||
AFLUnusual(Module &_M, Function &_F, DominatorTree &_DT)
|
||||
//IntraProceduralRA<Cousot> &_RA)
|
||||
: M(_M), F(_F), DT(_DT) {
|
||||
|
||||
initialize();
|
||||
|
||||
}
|
||||
|
||||
static bool isBlacklisted(const Function *F) {
|
||||
|
||||
static const char *Blacklist[] = {
|
||||
|
||||
"asan.", "llvm.", "sancov.", "__ubsan_handle_", "ign.", "__afl_",
|
||||
"_fini", "__libc_csu", "__asan", "__msan", "msan."
|
||||
|
||||
};
|
||||
|
||||
for (auto const &BlacklistFunc : Blacklist) {
|
||||
|
||||
if (F->getName().startswith(BlacklistFunc)) return true;
|
||||
|
||||
}
|
||||
|
||||
// if (F->getName() == "main") return true;
|
||||
if (F->getName() == "_start") return true;
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void initialize();
|
||||
bool instrumentFunction();
|
||||
|
||||
Type *VoidTy, *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty, *FloatTy, *DoubleTy,
|
||||
*StructTy, *Int8PTy, *Int16PTy, *Int32PTy, *Int64PTy, *FloatPTy,
|
||||
*DoublePTy, *StructPTy, *FuncTy;
|
||||
Type *IntTypeSized[4];
|
||||
|
||||
Function *dbgDeclareFn;
|
||||
|
||||
FunctionCallee unusualValuesFns[6];
|
||||
FunctionCallee unusualValuesPtrFn;
|
||||
FunctionCallee unusualValuesLogFn;
|
||||
|
||||
bool noSingle = false;
|
||||
bool noPtrs = false;
|
||||
|
||||
LLVMContext *C;
|
||||
Module & M;
|
||||
Function & F;
|
||||
|
||||
DominatorTree & DT;
|
||||
//IntraProceduralRA<Cousot> &RA;
|
||||
|
||||
int LongSize;
|
||||
|
||||
std::map<Value *, int> Comp;
|
||||
int CompID = 0;
|
||||
|
||||
std::vector<DILocalVariable *> DbgVars;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void AFLUnusual::initialize() {
|
||||
|
||||
C = &(M.getContext());
|
||||
|
||||
LongSize = M.getDataLayout().getPointerSizeInBits();
|
||||
|
||||
VoidTy = Type::getVoidTy(*C);
|
||||
|
||||
Int8Ty = IntegerType::get(*C, 8);
|
||||
Int16Ty = IntegerType::get(*C, 16);
|
||||
Int32Ty = IntegerType::get(*C, 32);
|
||||
Int64Ty = IntegerType::get(*C, 64);
|
||||
|
||||
FloatTy = Type::getFloatTy(*C);
|
||||
DoubleTy = Type::getDoubleTy(*C);
|
||||
|
||||
StructTy = StructType::create(*C);
|
||||
|
||||
Int8PTy = PointerType::get(Int8Ty, 0);
|
||||
Int16PTy = PointerType::get(Int16Ty, 0);
|
||||
Int32PTy = PointerType::get(Int32Ty, 0);
|
||||
Int64PTy = PointerType::get(Int64Ty, 0);
|
||||
|
||||
FloatPTy = PointerType::get(FloatTy, 0);
|
||||
DoublePTy = PointerType::get(DoubleTy, 0);
|
||||
|
||||
StructPTy = PointerType::get(StructTy, 0);
|
||||
|
||||
FuncTy = FunctionType::get(VoidTy, true);
|
||||
|
||||
dbgDeclareFn = M.getFunction("llvm.dbg.declare");
|
||||
|
||||
IntTypeSized[0] = Int8Ty;
|
||||
IntTypeSized[1] = Int16Ty;
|
||||
IntTypeSized[2] = Int32Ty;
|
||||
IntTypeSized[3] = Int64Ty;
|
||||
|
||||
unusualValuesFns[0] = M.getOrInsertFunction("__afl_unusual_values_1", Int32Ty,
|
||||
Int32Ty, Int64Ty, Int8Ty);
|
||||
unusualValuesFns[1] = M.getOrInsertFunction("__afl_unusual_values_2", Int32Ty,
|
||||
Int32Ty, Int64Ty, Int64Ty);
|
||||
unusualValuesFns[2] = M.getOrInsertFunction(
|
||||
"__afl_unusual_values_3", Int32Ty, Int32Ty, Int64Ty, Int64Ty, Int64Ty);
|
||||
|
||||
unusualValuesPtrFn = M.getOrInsertFunction("__afl_unusual_values_ptr", Int32Ty, Int32Ty, Int8PTy, Int8Ty);
|
||||
|
||||
unusualValuesLogFn =
|
||||
M.getOrInsertFunction("__afl_unusual_values_log", VoidTy, Int32Ty);
|
||||
|
||||
/* Show a banner */
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
if (getenv("AFL_DEBUG")) debug = 1;
|
||||
|
||||
if ((isatty(2) && !getenv("AFL_QUIET")) || getenv("AFL_DEBUG") != NULL) {
|
||||
|
||||
SAYF(cCYA "afl-unusual-pass" VERSION cRST
|
||||
" by <andreafioraldi@gmail.com>\n");
|
||||
|
||||
} else
|
||||
|
||||
be_quiet = 1;
|
||||
|
||||
noSingle = !!getenv("AFL_NO_SINGLE_UNUSUAL_VALUES");
|
||||
noPtrs = !!getenv("AFL_NO_PTR_UNUSUAL_VALUES");
|
||||
|
||||
}
|
||||
|
||||
static void AddComp(std::map<Value *, int> &Comp, int &CompID, Value *A) {
|
||||
|
||||
bool hasA = Comp.find(A) != Comp.end();
|
||||
|
||||
if (!hasA) {
|
||||
|
||||
Comp[A] = CompID;
|
||||
++CompID;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void MergeComp(std::map<Value *, int> &Comp, int &CompID, Value *A,
|
||||
Value *B) {
|
||||
|
||||
bool hasA = Comp.find(A) != Comp.end();
|
||||
bool hasB = Comp.find(B) != Comp.end();
|
||||
|
||||
if (hasA && !hasB)
|
||||
Comp[B] = Comp[A];
|
||||
else if (!hasA && hasB)
|
||||
Comp[A] = Comp[B];
|
||||
else if (!hasA && !hasB) {
|
||||
|
||||
Comp[A] = CompID;
|
||||
Comp[B] = CompID;
|
||||
++CompID;
|
||||
|
||||
} else {
|
||||
|
||||
int AID = Comp[A];
|
||||
int BID = Comp[B];
|
||||
for (auto &K : Comp) {
|
||||
|
||||
if (K.second == BID) K.second = AID;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool IsAlloca(Value* V) {
|
||||
|
||||
// we assume it is a ptr instruction
|
||||
if (isa<AllocaInst>(V)) return true;
|
||||
if (auto C = dyn_cast<CastInst>(V)) {
|
||||
return IsAlloca(C->getOperand(0));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool AFLUnusual::instrumentFunction() {
|
||||
|
||||
bool FunctionModified = false;
|
||||
|
||||
if (isBlacklisted(&F)) return FunctionModified; // not supported
|
||||
|
||||
struct timeval tv;
|
||||
struct timezone tz;
|
||||
/* Setup random() so we get Actually Random(TM) outputs from AFL_R() */
|
||||
gettimeofday(&tv, &tz);
|
||||
AFL_SR(tv.tv_sec ^ tv.tv_usec ^ getpid());
|
||||
|
||||
std::set<Value *> LocVals;
|
||||
std::vector<BasicBlock *> Blocks;
|
||||
|
||||
unsigned Calls1 = 0, Calls2 = 0;
|
||||
unsigned Key = 0;
|
||||
|
||||
for (Function::arg_iterator it = F.arg_begin(); it != F.arg_end(); ++it) {
|
||||
|
||||
Argument *A = &*it;
|
||||
Value * V = static_cast<Value *>(A);
|
||||
|
||||
if (LocVals.find(V) == LocVals.end()) LocVals.insert(V);
|
||||
AddComp(Comp, CompID, V);
|
||||
|
||||
}
|
||||
|
||||
std::function<void(BasicBlock *)> VisitBlock = [&](BasicBlock *BB) {
|
||||
|
||||
Blocks.push_back(BB);
|
||||
SmallVector<BasicBlock *, 3> Doms;
|
||||
DT.getDescendants(BB, Doms);
|
||||
for (auto DBB : Doms) {
|
||||
|
||||
if (std::find(Blocks.begin(), Blocks.end(), DBB) == Blocks.end())
|
||||
VisitBlock(DBB);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
VisitBlock(&F.getEntryBlock());
|
||||
|
||||
for (auto BB : Blocks) {
|
||||
|
||||
for (auto &I : *BB) {
|
||||
|
||||
if (auto *L = dyn_cast<LoadInst>(&I)) {
|
||||
|
||||
AddComp(Comp, CompID, L);
|
||||
AddComp(Comp, CompID, L->getPointerOperand());
|
||||
|
||||
} else if (auto ST = dyn_cast<StoreInst>(&I)) {
|
||||
|
||||
AddComp(Comp, CompID, ST->getPointerOperand());
|
||||
AddComp(Comp, CompID, ST->getValueOperand());
|
||||
|
||||
} else if (auto *DbgValue = dyn_cast<DbgValueInst>(&I)) {
|
||||
|
||||
Value *V = DbgValue->getValue();
|
||||
if (V && !isa<Constant>(V)) {
|
||||
|
||||
if (LocVals.find(V) == LocVals.end()) LocVals.insert(V);
|
||||
AddComp(Comp, CompID, V);
|
||||
|
||||
}
|
||||
|
||||
} else if (auto *RI = dyn_cast<ReturnInst>(&I)) {
|
||||
|
||||
Value *V = RI->getReturnValue();
|
||||
if (V && !isa<Constant>(V)) {
|
||||
|
||||
if (LocVals.find(V) == LocVals.end()) LocVals.insert(V);
|
||||
AddComp(Comp, CompID, V);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (auto BB : Blocks) {
|
||||
|
||||
for (auto &I : *BB) {
|
||||
|
||||
if (UnaryOperator *O = dyn_cast<UnaryOperator>(&I)) {
|
||||
|
||||
MergeComp(Comp, CompID, O, O->getOperand(0));
|
||||
|
||||
} else if (BinaryOperator *O = dyn_cast<BinaryOperator>(&I)) {
|
||||
|
||||
MergeComp(Comp, CompID, O->getOperand(0), O->getOperand(1));
|
||||
MergeComp(Comp, CompID, O, O->getOperand(1));
|
||||
|
||||
} else if (CastInst *C = dyn_cast<CastInst>(&I)) {
|
||||
|
||||
MergeComp(Comp, CompID, C, C->getOperand(0));
|
||||
|
||||
} else if (GetElementPtrInst *G = dyn_cast<GetElementPtrInst>(&I)) {
|
||||
|
||||
MergeComp(Comp, CompID, G, G->getPointerOperand());
|
||||
Value *First = nullptr;
|
||||
for (auto Idx = G->idx_begin(); Idx != G->idx_end(); ++Idx) {
|
||||
|
||||
if (Idx->get() && !isa<ConstantInt>(Idx->get())) {
|
||||
|
||||
if (First)
|
||||
MergeComp(Comp, CompID, First, Idx->get());
|
||||
else
|
||||
First = Idx->get();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::set<Value *> Dumpeds1;
|
||||
std::set<std::pair<Value *, Value *>> Dumpeds2;
|
||||
|
||||
for (auto &BB : Blocks) {
|
||||
|
||||
std::map<int, std::set<Value *>> CompArgs;
|
||||
|
||||
std::set<Value *> Rets;
|
||||
Value* Hash = nullptr;
|
||||
|
||||
IRBuilder<> IRB(BB->getTerminator());
|
||||
|
||||
auto GroupVar = [&](Value *V) {
|
||||
|
||||
Type *T = V->getType();
|
||||
int CompID = -1;
|
||||
if (Comp.find(V) != Comp.end()) CompID = Comp[V];
|
||||
|
||||
if (T->getTypeID() == Type::IntegerTyID) {
|
||||
|
||||
TypeSize BitsNum = T->getPrimitiveSizeInBits();
|
||||
if (BitsNum <= 64) {
|
||||
|
||||
// Value *I = IRB.CreateSExtOrBitCast(V, Int64Ty);
|
||||
// CompArgs[CompID].insert(I);
|
||||
CompArgs[CompID].insert(V);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
} else if (!noPtrs && T->getTypeID() == Type::PointerTyID) {
|
||||
|
||||
//if (!AA.pointsToConstantMemory(V)) {
|
||||
|
||||
// TODO get pointer values but avoid to emit checks that compare
|
||||
// pointers to integers
|
||||
// to check single invariants on pointers emit a different check
|
||||
// routine that see if it is NULL or a stack or heap ptr
|
||||
|
||||
CompArgs[CompID].insert(V);
|
||||
return true;
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
for (auto &I : *BB) {
|
||||
|
||||
if (I.getMetadata(M.getMDKindID("nosanitize"))) continue;
|
||||
|
||||
if (isa<PHINode>(&I)) continue;
|
||||
|
||||
for (auto op = I.op_begin(); op != I.op_end(); ++op) {
|
||||
|
||||
Value *V = op->get();
|
||||
if (LocVals.find(V) != LocVals.end()) GroupVar(V);
|
||||
|
||||
}
|
||||
|
||||
// ATM remove GEP as interesting instruction
|
||||
/* if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
|
||||
|
||||
if (!isa<PointerType>(GEP->getSourceElementType())) continue;
|
||||
if (!GEP->hasIndices()) continue;
|
||||
|
||||
GroupVar(GEP->getPointerOperand());
|
||||
|
||||
for (auto Idx = GEP->idx_begin(); Idx != GEP->idx_end(); ++Idx) {
|
||||
|
||||
if (Idx->get() && !isa<ConstantInt>(Idx->get())) GroupVar(Idx->get());
|
||||
|
||||
}
|
||||
|
||||
} else */
|
||||
|
||||
if (auto LD = dyn_cast<LoadInst>(&I)) {
|
||||
|
||||
GroupVar(LD->getPointerOperand());
|
||||
GroupVar(LD);
|
||||
|
||||
} else if (auto ST = dyn_cast<StoreInst>(&I)) {
|
||||
|
||||
GroupVar(ST->getPointerOperand());
|
||||
GroupVar(ST->getValueOperand());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int SingleCnt = 0;
|
||||
|
||||
for (auto P : CompArgs) {
|
||||
|
||||
// if (P.first == -1) continue;
|
||||
|
||||
// if (P.second.size() <= 1) continue;
|
||||
|
||||
for (auto X : P.second) {
|
||||
|
||||
Value *XB = nullptr;
|
||||
|
||||
if (isa<Constant>(X)) {
|
||||
|
||||
// errs() << "COSNT VAL " << *X << "\n";
|
||||
Dumpeds1.insert(X);
|
||||
|
||||
}
|
||||
|
||||
if (X->getType()->getTypeID() == Type::PointerTyID && IsAlloca(X)) {
|
||||
|
||||
Dumpeds1.insert(X);
|
||||
|
||||
}
|
||||
|
||||
/*if (LoadInst *L = dyn_cast<LoadInst>(X)) {
|
||||
|
||||
// Skip load from constant mem
|
||||
if (AA.pointsToConstantMemory(L->getPointerOperand())) {
|
||||
|
||||
// errs() << "COSNT MEM " << *L << "\n";
|
||||
Dumpeds1.insert(X);
|
||||
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
if (!noSingle && Dumpeds1.find(X) == Dumpeds1.end()) {
|
||||
|
||||
//Range Rng = RA.getRange(X);
|
||||
|
||||
bool MustCheck = false;
|
||||
u8 always_true = INV_ALL;
|
||||
u8 always_ptr_true = INV_ALL;
|
||||
|
||||
MustCheck = true;
|
||||
|
||||
/*if (!Rng.isUnknown() && !Rng.isEmpty()) {
|
||||
|
||||
bool HasMin = Rng.getLower().getActiveBits() <= 64;
|
||||
bool HasMax = Rng.getUpper().getActiveBits() <= 64;
|
||||
|
||||
if (HasMin && HasMax) {
|
||||
|
||||
int64_t A = (int64_t)Rng.getLower().getSExtValue();
|
||||
int64_t B = (int64_t)Rng.getUpper().getSExtValue();
|
||||
|
||||
// errs() << "Range " << A << " - " << B << "\n";
|
||||
|
||||
if (A > 0 && B > 0) always_true = INV_GT;
|
||||
if (A >= 0 && B > 0) always_true = INV_GE;
|
||||
if (A < 0 && B < 0) always_true = INV_LT;
|
||||
if (A < 0 && B <= 0) always_true = INV_LE;
|
||||
|
||||
if ((uint64_t)A >= 4096) always_ptr_true = INV_GE_PAGE;
|
||||
|
||||
// if (!((A > 0 && B > 0) || (A < 0 && B < 0) || (A == B))) {
|
||||
|
||||
if (A != B) { MustCheck = true; } // else
|
||||
|
||||
// errs() << "SKIP " << A << " - " << B << "\n";
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
MustCheck = true;
|
||||
|
||||
}*/
|
||||
|
||||
if (MustCheck) {
|
||||
|
||||
CallInst *CI;
|
||||
Key = AFL_R(UNUSUAL_MAP_SIZE);
|
||||
|
||||
if (X->getType()->getTypeID() == Type::IntegerTyID) {
|
||||
|
||||
XB = IRB.CreateSExtOrBitCast(X, Int64Ty);
|
||||
//XB->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
|
||||
CI = IRB.CreateCall(
|
||||
unusualValuesFns[0],
|
||||
ArrayRef<Value *>{ConstantInt::get(Int32Ty, Key, true), XB,
|
||||
ConstantInt::get(Int8Ty, always_true, true)});
|
||||
|
||||
} else { // Pointer
|
||||
|
||||
auto* XP = IRB.CreateBitCast(X, Int8PTy);
|
||||
//XP->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
|
||||
CI = IRB.CreateCall(
|
||||
unusualValuesPtrFn,
|
||||
ArrayRef<Value *>{ConstantInt::get(Int32Ty, Key, true), XP,
|
||||
ConstantInt::get(Int8Ty, always_ptr_true, true)});
|
||||
|
||||
}
|
||||
|
||||
CI->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
++Calls1;
|
||||
++SingleCnt;
|
||||
|
||||
Rets.insert(CI);
|
||||
if (Hash == nullptr) Hash = CI;
|
||||
else Hash = IRB.CreateXor(Hash, CI);
|
||||
|
||||
}
|
||||
|
||||
Dumpeds1.insert(X);
|
||||
|
||||
}
|
||||
|
||||
// if (P.first == -1) continue;
|
||||
|
||||
for (auto O : CompArgs) {
|
||||
|
||||
if (P.first != -1 && P.first != O.first) continue;
|
||||
|
||||
for (auto Y : O.second) {
|
||||
|
||||
if (X == Y ||
|
||||
X->getType()->getTypeID() != Y->getType()->getTypeID() ||
|
||||
Dumpeds2.find(std::make_pair(X, Y)) != Dumpeds2.end() ||
|
||||
Dumpeds2.find(std::make_pair(Y, X)) != Dumpeds2.end())
|
||||
continue;
|
||||
|
||||
if (X->getType()->getTypeID() == Type::PointerTyID && IsAlloca(X) && IsAlloca(Y)) continue;
|
||||
|
||||
CallInst *CI;
|
||||
Key = AFL_R(UNUSUAL_MAP_SIZE);
|
||||
|
||||
if (XB == nullptr) {
|
||||
XB = IRB.CreateSExtOrBitCast(X, Int64Ty);
|
||||
//XB->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
}
|
||||
|
||||
auto *YB = IRB.CreateSExtOrBitCast(Y, Int64Ty);
|
||||
|
||||
CI = IRB.CreateCall(
|
||||
unusualValuesFns[1],
|
||||
ArrayRef<Value *>{ConstantInt::get(Int32Ty, Key, true), XB,
|
||||
YB});
|
||||
|
||||
CI->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
++Calls2;
|
||||
|
||||
Rets.insert(CI);
|
||||
if (Hash == nullptr) Hash = CI;
|
||||
else Hash = IRB.CreateXor(Hash, CI);
|
||||
|
||||
Dumpeds2.insert(std::make_pair(X, Y));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Rets.size() && !(SingleCnt == 1 && Rets.size() == 1)) {
|
||||
|
||||
FunctionModified = true;
|
||||
|
||||
CallInst *CI =
|
||||
IRB.CreateCall(unusualValuesLogFn, ArrayRef<Value *>{Hash});
|
||||
CI->setMetadata(M.getMDKindID("nosanitize"), MDNode::get(*C, None));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (FunctionModified && !be_quiet) {
|
||||
|
||||
OKF("Inserted %d calls to log single values, %d to log pairs.", Calls1,
|
||||
Calls2);
|
||||
|
||||
}
|
||||
|
||||
return FunctionModified;
|
||||
|
||||
}
|
||||
|
||||
class AFLUnusualFunctionPass : public FunctionPass {
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
explicit AFLUnusualFunctionPass() : FunctionPass(ID) {
|
||||
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
|
||||
AU.setPreservesCFG();
|
||||
AU.addRequired<DominatorTreeWrapperPass>();
|
||||
//AU.addRequired<IntraProceduralRA<Cousot>>();
|
||||
//AU.addRequired<AAResultsWrapperPass>();
|
||||
|
||||
}
|
||||
|
||||
StringRef getPassName() const override {
|
||||
|
||||
return "AFLUnusualPass";
|
||||
|
||||
}
|
||||
|
||||
bool runOnFunction(Function &F) override {
|
||||
|
||||
Module & M = *F.getParent();
|
||||
DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
||||
//IntraProceduralRA<Cousot> &RA = getAnalysis<IntraProceduralRA<Cousot>>();
|
||||
AFLUnusual DI(M, F, DT);
|
||||
bool r = DI.instrumentFunction();
|
||||
// verifyFunction(F);
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
char AFLUnusualFunctionPass::ID = 0;
|
||||
|
||||
// For RangeAnalysis
|
||||
//template <class CGT>
|
||||
//char IntraProceduralRA<CGT>::ID;
|
||||
|
||||
static void registerAFLUnusualPass(const PassManagerBuilder &,
|
||||
legacy::PassManagerBase &PM) {
|
||||
|
||||
PM.add(new AFLUnusualFunctionPass());
|
||||
|
||||
}
|
||||
|
||||
static RegisterStandardPasses RegisterAFLUnusualPass(
|
||||
PassManagerBuilder::EP_OptimizerLast, registerAFLUnusualPass);
|
||||
|
||||
static RegisterStandardPasses RegisterAFLUnusualPass0(
|
||||
PassManagerBuilder::EP_EnabledOnOptLevel0, registerAFLUnusualPass);
|
||||
|
||||
static RegisterPass<AFLUnusualFunctionPass> X("afl-unusual", "AFLUnusualPass",
|
||||
false, false);
|
||||
|
753
instrumentation/afl-unusual-rt.o.c
Normal file
753
instrumentation/afl-unusual-rt.o.c
Normal file
@ -0,0 +1,753 @@
|
||||
/*
|
||||
american fuzzy lop++ - LLVM instrumentation bootstrap
|
||||
-----------------------------------------------------
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#include "unusual.h"
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct unusual_values_state __afl_unusual_dummy;
|
||||
// Override the weak symbol
|
||||
struct unusual_values_state *__afl_unusual = &__afl_unusual_dummy;
|
||||
|
||||
#define GET_BIT(_ar, _b) !!((((u8 *)(_ar))[(_b) >> 3] & (128 >> ((_b)&7))))
|
||||
|
||||
#define SET_BIT(_ar, _b) \
|
||||
do { \
|
||||
\
|
||||
u8 *_arf = (u8 *)(_ar); \
|
||||
u32 _bf = (_b); \
|
||||
_arf[(_bf) >> 3] |= (128 >> ((_bf)&7)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define UNSET_BIT(_ar, _b) \
|
||||
do { \
|
||||
\
|
||||
u8 *_arf = (u8 *)(_ar); \
|
||||
u32 _bf = (_b); \
|
||||
_arf[(_bf) >> 3] &= ~(128 >> ((_bf)&7)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define FLIP_BIT(_ar, _b) \
|
||||
do { \
|
||||
\
|
||||
u8 *_arf = (u8 *)(_ar); \
|
||||
u32 _bf = (_b); \
|
||||
_arf[(_bf) >> 3] ^= (128 >> ((_bf)&7)); \
|
||||
\
|
||||
} while (0)
|
||||
|
||||
#define UPDATE_MAP(k) SET_BIT(__afl_unusual->map, k)
|
||||
#define UPDATE_VIRGIN(k) \
|
||||
{ \
|
||||
\
|
||||
SET_BIT(__afl_unusual->virgin, k); \
|
||||
SET_BIT(__afl_unusual->crash, k); \
|
||||
\
|
||||
}
|
||||
// #define UPDATE_VIRGIN(k)
|
||||
|
||||
static void patch_caller(uint8_t *retaddr) {
|
||||
|
||||
#ifdef __x86_64__
|
||||
if (retaddr[-5] == 0xe8) { // Near call
|
||||
|
||||
uint8_t *caller = &retaddr[-5];
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uint8_t *page = (uint8_t *)((uintptr_t)caller & ~(page_size - 1));
|
||||
|
||||
if (page + page_size <= retaddr) {
|
||||
|
||||
// it crosses a boundary
|
||||
page_size *= 2;
|
||||
|
||||
}
|
||||
|
||||
mprotect(page, page_size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
// The patched stub must return 0
|
||||
// 4831c0 xor rax, rax
|
||||
caller[0] = 0x48;
|
||||
caller[1] = 0x31;
|
||||
caller[2] = 0xc0;
|
||||
// 90 nop
|
||||
caller[3] = 0x90;
|
||||
caller[4] = 0x90;
|
||||
mprotect(page, page_size, PROT_READ | PROT_EXEC);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static u32 unusual_values_single(uint8_t *retaddr, u32 k, u64 x,
|
||||
u8 always_true) {
|
||||
|
||||
u32 ret = 0;
|
||||
|
||||
int learning = __afl_unusual->learning;
|
||||
struct single_var_invariant *inv = &__afl_unusual->single_invariants[k];
|
||||
|
||||
// u8 old = inv->invariant;
|
||||
|
||||
switch (inv->invariant) {
|
||||
|
||||
case INV_NONE: {
|
||||
|
||||
if (learning) {
|
||||
|
||||
// inv->num_vals = 0;
|
||||
inv->vals[inv->num_vals++] = x;
|
||||
inv->invariant = INV_ONEOF;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_LT: {
|
||||
|
||||
if ((s64)x < 0) break;
|
||||
if (learning) {
|
||||
|
||||
if (x == 0)
|
||||
inv->invariant = INV_LE;
|
||||
else
|
||||
inv->invariant = INV_NE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
if (always_true == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_LE: {
|
||||
|
||||
if ((s64)x <= 0) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_GT: {
|
||||
|
||||
if ((s64)x > 0) break;
|
||||
if (learning) {
|
||||
|
||||
if (x == 0)
|
||||
inv->invariant = INV_GE;
|
||||
else
|
||||
inv->invariant = INV_NE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
if (always_true == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_GE: {
|
||||
|
||||
if ((s64)x >= 0) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_EQ: {
|
||||
|
||||
if (x == 0) break;
|
||||
if (learning) {
|
||||
|
||||
if ((s64)x > 0)
|
||||
inv->invariant = INV_GE;
|
||||
else
|
||||
inv->invariant = INV_LE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
if (always_true == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_NE: {
|
||||
|
||||
if (x != 0) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_ONEOF: {
|
||||
|
||||
int oneof = 1;
|
||||
size_t i;
|
||||
for (i = 0; i < inv->num_vals; ++i) {
|
||||
|
||||
if (inv->vals[i] != x) oneof = 0;
|
||||
|
||||
}
|
||||
|
||||
if (oneof) break;
|
||||
|
||||
if (learning) {
|
||||
|
||||
if (inv->num_vals < INV_ONEOF_MAX_NUM_VALS) {
|
||||
|
||||
inv->vals[inv->num_vals++] = x;
|
||||
|
||||
} else {
|
||||
|
||||
int lt = 0, gt = 0, eq = 0;
|
||||
for (i = 0; i < INV_ONEOF_MAX_NUM_VALS; ++i) {
|
||||
|
||||
if ((s64)inv->vals[i] < 0)
|
||||
++lt;
|
||||
else if ((s64)inv->vals[i] > 0)
|
||||
++gt;
|
||||
else if ((s64)inv->vals[i] == 0)
|
||||
++eq;
|
||||
|
||||
}
|
||||
|
||||
if (lt && !gt && !eq)
|
||||
inv->invariant = INV_LT;
|
||||
else if (lt && !gt && eq)
|
||||
inv->invariant = INV_LE;
|
||||
else if (!lt && gt && !eq)
|
||||
inv->invariant = INV_GT;
|
||||
else if (!lt && gt && eq)
|
||||
inv->invariant = INV_GE;
|
||||
else if (lt && gt && !eq)
|
||||
inv->invariant = INV_NE;
|
||||
else { // if (lt && gt && eq)
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
if (always_true == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_ALL: {
|
||||
|
||||
patch_caller(retaddr);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (learning) ++inv->execs;
|
||||
|
||||
// if (old != inv->invariant) fprintf(stderr, "LEARNING %x %d -- %d %d\n", k, inv->execs, old, inv->invariant);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static u32 unusual_values_pair(uint8_t *retaddr, u32 k, u64 x, u64 y) {
|
||||
|
||||
u32 ret = 0;
|
||||
|
||||
int learning = __afl_unusual->learning;
|
||||
struct pair_vars_invariant *inv = &__afl_unusual->pair_invariants[k];
|
||||
|
||||
switch (inv->invariant) {
|
||||
|
||||
case INV_NONE: {
|
||||
|
||||
if (learning) {
|
||||
|
||||
if (x == y)
|
||||
inv->invariant = INV_EQ;
|
||||
else if ((s64)x > (s64)y)
|
||||
inv->invariant = INV_GT;
|
||||
else // if ((s64)x < (s64)y)
|
||||
inv->invariant = INV_LT;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_LT: {
|
||||
|
||||
if ((s64)x < (s64)y) break;
|
||||
if (learning) {
|
||||
|
||||
if (x == y)
|
||||
inv->invariant = INV_LE;
|
||||
else
|
||||
inv->invariant = INV_NE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_LE: {
|
||||
|
||||
if ((s64)x <= (s64)y) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_GT: {
|
||||
|
||||
if ((s64)x > (s64)y) break;
|
||||
if (learning) {
|
||||
|
||||
if (x == y)
|
||||
inv->invariant = INV_GE;
|
||||
else
|
||||
inv->invariant = INV_NE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_GE: {
|
||||
|
||||
if ((s64)x >= (s64)y) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_EQ: {
|
||||
|
||||
if (x == y) break;
|
||||
if (learning) {
|
||||
|
||||
if ((s64)x > (s64)y)
|
||||
inv->invariant = INV_GE;
|
||||
else
|
||||
inv->invariant = INV_LE;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_NE: {
|
||||
|
||||
if (x != y) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (learning) ++inv->execs;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static uintptr_t stack_end = UINTPTR_MAX;
|
||||
|
||||
__attribute__((constructor)) void register_stack_end(void) {
|
||||
|
||||
int dummy;
|
||||
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
stack_end = (uintptr_t)&dummy & ~(page_size - 1) + page_size;
|
||||
|
||||
}
|
||||
|
||||
static int is_stack(uintptr_t p) {
|
||||
|
||||
int dummy;
|
||||
uintptr_t sp = (uintptr_t)&dummy;
|
||||
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
uintptr_t page = sp & ~(page_size - 1);
|
||||
|
||||
return p >= page && p < stack_end;
|
||||
|
||||
}
|
||||
|
||||
static u32 unusual_values_ptr(uint8_t *retaddr, u32 k, uintptr_t x, u8 always_true) {
|
||||
|
||||
u32 ret = 0;
|
||||
|
||||
uintptr_t first_page = (uintptr_t)sysconf(_SC_PAGE_SIZE);
|
||||
int learning = __afl_unusual->learning;
|
||||
|
||||
struct single_var_invariant *inv = &__afl_unusual->single_invariants[k];
|
||||
|
||||
switch (inv->invariant) {
|
||||
|
||||
case INV_NONE: {
|
||||
|
||||
if (learning) {
|
||||
|
||||
if (x == 0) inv->invariant = INV_EQ;
|
||||
else if (is_stack(x)) inv->invariant = INV_STACK;
|
||||
else if (x >= first_page) inv->invariant = INV_GE_PAGE;
|
||||
else if (x < first_page) inv->invariant = INV_LT_PAGE;
|
||||
else inv->invariant = INV_ALL;
|
||||
|
||||
if (always_true == inv->invariant || INV_ALL == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_EQ: {
|
||||
|
||||
if (x == 0) break;
|
||||
if (learning) {
|
||||
|
||||
if (x < first_page) inv->invariant = INV_LT_PAGE;
|
||||
else inv->invariant = INV_ALL;
|
||||
|
||||
if (always_true == inv->invariant || INV_ALL == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_LT_PAGE: {
|
||||
|
||||
if (x < first_page) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_GE_PAGE: {
|
||||
|
||||
if (x >= first_page) break;
|
||||
if (learning) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
UPDATE_VIRGIN(k);
|
||||
|
||||
patch_caller(retaddr);
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_STACK: {
|
||||
|
||||
if (is_stack(x)) break;
|
||||
if (learning) {
|
||||
|
||||
if (x >= first_page) inv->invariant = INV_GE_PAGE;
|
||||
else inv->invariant = INV_ALL;
|
||||
|
||||
if (always_true == inv->invariant || INV_ALL == inv->invariant) {
|
||||
|
||||
inv->invariant = INV_ALL;
|
||||
patch_caller(retaddr);
|
||||
|
||||
}
|
||||
|
||||
} else if (inv->execs >= INV_EXECS_MIN_BOUND) {
|
||||
|
||||
ret = k;
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case INV_ALL: {
|
||||
|
||||
patch_caller(retaddr);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (learning) ++inv->execs;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
u32 __afl_unusual_values_1(u32 k, u64 x, u8 always_true) {
|
||||
|
||||
// if (!__afl_unusual) return 0;
|
||||
|
||||
u32 r = unusual_values_single((uint8_t *)__builtin_return_address(0), k, x,
|
||||
always_true);
|
||||
|
||||
//if (r && GET_BIT(__afl_unusual->virgin, r)) fprintf(stderr, "VIOLATED 1 %x\n", r);
|
||||
|
||||
UPDATE_MAP(r);
|
||||
|
||||
// if (unusual)
|
||||
// fprintf(stderr, "(%x) unusual = %d, x = %llu\n", k, unusual,
|
||||
// (unsigned long long)x);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
u32 __afl_unusual_values_2(u32 k, u64 x, u64 y) {
|
||||
|
||||
// if (!__afl_unusual) return 0;
|
||||
|
||||
u32 r = unusual_values_pair((uint8_t *)__builtin_return_address(0), k, x, y);
|
||||
|
||||
//if (r && GET_BIT(__afl_unusual->virgin, r)) fprintf(stderr, "VIOLATED 2 %x\n", r);
|
||||
|
||||
UPDATE_MAP(r);
|
||||
|
||||
// if (unusual)
|
||||
// fprintf(stderr, "(%x) unusual = %d, x = %llu, y = %llu\n", k, unusual,
|
||||
// (unsigned long long)x, (unsigned long long)y);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
u32 __afl_unusual_values_ptr(u32 k, uintptr_t x, u8 always_true) {
|
||||
|
||||
// if (!__afl_unusual) return 0;
|
||||
|
||||
u32 r = unusual_values_ptr((uint8_t *)__builtin_return_address(0), k, x,
|
||||
always_true);
|
||||
|
||||
//if (r && GET_BIT(__afl_unusual->virgin, r)) fprintf(stderr, "VIOLATED P %x\n", r);
|
||||
|
||||
UPDATE_MAP(r);
|
||||
|
||||
// if (unusual)
|
||||
// fprintf(stderr, "(%x) unusual = %d, x = %llu\n", k, unusual,
|
||||
// (unsigned long long)x);
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
extern u8 *__afl_area_ptr;
|
||||
|
||||
void __afl_unusual_values_log(u32 k) {
|
||||
|
||||
k &= UNUSUAL_MAP_SIZE -1;
|
||||
|
||||
//if (k && GET_BIT(__afl_unusual->virgin, k)) fprintf(stderr, "FILLING %x\n", k);
|
||||
|
||||
// if (!__afl_unusual->learning) __afl_area_ptr[k]++;
|
||||
UPDATE_MAP(k);
|
||||
|
||||
}
|
||||
|
40
src/afl-cc.c
40
src/afl-cc.c
@ -57,6 +57,7 @@ static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
|
||||
static u8 debug;
|
||||
static u8 cwd[4096];
|
||||
static u8 cmplog_mode;
|
||||
static u8 unusual_mode;
|
||||
u8 use_stdin; /* dummy */
|
||||
// static u8 *march_opt = CFLAGS_OPT;
|
||||
|
||||
@ -642,6 +643,25 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (unusual_mode) {
|
||||
|
||||
if (lto_mode && !have_c) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("-Wl,-mllvm=-load=%s/afl-unusual-pass.so", obj_path);
|
||||
|
||||
} else {
|
||||
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] = "-load";
|
||||
cc_params[cc_par_cnt++] = "-Xclang";
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-unusual-pass.so", obj_path);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// cc_params[cc_par_cnt++] = "-Qunused-arguments";
|
||||
|
||||
@ -998,9 +1018,16 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
switch (bit_mode) {
|
||||
|
||||
case 0:
|
||||
if (!shared_linking && !partial_linking)
|
||||
if (!shared_linking && !partial_linking) {
|
||||
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-compiler-rt.o", obj_path);
|
||||
if (unusual_mode)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-unusual-rt.o", obj_path);
|
||||
|
||||
}
|
||||
|
||||
if (lto_mode)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
|
||||
@ -1013,6 +1040,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
alloc_printf("%s/afl-compiler-rt-32.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m32 is not supported by your compiler");
|
||||
if (unusual_mode)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-unusual-rt-32.o", obj_path);
|
||||
|
||||
}
|
||||
|
||||
@ -1034,6 +1064,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
|
||||
alloc_printf("%s/afl-compiler-rt-64.o", obj_path);
|
||||
if (access(cc_params[cc_par_cnt - 1], R_OK))
|
||||
FATAL("-m64 is not supported by your compiler");
|
||||
if (unusual_mode)
|
||||
cc_params[cc_par_cnt++] =
|
||||
alloc_printf("%s/afl-unusual-rt-64.o", obj_path);
|
||||
|
||||
}
|
||||
|
||||
@ -2033,6 +2066,11 @@ int main(int argc, char **argv, char **envp) {
|
||||
if (!be_quiet && cmplog_mode)
|
||||
printf("CmpLog mode by <andreafioraldi@gmail.com>\n");
|
||||
|
||||
unusual_mode =
|
||||
getenv("AFL_UNUSUAL_VALUES") || getenv("AFL_LLVM_UNUSUAL_VALUES");
|
||||
if (!be_quiet && unusual_mode)
|
||||
printf("Unusual Values mode by <andreafioraldi@gmail.com>\n");
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(ANDROID)
|
||||
ptr = find_object("afl-compiler-rt.o", argv[0]);
|
||||
|
||||
|
@ -423,6 +423,13 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
|
||||
|
||||
}
|
||||
|
||||
if (!fsrv->unusual_binary && fsrv->qemu_mode == false &&
|
||||
fsrv->frida_mode == false) {
|
||||
|
||||
unsetenv(UNUSUAL_SHM_ENV_VAR); // we do not want that in non-unusual fsrv
|
||||
|
||||
}
|
||||
|
||||
/* Umpf. On OpenBSD, the default fd limit for root users is set to
|
||||
soft 128. Let's try to fix that... */
|
||||
if (!getrlimit(RLIMIT_NOFILE, &r) && r.rlim_cur < FORKSRV_FD + 2) {
|
||||
|
@ -384,7 +384,8 @@ 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 || new_bits == 5) { strcat(ret, ",+cov"); }
|
||||
if (new_bits >= 3) { strcat(ret, ",+un"); }
|
||||
|
||||
if (unlikely(strlen(ret) >= max_description_len))
|
||||
FATAL("describe string is too long");
|
||||
@ -450,12 +451,101 @@ void write_crash_readme(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
u8 is_unusual(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(!afl->shm.unusual_mode)) { return 0; }
|
||||
|
||||
u64 *current_begin = (u64 *)afl->shm.unusual->map;
|
||||
u64 *current = current_begin;
|
||||
u64 *current_end =
|
||||
(u64 *)(afl->shm.unusual->map + sizeof(afl->shm.unusual->map));
|
||||
u64 *virgin = (u64 *)afl->shm.unusual->virgin;
|
||||
u8 has_new = 0;
|
||||
for (; current < current_end; virgin += 8, current += 8) {
|
||||
\
|
||||
#define GET_BIT(_ar, _b) !!((((u8 *)(_ar))[(_b) >> 3] & (128 >> ((_b)&7))))
|
||||
#define UNROLL(idx) \
|
||||
if (current[idx] & virgin[idx]) { \
|
||||
\
|
||||
if (GET_BIT(current, 0)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 0] = 1; \
|
||||
if (GET_BIT(current, 1)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 1] = 1; \
|
||||
if (GET_BIT(current, 2)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 2] = 1; \
|
||||
if (GET_BIT(current, 3)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 3] = 1; \
|
||||
if (GET_BIT(current, 4)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 4] = 1; \
|
||||
if (GET_BIT(current, 5)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 5] = 1; \
|
||||
if (GET_BIT(current, 6)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 6] = 1; \
|
||||
if (GET_BIT(current, 7)) \
|
||||
afl->unusual_item_changed[(¤t[idx] - current_begin) + 7] = 1; \
|
||||
has_new = 1; \
|
||||
virgin[idx] &= ~current[idx]; \
|
||||
\
|
||||
}
|
||||
UNROLL(0)
|
||||
UNROLL(1)
|
||||
UNROLL(2)
|
||||
UNROLL(3)
|
||||
UNROLL(4)
|
||||
UNROLL(5)
|
||||
UNROLL(6)
|
||||
UNROLL(7)
|
||||
#undef UNROLL
|
||||
#undef GET_BIT
|
||||
|
||||
}
|
||||
|
||||
return has_new;
|
||||
|
||||
}
|
||||
|
||||
u8 is_unusual_crash(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(!afl->shm.unusual_mode)) { return 0; }
|
||||
|
||||
u64 *current_begin = (u64 *)afl->shm.unusual->map;
|
||||
u64 *current = current_begin;
|
||||
u64 *current_end =
|
||||
(u64 *)(afl->shm.unusual->map + sizeof(afl->shm.unusual->map));
|
||||
u64 *virgin = (u64 *)afl->shm.unusual->crash;
|
||||
u8 has_new = 0;
|
||||
for (; current < current_end; virgin += 8, current += 8) {
|
||||
\
|
||||
#define UNROLL(idx) \
|
||||
if (current[idx] & virgin[idx]) { \
|
||||
\
|
||||
has_new = 1; \
|
||||
virgin[idx] &= ~current[idx]; \
|
||||
\
|
||||
}
|
||||
UNROLL(0)
|
||||
UNROLL(1)
|
||||
UNROLL(2)
|
||||
UNROLL(3)
|
||||
UNROLL(4)
|
||||
UNROLL(5)
|
||||
UNROLL(6)
|
||||
UNROLL(7)
|
||||
#undef UNROLL
|
||||
|
||||
}
|
||||
|
||||
return has_new;
|
||||
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
|
||||
u8 __attribute__((hot))
|
||||
save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault,
|
||||
u8 check_unusual) {
|
||||
|
||||
if (unlikely(len == 0)) { return 0; }
|
||||
|
||||
@ -488,6 +578,13 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
new_bits = has_new_bits_unclassified(afl, afl->virgin_bits);
|
||||
|
||||
if (check_unusual && is_unusual(afl)) {
|
||||
|
||||
if (!new_bits) classify_counts(&afl->fsrv);
|
||||
new_bits += 3;
|
||||
|
||||
}
|
||||
|
||||
if (likely(!new_bits)) {
|
||||
|
||||
if (unlikely(afl->crash_mode)) { ++afl->total_crashes; }
|
||||
@ -550,6 +647,12 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
++afl->queued_with_cov;
|
||||
|
||||
}
|
||||
|
||||
if (new_bits >= 3) {
|
||||
|
||||
afl->queue_top->has_unusual = 1;
|
||||
|
||||
}
|
||||
|
||||
if (cksum)
|
||||
afl->queue_top->exec_cksum = cksum;
|
||||
@ -705,7 +808,13 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
|
||||
simplify_trace(afl, afl->fsrv.trace_bits);
|
||||
|
||||
if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; }
|
||||
u8 has_new = has_new_bits(afl, afl->virgin_crash);
|
||||
|
||||
if (!has_new && check_unusual && is_unusual_crash(afl)) has_new = 1;
|
||||
|
||||
// if (!has_new_bits(afl, afl->virgin_crash)) { return keeping; }
|
||||
|
||||
if (!has_new) { return keeping; }
|
||||
|
||||
}
|
||||
|
||||
@ -768,7 +877,7 @@ save_if_interesting(afl_state_t *afl, void *mem, u32 len, u8 fault) {
|
||||
}
|
||||
|
||||
afl->last_crash_time = get_cur_time();
|
||||
afl->last_crash_execs = afl->fsrv.total_execs;
|
||||
afl->last_crash_execs = total_execs_all(afl);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -620,7 +620,7 @@ void read_foreign_testcases(afl_state_t *afl, int first) {
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
afl->syncing_party = foreign_name;
|
||||
afl->queued_imported +=
|
||||
save_if_interesting(afl, mem, st.st_size, fault);
|
||||
save_if_interesting(afl, mem, st.st_size, fault, 0);
|
||||
afl->syncing_party = 0;
|
||||
munmap(mem, st.st_size);
|
||||
close(fd);
|
||||
|
@ -504,7 +504,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
************/
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
|
||||
!afl->disable_trim)) {
|
||||
!afl->disable_trim && !afl->queue_cur->has_unusual)) {
|
||||
|
||||
u32 old_len = afl->queue_cur->len;
|
||||
|
||||
@ -549,6 +549,18 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
|
||||
if (unlikely(perf_score <= 0)) { goto abandon_entry; }
|
||||
|
||||
// Unusual learning phase
|
||||
|
||||
/*if (afl->shm.unusual_mode) {
|
||||
|
||||
afl->shm.unusual->learning = 1;
|
||||
|
||||
common_fuzz_unusual_stuff(afl, out_buf, len);
|
||||
|
||||
afl->shm.unusual->learning = 0;
|
||||
|
||||
}*/
|
||||
|
||||
if (unlikely(afl->shm.cmplog_mode &&
|
||||
afl->queue_cur->colorized < afl->cmplog_lvl &&
|
||||
(u32)len <= afl->cmplog_max_filesize)) {
|
||||
@ -562,7 +574,7 @@ u8 fuzz_one_original(afl_state_t *afl) {
|
||||
if (afl->cmplog_lvl == 3 ||
|
||||
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
||||
afl->queue_cur->favored ||
|
||||
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
||||
!(total_execs_all(afl) % afl->queued_paths) ||
|
||||
get_cur_time() - afl->last_path_time > 300000) { // 300 seconds
|
||||
|
||||
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
||||
@ -3004,7 +3016,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
|
||||
************/
|
||||
|
||||
if (unlikely(!afl->non_instrumented_mode && !afl->queue_cur->trim_done &&
|
||||
!afl->disable_trim)) {
|
||||
!afl->disable_trim && !afl->queue_cur->has_unusual)) {
|
||||
|
||||
u32 old_len = afl->queue_cur->len;
|
||||
|
||||
@ -3060,7 +3072,7 @@ static u8 mopt_common_fuzzing(afl_state_t *afl, MOpt_globals_t MOpt_globals) {
|
||||
|
||||
if (afl->cmplog_lvl == 3 ||
|
||||
(afl->cmplog_lvl == 2 && afl->queue_cur->tc_ref) ||
|
||||
!(afl->fsrv.total_execs % afl->queued_paths) ||
|
||||
!(total_execs_all(afl) % afl->queued_paths) ||
|
||||
get_cur_time() - afl->last_path_time > 300000) { // 300 seconds
|
||||
|
||||
if (input_to_state_stage(afl, in_buf, out_buf, len)) {
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include "unusual.h"
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
@ -550,6 +551,23 @@ void update_bitmap_score(afl_state_t *afl, struct queue_entry *q) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->shm.unusual_mode && !afl->shm.unusual->learning) {
|
||||
|
||||
for (i = 0; i < UNUSUAL_MAP_SIZE; i++) {
|
||||
|
||||
if (afl->unusual_item_changed[i]) {
|
||||
|
||||
/* Insert ourselves as the new winner. */
|
||||
afl->top_rated_unusual[i] = q;
|
||||
afl->score_changed = 1;
|
||||
afl->unusual_item_changed[i] = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* For every byte set in afl->fsrv.trace_bits[], see if there is a previous
|
||||
winner, and how it compares to us. */
|
||||
for (i = 0; i < afl->fsrv.map_size; ++i) {
|
||||
@ -663,6 +681,31 @@ void cull_queue(afl_state_t *afl) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->shm.unusual_mode) {
|
||||
|
||||
for (i = 0; i < UNUSUAL_MAP_SIZE; i++) {
|
||||
|
||||
if (afl->top_rated_unusual[i]) {
|
||||
|
||||
/* if top rated for any i, will be favored */
|
||||
u8 was_favored_already = afl->top_rated_unusual[i]->favored;
|
||||
|
||||
afl->top_rated_unusual[i]->favored = 1;
|
||||
|
||||
/* increments counts only if not also favored for another i */
|
||||
if (!was_favored_already) {
|
||||
|
||||
afl->queued_favored++;
|
||||
if (!afl->top_rated_unusual[i]->was_fuzzed) afl->pending_favored++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Let's see if anything in the bitmap isn't captured in temp_v.
|
||||
If yes, and if it has a afl->top_rated[] contender, let's use it. */
|
||||
|
||||
@ -956,7 +999,7 @@ u32 calculate_score(afl_state_t *afl, struct queue_entry *q) {
|
||||
// the more often fuzz result paths are equal to this queue entry,
|
||||
// reduce its value
|
||||
perf_score *= (1 - (double)((double)afl->n_fuzz[q->n_fuzz_entry] /
|
||||
(double)afl->fsrv.total_execs));
|
||||
(double)total_execs_all(afl)));
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2563,10 +2563,10 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
|
||||
// Start insertion loop
|
||||
|
||||
u64 orig_hit_cnt, new_hit_cnt;
|
||||
u64 orig_execs = afl->fsrv.total_execs;
|
||||
u64 orig_execs = total_execs_all(afl);
|
||||
orig_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
||||
u64 screen_update = 100000 / afl->queue_cur->exec_us,
|
||||
execs = afl->fsrv.total_execs;
|
||||
execs = total_execs_all(afl);
|
||||
|
||||
afl->stage_name = "input-to-state";
|
||||
afl->stage_short = "its";
|
||||
@ -2646,9 +2646,9 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->fsrv.total_execs - execs > screen_update) {
|
||||
if (total_execs_all(afl) - execs > screen_update) {
|
||||
|
||||
execs = afl->fsrv.total_execs;
|
||||
execs = total_execs_all(afl);
|
||||
show_stats(afl);
|
||||
|
||||
}
|
||||
@ -2750,7 +2750,7 @@ exit_its:
|
||||
|
||||
new_hit_cnt = afl->queued_paths + afl->unique_crashes;
|
||||
afl->stage_finds[STAGE_ITS] += new_hit_cnt - orig_hit_cnt;
|
||||
afl->stage_cycles[STAGE_ITS] += afl->fsrv.total_execs - orig_execs;
|
||||
afl->stage_cycles[STAGE_ITS] += total_execs_all(afl) - orig_execs;
|
||||
|
||||
#if defined(_DEBUG) || defined(CMPLOG_INTROSPECTION)
|
||||
FILE *f = stderr;
|
||||
|
@ -351,6 +351,31 @@ u8 calibrate_case(afl_state_t *afl, struct queue_entry *q, u8 *use_mem,
|
||||
|
||||
}
|
||||
|
||||
if (afl->shm.unusual_mode /*&& afl->shm.unusual->learning*/) {
|
||||
|
||||
afl->shm.unusual->learning = 1;
|
||||
|
||||
write_to_testcase(afl, use_mem, q->len);
|
||||
|
||||
fuzz_run_target(afl, &afl->unusual_fsrv, use_tmout);
|
||||
|
||||
afl->shm.unusual->learning = 0;
|
||||
|
||||
/* afl->stop_soon is set by the handler for Ctrl+C. When it's pressed,
|
||||
we want to bail out quickly. */
|
||||
|
||||
if (afl->stop_soon || fault != afl->crash_mode) { goto abort_calibration; }
|
||||
|
||||
if (!afl->non_instrumented_mode && !afl->stage_cur &&
|
||||
!count_bytes(afl, afl->unusual_fsrv.trace_bits)) {
|
||||
|
||||
fault = FSRV_RUN_NOINST;
|
||||
goto abort_calibration;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
start_us = get_cur_time_us();
|
||||
|
||||
for (afl->stage_cur = 0; afl->stage_cur < afl->stage_max; ++afl->stage_cur) {
|
||||
@ -654,13 +679,17 @@ void sync_fuzzers(afl_state_t *afl) {
|
||||
|
||||
write_to_testcase(afl, mem, st.st_size);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
if (afl->shm.unusual_mode && afl->shm.unusual->learning)
|
||||
fault =
|
||||
fuzz_run_target(afl, &afl->unusual_fsrv, afl->fsrv.exec_tmout);
|
||||
else
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
|
||||
if (afl->stop_soon) { goto close_sync; }
|
||||
|
||||
afl->syncing_party = sd_ent->d_name;
|
||||
afl->queued_imported +=
|
||||
save_if_interesting(afl, mem, st.st_size, fault);
|
||||
save_if_interesting(afl, mem, st.st_size, fault, 0);
|
||||
afl->syncing_party = 0;
|
||||
|
||||
munmap(mem, st.st_size);
|
||||
@ -895,6 +924,10 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
u8 fault;
|
||||
|
||||
//if (afl->shm.unusual_mode && afl->shm.unusual->learning == 0)
|
||||
if (afl->shm.unusual_mode && rand_below(afl, 16) == 0)
|
||||
return common_fuzz_unusual_stuff(afl, out_buf, len);
|
||||
|
||||
write_to_testcase(afl, out_buf, len);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->fsrv, afl->fsrv.exec_tmout);
|
||||
@ -929,7 +962,7 @@ common_fuzz_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
/* This handles FAULT_ERROR for us: */
|
||||
|
||||
afl->queued_discovered += save_if_interesting(afl, out_buf, len, fault);
|
||||
afl->queued_discovered += save_if_interesting(afl, out_buf, len, fault, 0);
|
||||
|
||||
if (!(afl->stage_cur % afl->stats_update_freq) ||
|
||||
afl->stage_cur + 1 == afl->stage_max) {
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include "unusual.h"
|
||||
#include "envs.h"
|
||||
|
||||
s8 interesting_8[] = {INTERESTING_8};
|
||||
@ -119,6 +120,8 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
|
||||
afl->virgin_crash = ck_alloc(map_size);
|
||||
afl->var_bytes = ck_alloc(map_size);
|
||||
afl->top_rated = ck_alloc(map_size * sizeof(void *));
|
||||
afl->top_rated_unusual = ck_alloc(UNUSUAL_MAP_SIZE * sizeof(void *));
|
||||
afl->unusual_item_changed = ck_alloc(UNUSUAL_MAP_SIZE);
|
||||
afl->clean_trace = ck_alloc(map_size);
|
||||
afl->clean_trace_custom = ck_alloc(map_size);
|
||||
afl->first_trace = ck_alloc(map_size);
|
||||
@ -555,6 +558,8 @@ void afl_state_deinit(afl_state_t *afl) {
|
||||
ck_free(afl->virgin_crash);
|
||||
ck_free(afl->var_bytes);
|
||||
ck_free(afl->top_rated);
|
||||
ck_free(afl->top_rated_unusual);
|
||||
ck_free(afl->unusual_item_changed);
|
||||
ck_free(afl->clean_trace);
|
||||
ck_free(afl->clean_trace_custom);
|
||||
ck_free(afl->first_trace);
|
||||
|
@ -221,9 +221,9 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
cur_time - afl->last_avg_exec_update >= 60000))) {
|
||||
|
||||
afl->last_avg_execs_saved =
|
||||
(double)(1000 * (afl->fsrv.total_execs - afl->last_avg_execs)) /
|
||||
(double)(1000 * (total_execs_all(afl) - afl->last_avg_execs)) /
|
||||
(double)(cur_time - afl->last_avg_exec_update);
|
||||
afl->last_avg_execs = afl->fsrv.total_execs;
|
||||
afl->last_avg_execs = total_execs_all(afl);
|
||||
afl->last_avg_exec_update = cur_time;
|
||||
|
||||
}
|
||||
@ -277,8 +277,8 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
(afl->start_time - afl->prev_run_time) / 1000, cur_time / 1000,
|
||||
(afl->prev_run_time + cur_time - afl->start_time) / 1000,
|
||||
(u32)getpid(), afl->queue_cycle ? (afl->queue_cycle - 1) : 0,
|
||||
afl->cycles_wo_finds, afl->fsrv.total_execs,
|
||||
afl->fsrv.total_execs /
|
||||
afl->cycles_wo_finds, total_execs_all(afl),
|
||||
total_execs_all(afl) /
|
||||
((double)(afl->prev_run_time + get_cur_time() - afl->start_time) /
|
||||
1000),
|
||||
afl->last_avg_execs_saved, afl->queued_paths, afl->queued_favored,
|
||||
@ -287,7 +287,7 @@ void write_stats_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
afl->queued_variable, stability, bitmap_cvg, afl->unique_crashes,
|
||||
afl->unique_hangs, afl->last_path_time / 1000,
|
||||
afl->last_crash_time / 1000, afl->last_hang_time / 1000,
|
||||
afl->fsrv.total_execs - afl->last_crash_execs, afl->fsrv.exec_tmout,
|
||||
total_execs_all(afl) - afl->last_crash_execs, afl->fsrv.exec_tmout,
|
||||
afl->slowest_exec_ms,
|
||||
#ifndef __HAIKU__
|
||||
#ifdef __APPLE__
|
||||
@ -367,7 +367,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
afl->plot_prev_uc == afl->unique_crashes &&
|
||||
afl->plot_prev_uh == afl->unique_hangs &&
|
||||
afl->plot_prev_md == afl->max_depth &&
|
||||
afl->plot_prev_ed == afl->fsrv.total_execs) ||
|
||||
afl->plot_prev_ed == total_execs_all(afl)) ||
|
||||
!afl->queue_cycle ||
|
||||
get_cur_time() - afl->start_time <= 60000))) {
|
||||
|
||||
@ -383,7 +383,7 @@ void maybe_update_plot_file(afl_state_t *afl, u32 t_bytes, double bitmap_cvg,
|
||||
afl->plot_prev_uc = afl->unique_crashes;
|
||||
afl->plot_prev_uh = afl->unique_hangs;
|
||||
afl->plot_prev_md = afl->max_depth;
|
||||
afl->plot_prev_ed = afl->fsrv.total_execs;
|
||||
afl->plot_prev_ed = total_execs_all(afl);
|
||||
|
||||
/* Fields in the file:
|
||||
|
||||
@ -451,7 +451,7 @@ void show_stats(afl_state_t *afl) {
|
||||
|
||||
if (afl->most_execs_key == 1) {
|
||||
|
||||
if (afl->most_execs <= afl->fsrv.total_execs) {
|
||||
if (afl->most_execs <= total_execs_all(afl)) {
|
||||
|
||||
afl->most_execs_key = 2;
|
||||
afl->stop_soon = 2;
|
||||
@ -479,7 +479,7 @@ void show_stats(afl_state_t *afl) {
|
||||
|
||||
if (likely(cur_ms != afl->start_time)) {
|
||||
|
||||
afl->stats_avg_exec = ((double)afl->fsrv.total_execs) * 1000 /
|
||||
afl->stats_avg_exec = ((double)total_execs_all(afl)) * 1000 /
|
||||
(afl->prev_run_time + cur_ms - afl->start_time);
|
||||
|
||||
}
|
||||
@ -489,7 +489,7 @@ void show_stats(afl_state_t *afl) {
|
||||
if (likely(cur_ms != afl->stats_last_ms)) {
|
||||
|
||||
double cur_avg =
|
||||
((double)(afl->fsrv.total_execs - afl->stats_last_execs)) * 1000 /
|
||||
((double)(total_execs_all(afl) - afl->stats_last_execs)) * 1000 /
|
||||
(cur_ms - afl->stats_last_ms);
|
||||
|
||||
/* If there is a dramatic (5x+) jump in speed, reset the indicator
|
||||
@ -510,7 +510,7 @@ void show_stats(afl_state_t *afl) {
|
||||
}
|
||||
|
||||
afl->stats_last_ms = cur_ms;
|
||||
afl->stats_last_execs = afl->fsrv.total_execs;
|
||||
afl->stats_last_execs = total_execs_all(afl);
|
||||
|
||||
/* Tell the callers when to contact us (as measured in execs). */
|
||||
|
||||
@ -518,6 +518,29 @@ void show_stats(afl_state_t *afl) {
|
||||
if (!afl->stats_update_freq) { afl->stats_update_freq = 1; }
|
||||
|
||||
/* Do some bitmap stats. */
|
||||
|
||||
u32 t_unusual_bits = 0, t_unusual_fav = 0;
|
||||
double t_unusual_ratio = 0.0;
|
||||
double t_unusual_fav_ratio = 0.0;
|
||||
|
||||
if (afl->shm.unusual_mode) {
|
||||
|
||||
u64 *current_begin = (u64 *)afl->shm.unusual->virgin;
|
||||
u64 *current = current_begin;
|
||||
u64 *current_end =
|
||||
(u64 *)(afl->shm.unusual->virgin + sizeof(afl->shm.unusual->virgin));
|
||||
for (; current < current_end; current += 8) {
|
||||
t_unusual_bits += __builtin_popcountll(~(long long)*current);
|
||||
}
|
||||
t_unusual_ratio = ((double)t_unusual_bits * 100) / UNUSUAL_MAP_SIZE;
|
||||
|
||||
u32 i;
|
||||
for (i = 0; i < UNUSUAL_MAP_SIZE; i++) {
|
||||
if (afl->top_rated_unusual[i]) ++t_unusual_fav;
|
||||
}
|
||||
t_unusual_fav_ratio = ((double)t_unusual_fav * 100) / UNUSUAL_MAP_SIZE;
|
||||
|
||||
}
|
||||
|
||||
t_bytes = count_non_255_bytes(afl, afl->virgin_bits);
|
||||
t_byte_ratio = ((double)t_bytes * 100) / afl->fsrv.map_size;
|
||||
@ -635,17 +658,26 @@ void show_stats(afl_state_t *afl) {
|
||||
banner_pad = (79 - banner_len) / 2;
|
||||
memset(tmp, ' ', banner_pad);
|
||||
|
||||
char *learning_str = "", *learning_pad = " ";
|
||||
if (afl->shm.unusual_mode && afl->shm.unusual->learning) {
|
||||
|
||||
learning_str = ", learning";
|
||||
learning_pad = "";
|
||||
|
||||
}
|
||||
|
||||
#ifdef HAVE_AFFINITY
|
||||
sprintf(
|
||||
tmp + banner_pad,
|
||||
"%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]" cBLU " {%d}",
|
||||
"%s " cLCY VERSION cLGN " (%s) " cPIN "[%s%s]" cBLU " {%d}%s",
|
||||
afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
|
||||
afl->use_banner, afl->power_name, afl->cpu_aff);
|
||||
afl->use_banner, afl->power_name, learning_str, afl->cpu_aff,
|
||||
learning_pad);
|
||||
#else
|
||||
sprintf(
|
||||
tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s]",
|
||||
tmp + banner_pad, "%s " cLCY VERSION cLGN " (%s) " cPIN "[%s%s]%s",
|
||||
afl->crash_mode ? cPIN "peruvian were-rabbit" : cYEL "american fuzzy lop",
|
||||
afl->use_banner, afl->power_name);
|
||||
afl->use_banner, afl->power_name, learning_str, learning_pad);
|
||||
#endif /* HAVE_AFFINITY */
|
||||
|
||||
SAYF("\n%s\n", tmp);
|
||||
@ -780,9 +812,9 @@ void show_stats(afl_state_t *afl) {
|
||||
|
||||
SAYF(bV bSTOP " now processing : " cRST "%-16s " bSTG bV bSTOP, tmp);
|
||||
|
||||
sprintf(tmp, "%0.02f%% / %0.02f%%",
|
||||
sprintf(tmp, "%0.02f%% / %0.02f%% - %0.02f%% %0.02f%%",
|
||||
((double)afl->queue_cur->bitmap_size) * 100 / afl->fsrv.map_size,
|
||||
t_byte_ratio);
|
||||
t_byte_ratio, t_unusual_ratio, t_unusual_fav_ratio);
|
||||
|
||||
SAYF(" map density : %s%-21s" bSTG bV "\n",
|
||||
t_byte_ratio > 70
|
||||
@ -839,13 +871,13 @@ void show_stats(afl_state_t *afl) {
|
||||
|
||||
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
|
||||
" new crashes : %s%-22s" bSTG bV "\n",
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
|
||||
u_stringify_int(IB(0), total_execs_all(afl)), crash_color, tmp);
|
||||
|
||||
} else {
|
||||
|
||||
SAYF(bV bSTOP " total execs : " cRST "%-20s " bSTG bV bSTOP
|
||||
" total crashes : %s%-22s" bSTG bV "\n",
|
||||
u_stringify_int(IB(0), afl->fsrv.total_execs), crash_color, tmp);
|
||||
u_stringify_int(IB(0), total_execs_all(afl)), crash_color, tmp);
|
||||
|
||||
}
|
||||
|
||||
|
@ -234,8 +234,8 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) {
|
||||
snprintf(
|
||||
buff, bufflen, afl->statsd_metric_format,
|
||||
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
|
||||
afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
|
||||
afl->fsrv.total_execs /
|
||||
afl->cycles_wo_finds, tags, total_execs_all(afl), tags,
|
||||
total_execs_all(afl) /
|
||||
((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
|
||||
1000),
|
||||
tags, afl->queued_paths, tags, afl->queued_favored, tags,
|
||||
@ -252,8 +252,8 @@ int statsd_format_metric(afl_state_t *afl, char *buff, size_t bufflen) {
|
||||
snprintf(
|
||||
buff, bufflen, afl->statsd_metric_format, tags,
|
||||
afl->queue_cycle ? (afl->queue_cycle - 1) : 0, tags,
|
||||
afl->cycles_wo_finds, tags, afl->fsrv.total_execs, tags,
|
||||
afl->fsrv.total_execs /
|
||||
afl->cycles_wo_finds, tags, total_execs_all(afl), tags,
|
||||
total_execs_all(afl) /
|
||||
((double)(get_cur_time() + afl->prev_run_time - afl->start_time) /
|
||||
1000),
|
||||
tags, afl->queued_paths, tags, afl->queued_favored, tags,
|
||||
|
101
src/afl-fuzz-unusual.c
Normal file
101
src/afl-fuzz-unusual.c
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
american fuzzy lop++ - unusual 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-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
|
||||
|
||||
Shared code to handle the shared memory. This is used by the fuzzer
|
||||
as well the other components like afl-tmin, afl-showmap, etc...
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
|
||||
void unusual_exec_child(afl_forkserver_t *fsrv, char **argv) {
|
||||
|
||||
setenv("___AFL_DREI_VIER_GRENADIER___", "1", 1);
|
||||
|
||||
if (fsrv->qemu_mode) { setenv("AFL_DISABLE_LLVM_INSTRUMENTATION", "1", 0); }
|
||||
|
||||
if (!fsrv->qemu_mode && !fsrv->frida_mode &&
|
||||
argv[0] != fsrv->unusual_binary) {
|
||||
|
||||
argv[0] = fsrv->unusual_binary;
|
||||
|
||||
}
|
||||
|
||||
execv(argv[0], argv);
|
||||
|
||||
}
|
||||
|
||||
u8 common_fuzz_unusual_stuff(afl_state_t *afl, u8 *out_buf, u32 len) {
|
||||
|
||||
u8 fault;
|
||||
|
||||
unusual_values_state_reset(afl->shm.unusual);
|
||||
|
||||
write_to_testcase(afl, out_buf, len);
|
||||
|
||||
fault = fuzz_run_target(afl, &afl->unusual_fsrv, afl->fsrv.exec_tmout);
|
||||
|
||||
if (afl->stop_soon) { return 1; }
|
||||
|
||||
if (fault == FSRV_RUN_TMOUT) {
|
||||
|
||||
if (afl->subseq_tmouts++ > TMOUT_LIMIT) {
|
||||
|
||||
++afl->cur_skipped_paths;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
afl->subseq_tmouts = 0;
|
||||
|
||||
}
|
||||
|
||||
/* Users can hit us with SIGUSR1 to request the current input
|
||||
to be abandoned. */
|
||||
|
||||
if (afl->skip_requested) {
|
||||
|
||||
afl->skip_requested = 0;
|
||||
++afl->cur_skipped_paths;
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* This handles FAULT_ERROR for us: */
|
||||
|
||||
afl->queued_discovered += save_if_interesting(afl, out_buf, len, fault,
|
||||
!afl->shm.unusual->learning);
|
||||
|
||||
if (!(afl->stage_cur % afl->stats_update_freq) ||
|
||||
afl->stage_cur + 1 == afl->stage_max) {
|
||||
|
||||
show_stats(afl);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
155
src/afl-fuzz.c
155
src/afl-fuzz.c
@ -25,6 +25,7 @@
|
||||
|
||||
#include "afl-fuzz.h"
|
||||
#include "cmplog.h"
|
||||
#include "unusual.h"
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef USEMMAP
|
||||
@ -46,7 +47,8 @@ extern u64 time_spent_working;
|
||||
static void at_exit() {
|
||||
|
||||
s32 i, pid1 = 0, pid2 = 0;
|
||||
char *list[4] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR, NULL};
|
||||
char *list[] = {SHM_ENV_VAR, SHM_FUZZ_ENV_VAR, CMPLOG_SHM_ENV_VAR,
|
||||
UNUSUAL_SHM_ENV_VAR, NULL};
|
||||
char *ptr;
|
||||
|
||||
ptr = getenv(CPU_AFFINITY_ENV_VAR);
|
||||
@ -433,7 +435,8 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
while ((opt = getopt(
|
||||
argc, argv,
|
||||
"+b:B:c:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) > 0) {
|
||||
"+b:B:c:u:CdDe:E:hi:I:f:F:l:L:m:M:nNOo:p:RQs:S:t:T:UV:Wx:Z")) >
|
||||
0) {
|
||||
|
||||
switch (opt) {
|
||||
|
||||
@ -467,6 +470,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
case 'u': {
|
||||
|
||||
afl->shm.unusual_mode = 1;
|
||||
afl->unusual_binary = ck_strdup(optarg);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case 's': {
|
||||
|
||||
if (optarg == NULL) { FATAL("No valid seed provided. Got NULL."); }
|
||||
@ -1658,6 +1669,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->unusual_binary) {
|
||||
|
||||
if (afl->unicorn_mode || afl->fsrv.qemu_mode || afl->fsrv.frida_mode) {
|
||||
|
||||
FATAL(
|
||||
"CmpLog and Unicorn/QEMU/Frida mode are not compatible at the "
|
||||
"moment, sorry");
|
||||
|
||||
}
|
||||
|
||||
if (!afl->non_instrumented_mode) { check_binary(afl, afl->unusual_binary); }
|
||||
|
||||
}
|
||||
|
||||
check_binary(afl, argv[optind]);
|
||||
|
||||
#ifdef AFL_PERSISTENT_RECORD
|
||||
@ -1836,6 +1861,84 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
if (afl->unusual_binary) {
|
||||
|
||||
ACTF("Spawning unusual forkserver");
|
||||
afl_fsrv_init_dup(&afl->unusual_fsrv, &afl->fsrv);
|
||||
// TODO: this is semi-nice
|
||||
afl->unusual_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl->unusual_fsrv.qemu_mode = afl->fsrv.qemu_mode;
|
||||
afl->unusual_fsrv.frida_mode = afl->fsrv.frida_mode;
|
||||
afl->unusual_fsrv.unusual_binary = afl->unusual_binary;
|
||||
afl->unusual_fsrv.init_child_func = unusual_exec_child;
|
||||
|
||||
if ((map_size <= DEFAULT_SHMEM_SIZE ||
|
||||
afl->unusual_fsrv.map_size < map_size) &&
|
||||
!afl->non_instrumented_mode && !afl->fsrv.qemu_mode &&
|
||||
!afl->fsrv.frida_mode && !afl->unicorn_mode &&
|
||||
!afl->afl_env.afl_skip_bin_check) {
|
||||
|
||||
afl->unusual_fsrv.map_size = MAX(map_size, (u32)DEFAULT_SHMEM_SIZE);
|
||||
char vbuf[16];
|
||||
snprintf(vbuf, sizeof(vbuf), "%u", afl->unusual_fsrv.map_size);
|
||||
setenv("AFL_MAP_SIZE", vbuf, 1);
|
||||
|
||||
}
|
||||
|
||||
u32 new_map_size =
|
||||
afl_fsrv_get_mapsize(&afl->unusual_fsrv, 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 unusual", 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);
|
||||
if (afl->cmplog_binary) afl_fsrv_kill(&afl->cmplog_fsrv);
|
||||
afl_fsrv_kill(&afl->unusual_fsrv);
|
||||
afl_shm_deinit(&afl->shm);
|
||||
|
||||
afl->unusual_fsrv.map_size = new_map_size; // non-unusual 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);
|
||||
if (afl->cmplog_binary)
|
||||
afl->cmplog_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl->unusual_fsrv.trace_bits = afl->fsrv.trace_bits;
|
||||
afl_fsrv_start(&afl->fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
if (afl->cmplog_binary) {
|
||||
|
||||
afl_fsrv_start(&afl->cmplog_fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
}
|
||||
|
||||
afl_fsrv_start(&afl->unusual_fsrv, afl->argv, &afl->stop_soon,
|
||||
afl->afl_env.afl_debug_child);
|
||||
|
||||
}
|
||||
|
||||
OKF("Unusual forkserver successfully started");
|
||||
// afl->shm.unusual->learning = 1;
|
||||
|
||||
}
|
||||
|
||||
load_auto(afl);
|
||||
|
||||
if (extras_dir_cnt) {
|
||||
@ -1866,8 +1969,12 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
memset(afl->virgin_tmout, 255, map_size);
|
||||
memset(afl->virgin_crash, 255, map_size);
|
||||
|
||||
//if (afl->shm.unusual_mode) afl->shm.unusual->learning = 1;
|
||||
|
||||
perform_dry_run(afl);
|
||||
|
||||
//if (afl->shm.unusual_mode) afl->shm.unusual->learning = 0;
|
||||
|
||||
if (afl->q_testcase_max_cache_entries) {
|
||||
|
||||
@ -1956,6 +2063,14 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
OKF("Writing mutation introspection to '%s'", ifn);
|
||||
#endif
|
||||
|
||||
/*if (getenv("AFL_SKIP_START_LEARNING") && afl->shm.unusual_mode) {
|
||||
afl->shm.unusual->learning = 0;
|
||||
}*/
|
||||
|
||||
|
||||
afl->clear_screen = 1;
|
||||
show_stats(afl);
|
||||
|
||||
while (likely(!afl->stop_soon)) {
|
||||
|
||||
cull_queue(afl);
|
||||
@ -1972,6 +2087,23 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
|
||||
}
|
||||
|
||||
// Set learning with a given probability
|
||||
// TODO find a better policy
|
||||
/*if (afl->queue_cycle && afl->shm.unusual_mode) {
|
||||
|
||||
afl->shm.unusual->learning = rand_below(afl, 4) == 0;
|
||||
afl->clear_screen = 1;
|
||||
|
||||
}*/
|
||||
|
||||
/*if (afl->shm.unusual_mode && afl->queue_cycle) {
|
||||
|
||||
u8 prev_learning = afl->shm.unusual->learning;
|
||||
afl->shm.unusual->learning = !prev_learning;
|
||||
afl->clear_screen = 1;
|
||||
|
||||
}*/
|
||||
|
||||
++afl->queue_cycle;
|
||||
runs_in_current_cycle = (u32)-1;
|
||||
afl->cur_skipped_paths = 0;
|
||||
@ -2022,6 +2154,20 @@ int main(int argc, char **argv_orig, char **envp) {
|
||||
3600 */
|
||||
)) {
|
||||
|
||||
/*if (afl->shm.unusual_mode) {
|
||||
|
||||
afl->shm.unusual->learning = !afl->shm.unusual->learning;
|
||||
afl->clear_screen = 1;
|
||||
|
||||
}*/
|
||||
|
||||
/*if (afl->shm.unusual_mode && !prev_learning) {
|
||||
|
||||
afl->shm.unusual->learning = 1;
|
||||
afl->clear_screen = 1;
|
||||
|
||||
}*/
|
||||
|
||||
if (afl->use_splicing) {
|
||||
|
||||
++afl->cycles_wo_finds;
|
||||
@ -2265,8 +2411,7 @@ stop_fuzzing:
|
||||
#ifdef PROFILING
|
||||
SAYF(cYEL "[!] " cRST
|
||||
"Profiling information: %llu ms total work, %llu ns/run\n",
|
||||
time_spent_working / 1000000,
|
||||
time_spent_working / afl->fsrv.total_execs);
|
||||
time_spent_working / 1000000, time_spent_working / total_execs_all(afl));
|
||||
#endif
|
||||
|
||||
if (afl->is_main_node) {
|
||||
@ -2293,6 +2438,8 @@ stop_fuzzing:
|
||||
}
|
||||
|
||||
afl_fsrv_deinit(&afl->fsrv);
|
||||
if (afl->cmplog_binary) afl_fsrv_deinit(&afl->cmplog_fsrv);
|
||||
if (afl->unusual_binary) afl_fsrv_deinit(&afl->unusual_fsrv);
|
||||
|
||||
/* remove tmpfile */
|
||||
if (afl->tmp_dir != NULL && !afl->in_place_resume && afl->fsrv.out_file) {
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "hash.h"
|
||||
#include "sharedmem.h"
|
||||
#include "cmplog.h"
|
||||
#include "unusual.h"
|
||||
#include "list.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -130,6 +131,7 @@ void afl_shm_deinit(sharedmem_t *shm) {
|
||||
#else
|
||||
shmctl(shm->shm_id, IPC_RMID, NULL);
|
||||
if (shm->cmplog_mode) { shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); }
|
||||
shmctl(shm->unusual_shm_id, IPC_RMID, NULL);
|
||||
#endif
|
||||
|
||||
shm->map = NULL;
|
||||
@ -260,6 +262,28 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
}
|
||||
|
||||
if (shm->unusual_mode) {
|
||||
|
||||
shm->unusual_shm_id =
|
||||
shmget(IPC_PRIVATE, sizeof(struct unusual_values_state),
|
||||
IPC_CREAT | IPC_EXCL | DEFAULT_PERMISSION);
|
||||
|
||||
if (shm->unusual_shm_id < 0) {
|
||||
|
||||
shmctl(shm->shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
if (shm->cmplog_mode) {
|
||||
|
||||
shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
}
|
||||
|
||||
PFATAL("shmget() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!non_instrumented_mode) {
|
||||
|
||||
shm_str = alloc_printf("%d", shm->shm_id);
|
||||
@ -285,6 +309,16 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
}
|
||||
|
||||
if (shm->unusual_mode && !non_instrumented_mode) {
|
||||
|
||||
shm_str = alloc_printf("%d", shm->unusual_shm_id);
|
||||
|
||||
setenv(UNUSUAL_SHM_ENV_VAR, shm_str, 1);
|
||||
|
||||
ck_free(shm_str);
|
||||
|
||||
}
|
||||
|
||||
shm->map = shmat(shm->shm_id, NULL, 0);
|
||||
|
||||
if (shm->map == (void *)-1 || !shm->map) {
|
||||
@ -297,6 +331,12 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
}
|
||||
|
||||
if (shm->unusual_mode) {
|
||||
|
||||
shmctl(shm->unusual_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
}
|
||||
|
||||
PFATAL("shmat() failed");
|
||||
|
||||
}
|
||||
@ -311,12 +351,42 @@ u8 *afl_shm_init(sharedmem_t *shm, size_t map_size,
|
||||
|
||||
shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
if (shm->unusual_mode) {
|
||||
|
||||
shmctl(shm->unusual_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
}
|
||||
|
||||
PFATAL("shmat() failed");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (shm->unusual_mode) {
|
||||
|
||||
shm->unusual = shmat(shm->unusual_shm_id, NULL, 0);
|
||||
|
||||
if (shm->unusual == (void *)-1 || !shm->unusual) {
|
||||
|
||||
shmctl(shm->shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
if (shm->cmplog_mode) {
|
||||
|
||||
shmctl(shm->cmplog_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
}
|
||||
|
||||
shmctl(shm->unusual_shm_id, IPC_RMID, NULL); // do not leak shmem
|
||||
|
||||
PFATAL("shmat() failed");
|
||||
|
||||
}
|
||||
|
||||
unusual_values_state_init(shm->unusual);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
shm->map_size = map_size;
|
||||
|
Submodule unicorn_mode/unicornafl updated: 019b871539...fb2fc9f25d
Reference in New Issue
Block a user