Merge branch '420' into dev

This commit is contained in:
van Hauser
2024-02-08 14:51:13 +01:00
committed by GitHub
18 changed files with 1373 additions and 697 deletions

View File

@ -5,6 +5,7 @@ on:
branches: branches:
- stable - stable
- dev - dev
- 420
pull_request: pull_request:
branches: branches:
- dev # No need for stable-pull-request, as that equals dev-push - dev # No need for stable-pull-request, as that equals dev-push

View File

@ -471,8 +471,8 @@ src/afl-forkserver.o : $(COMM_HDR) src/afl-forkserver.c include/forkserver.h
src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h src/afl-sharedmem.o : $(COMM_HDR) src/afl-sharedmem.c include/sharedmem.h
$(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o $(CC) $(CFLAGS) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -c src/afl-sharedmem.c -o src/afl-sharedmem.o
afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o | test_x86 afl-fuzz: $(COMM_HDR) include/afl-fuzz.h $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) -lm $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) -Wno-shift-count-overflow $(AFL_FUZZ_FILES) src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o src/hashmap.c -o $@ $(PYFLAGS) $(LDFLAGS) -lm
afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86 afl-showmap: src/afl-showmap.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS) $(CC) $(CFLAGS) $(COMPILE_STATIC) $(CFLAGS_FLTO) $(SPECIAL_PERFORMANCE) src/$@.c src/afl-fuzz-mutators.c src/afl-fuzz-python.c src/afl-common.o src/afl-sharedmem.o src/afl-forkserver.o src/afl-performance.o -o $@ $(PYFLAGS) $(LDFLAGS)

View File

@ -4,7 +4,7 @@
Release version: [4.10c](https://github.com/AFLplusplus/AFLplusplus/releases) Release version: [4.10c](https://github.com/AFLplusplus/AFLplusplus/releases)
GitHub version: 4.10c GitHub version: 4.20a
Repository: Repository:
[https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus) [https://github.com/AFLplusplus/AFLplusplus](https://github.com/AFLplusplus/AFLplusplus)

View File

@ -3,6 +3,16 @@
This is the list of all noteworthy changes made in every public This is the list of all noteworthy changes made in every public
release of the tool. See README.md for the general instruction manual. release of the tool. See README.md for the general instruction manual.
### Version ++4.20a (dev)
- afl-fuzz:
- the new deterministic fuzzing feature is now activated by default,
deactivate with -z. Parameters -d and -D are ignored.
- afl-cc:
- added collision free caller instrumentation to LTO mode. activate with
`AFL_LLVM_LTO_CALLER=1`. You can set a max depth to go through single
block functions with `AFL_LLVM_LTO_CALLER_DEPTH` (default 0)
### Version ++4.10c (release) ### Version ++4.10c (release)
- afl-fuzz: - afl-fuzz:
- default power schedule is now EXPLORE, due a fix in fast schedules - default power schedule is now EXPLORE, due a fix in fast schedules

View File

@ -248,6 +248,9 @@ use (which only ever the author of this LTO implementation will use). These are
used if several separated instrumentations are performed which are then later used if several separated instrumentations are performed which are then later
combined. combined.
- `AFL_LLVM_LTO_CALLER` activates collision free CALLER instrumentation
- `AFL_LLVM_LTO_CALLER` sets the maximum mumber of single block functions
to dig deeper into a real function. Default 0.
- `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given - `AFL_LLVM_DOCUMENT_IDS=file` will document to a file which edge ID was given
to which function. This helps to identify functions with variable bytes or to which function. This helps to identify functions with variable bytes or
which functions were touched by an input. which functions were touched by an input.

View File

@ -38,18 +38,16 @@
#define SHAPE_BYTES(x) (x + 1) #define SHAPE_BYTES(x) (x + 1)
#define CMP_TYPE_INS 1 #define CMP_TYPE_INS 0
#define CMP_TYPE_RTN 2 #define CMP_TYPE_RTN 1
struct cmp_header { struct cmp_header {
unsigned hits : 24; unsigned hits : 6; // up to 63 entries, we have CMP_MAP_H = 32
unsigned id : 24; unsigned shape : 5; // 31+1 bytes
unsigned shape : 5; unsigned type : 1; // 4, we use 3: none, rtn, cmp
unsigned type : 2; unsigned attribute : 4; // 16 for arithmetic comparison types
unsigned attribute : 4; //unsigned reserved : 6;
unsigned overflow : 1;
unsigned reserved : 4;
} __attribute__((packed)); } __attribute__((packed));
@ -59,14 +57,17 @@ struct cmp_operands {
u64 v1; u64 v1;
u64 v0_128; u64 v0_128;
u64 v1_128; u64 v1_128;
u64 unused;
u8 unused1;
u8 unused2;
} __attribute__((packed)); } __attribute__((packed));
struct cmpfn_operands { struct cmpfn_operands {
u8 v0[31]; u8 v0[32];
u8 v0_len; u8 v0_len;
u8 v1[31]; u8 v1[32];
u8 v1_len; u8 v1_len;
} __attribute__((packed)); } __attribute__((packed));

View File

@ -21,7 +21,7 @@ static char *afl_environment_variables[] = {
"AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER", "AFL_BENCH_UNTIL_CRASH", "AFL_CAL_FAST", "AFL_CC", "AFL_CC_COMPILER",
"AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW", "AFL_CMIN_ALLOW_ANY", "AFL_CMIN_CRASHES_ONLY", "AFL_CMPLOG_ONLY_NEW",
"AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME", "AFL_CODE_END", "AFL_CODE_START", "AFL_COMPCOV_BINNAME",
"AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE", "AFL_CMPLOG_MAX_LEN", "AFL_COMPCOV_LEVEL", "AFL_CRASH_EXITCODE",
"AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY", "AFL_CRASHING_SEEDS_AS_NEW_CRASH", "AFL_CUSTOM_MUTATOR_LIBRARY",
"AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM", "AFL_CUSTOM_MUTATOR_ONLY", "AFL_CUSTOM_INFO_PROGRAM",
"AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT", "AFL_CUSTOM_INFO_PROGRAM_ARGV", "AFL_CUSTOM_INFO_PROGRAM_INPUT",

View File

@ -49,6 +49,14 @@ typedef uint128_t u128;
#define FS_ERROR_OLD_CMPLOG 32 #define FS_ERROR_OLD_CMPLOG 32
#define FS_ERROR_OLD_CMPLOG_QEMU 64 #define FS_ERROR_OLD_CMPLOG_QEMU 64
/* New Forkserver */
#define FS_NEW_VERSION_MIN 1
#define FS_NEW_VERSION_MAX 1
#define FS_NEW_ERROR 0xeffe0000
#define FS_NEW_OPT_MAPSIZE 0x00000001 // parameter: 32 bit value
#define FS_NEW_OPT_SHDMEM_FUZZ 0x00000002 // parameter: none
#define FS_NEW_OPT_AUTODICT 0x00000800 // autodictionary data
/* Reporting options */ /* Reporting options */
#define FS_OPT_ENABLED 0x80000001 #define FS_OPT_ENABLED 0x80000001
#define FS_OPT_MAPSIZE 0x40000000 #define FS_OPT_MAPSIZE 0x40000000

File diff suppressed because it is too large Load Diff

View File

@ -190,6 +190,8 @@ __thread u32 __afl_prev_ctx;
struct cmp_map *__afl_cmp_map; struct cmp_map *__afl_cmp_map;
struct cmp_map *__afl_cmp_map_backup; struct cmp_map *__afl_cmp_map_backup;
static u8 __afl_cmplog_max_len = 32; // 16-32
/* Child pid? */ /* Child pid? */
static s32 child_pid; static s32 child_pid;
@ -268,7 +270,7 @@ static void send_forkserver_error(int error) {
u32 status; u32 status;
if (!error || error > 0xffff) return; if (!error || error > 0xffff) return;
status = (FS_OPT_ERROR | FS_OPT_SET_ERROR(error)); status = (FS_NEW_ERROR | error);
if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; } if (write(FORKSRV_FD + 1, (char *)&status, 4) != 4) { return; }
} }
@ -371,32 +373,13 @@ static void __afl_map_shm(void) {
if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); } if ((ptr = getenv("AFL_MAP_SIZE")) != NULL) { val = atoi(ptr); }
if (val < __afl_final_loc) { if (val < __afl_final_loc) {
if (__afl_final_loc > FS_OPT_MAX_MAPSIZE) { if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) {
if (!getenv("AFL_QUIET")) fprintf(stderr,
fprintf(stderr, "Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
"Error: AFL++ tools *require* to set AFL_MAP_SIZE to %u " "to be able to run this instrumented program if this "
"to be able to run this instrumented program!\n", "crashes!\n",
__afl_final_loc); __afl_final_loc);
if (id_str) {
send_forkserver_error(FS_ERROR_MAP_SIZE);
exit(-1);
}
} else {
if (__afl_final_loc > MAP_INITIAL_SIZE && !getenv("AFL_QUIET")) {
fprintf(stderr,
"Warning: AFL++ tools might need to set AFL_MAP_SIZE to %u "
"to be able to run this instrumented program if this "
"crashes!\n",
__afl_final_loc);
}
} }
@ -404,15 +387,6 @@ static void __afl_map_shm(void) {
} }
} else {
if (getenv("AFL_DUMP_MAP_SIZE")) {
printf("%u\n", MAP_SIZE);
exit(-1);
}
} }
if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) || if (__afl_sharedmem_fuzzing && (!id_str || !getenv(SHM_FUZZ_ENV_VAR) ||
@ -478,14 +452,13 @@ static void __afl_map_shm(void) {
if (__afl_debug) { if (__afl_debug) {
fprintf( fprintf(stderr,
stderr, "DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"DEBUG: (1) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE %u, " "__afl_final_loc %u, __afl_map_size %u\n",
"__afl_final_loc %u, __afl_map_size %u, max_size_forkserver %u/0x%x\n", id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
id_str == NULL ? "<null>" : id_str, __afl_area_ptr, __afl_area_initial, __afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, __afl_final_loc, __afl_final_loc, __afl_map_size);
__afl_map_size, FS_OPT_MAX_MAPSIZE, FS_OPT_MAX_MAPSIZE);
} }
@ -643,12 +616,10 @@ static void __afl_map_shm(void) {
fprintf(stderr, fprintf(stderr,
"DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, " "DEBUG: (2) id_str %s, __afl_area_ptr %p, __afl_area_initial %p, "
"__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE " "__afl_area_ptr_dummy %p, __afl_map_addr 0x%llx, MAP_SIZE "
"%u, __afl_final_loc %u, __afl_map_size %u, " "%u, __afl_final_loc %u, __afl_map_size %u",
"max_size_forkserver %u/0x%x\n",
id_str == NULL ? "<null>" : id_str, __afl_area_ptr, id_str == NULL ? "<null>" : id_str, __afl_area_ptr,
__afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE, __afl_area_initial, __afl_area_ptr_dummy, __afl_map_addr, MAP_SIZE,
__afl_final_loc, __afl_map_size, FS_OPT_MAX_MAPSIZE, __afl_final_loc, __afl_map_size);
FS_OPT_MAX_MAPSIZE);
} }
@ -765,6 +736,19 @@ static void __afl_map_shm(void) {
#endif // __AFL_CODE_COVERAGE #endif // __AFL_CODE_COVERAGE
if (!__afl_cmp_map && getenv("AFL_CMPLOG_DEBUG")) {
__afl_cmp_map_backup = __afl_cmp_map = malloc(sizeof(struct cmp_map));
}
if (getenv("AFL_CMPLOG_MAX_LEN")) {
int tmp = atoi(getenv("AFL_CMPLOG_MAX_LEN"));
if (tmp >= 16 && tmp <= 32) { __afl_cmplog_max_len = tmp; }
}
} }
/* unmap SHM. */ /* unmap SHM. */
@ -859,242 +843,6 @@ void write_error_with_location(char *text, char *filename, int linenumber) {
} }
#ifdef __linux__
static void __afl_start_snapshots(void) {
static u8 tmp[4] = {0, 0, 0, 0};
u32 status = 0;
u32 already_read_first = 0;
u32 was_killed;
u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
/* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */
status |= (FS_OPT_ENABLED | FS_OPT_SNAPSHOT | FS_OPT_NEWCMPLOG);
if (__afl_sharedmem_fuzzing) { status |= FS_OPT_SHDMEM_FUZZ; }
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE)
status |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
if (__afl_dictionary_len && __afl_dictionary) { status |= FS_OPT_AUTODICT; }
memcpy(tmp, &status, 4);
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; }
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
write_error("read to afl-fuzz");
_exit(1);
}
if (__afl_debug) {
fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed);
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) ==
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
__afl_map_shm_fuzz();
}
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) ==
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
__afl_dictionary_len && __afl_dictionary) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
s32 ret;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
}
while (len != 0) {
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
}
}
while (1) {
int status;
if (already_read_first) {
already_read_first = 0;
} else {
/* Wait for parent by reading from the pipe. Abort if read fails. */
if (read(FORKSRV_FD, &was_killed, 4) != 4) {
write_error("reading from afl-fuzz");
_exit(1);
}
}
#ifdef _AFL_DOCUMENT_MUTATIONS
if (__afl_fuzz_ptr) {
static uint32_t counter = 0;
char fn[32];
sprintf(fn, "%09u:forkserver", counter);
s32 fd_doc = open(fn, O_WRONLY | O_CREAT | O_TRUNC, DEFAULT_PERMISSION);
if (fd_doc >= 0) {
if (write(fd_doc, __afl_fuzz_ptr, *__afl_fuzz_len) != *__afl_fuzz_len) {
fprintf(stderr, "write of mutation file failed: %s\n", fn);
unlink(fn);
}
close(fd_doc);
}
counter++;
}
#endif
/* If we stopped the child in persistent mode, but there was a race
condition and afl-fuzz already issued SIGKILL, write off the old
process. */
if (child_stopped && was_killed) {
child_stopped = 0;
if (waitpid(child_pid, &status, 0) < 0) {
write_error("child_stopped && was_killed");
_exit(1); // TODO why exit?
}
}
if (!child_stopped) {
/* Once woken up, create a clone of our process. */
child_pid = fork();
if (child_pid < 0) {
write_error("fork");
_exit(1);
}
/* In child process: close fds, resume execution. */
if (!child_pid) {
//(void)nice(-20); // does not seem to improve
signal(SIGCHLD, old_sigchld_handler);
signal(SIGTERM, old_sigterm_handler);
close(FORKSRV_FD);
close(FORKSRV_FD + 1);
if (!afl_snapshot_take(AFL_SNAPSHOT_MMAP | AFL_SNAPSHOT_FDS |
AFL_SNAPSHOT_REGS | AFL_SNAPSHOT_EXIT)) {
raise(SIGSTOP);
}
__afl_area_ptr[0] = 1;
memset(__afl_prev_loc, 0, NGRAM_SIZE_MAX * sizeof(PREV_LOC_T));
return;
}
} else {
/* Special handling for persistent mode: if the child is alive but
currently stopped, simply restart it with SIGCONT. */
kill(child_pid, SIGCONT);
child_stopped = 0;
}
/* In parent process: write PID to pipe, then wait for child. */
if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) {
write_error("write to afl-fuzz");
_exit(1);
}
if (waitpid(child_pid, &status, WUNTRACED) < 0) {
write_error("waitpid");
_exit(1);
}
/* In persistent mode, the child stops itself with SIGSTOP to indicate
a successful run. In this case, we want to wake it up without forking
again. */
if (WIFSTOPPED(status)) child_stopped = 1;
/* Relay wait status to pipe, then loop back. */
if (write(FORKSRV_FD + 1, &status, 4) != 4) {
write_error("writing to afl-fuzz");
_exit(1);
}
}
}
#endif
/* Fork server logic. */ /* Fork server logic. */
static void __afl_start_forkserver(void) { static void __afl_start_forkserver(void) {
@ -1107,114 +855,93 @@ static void __afl_start_forkserver(void) {
old_sigterm_handler = orig_action.sa_handler; old_sigterm_handler = orig_action.sa_handler;
signal(SIGTERM, at_exit); signal(SIGTERM, at_exit);
#ifdef __linux__
if (/*!is_persistent &&*/ !__afl_cmp_map && !getenv("AFL_NO_SNAPSHOT") &&
afl_snapshot_init() >= 0) {
__afl_start_snapshots();
return;
}
#endif
u8 tmp[4] = {0, 0, 0, 0};
u32 status_for_fsrv = 0;
u32 already_read_first = 0; u32 already_read_first = 0;
u32 was_killed; u32 was_killed;
u32 version = 0x41464c00 + FS_NEW_VERSION_MAX;
u32 tmp = version ^ 0xffffffff, status2, status = version;
u8 *msg = (u8 *)&status;
u8 *reply = (u8 *)&status2;
u8 child_stopped = 0; u8 child_stopped = 0;
void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL); void (*old_sigchld_handler)(int) = signal(SIGCHLD, SIG_DFL);
if (__afl_map_size <= FS_OPT_MAX_MAPSIZE) {
status_for_fsrv |= (FS_OPT_SET_MAPSIZE(__afl_map_size) | FS_OPT_MAPSIZE);
}
if (__afl_dictionary_len && __afl_dictionary) {
status_for_fsrv |= FS_OPT_AUTODICT;
}
if (__afl_sharedmem_fuzzing) { status_for_fsrv |= FS_OPT_SHDMEM_FUZZ; }
if (status_for_fsrv) {
status_for_fsrv |= (FS_OPT_ENABLED | FS_OPT_NEWCMPLOG);
}
memcpy(tmp, &status_for_fsrv, 4);
/* Phone home and tell the parent that we're OK. If parent isn't there, /* Phone home and tell the parent that we're OK. If parent isn't there,
assume we're not running in forkserver mode and just execute program. */ assume we're not running in forkserver mode and just execute program. */
if (write(FORKSRV_FD + 1, tmp, 4) != 4) { return; } // return because possible non-forkserver usage
if (write(FORKSRV_FD + 1, msg, 4) != 4) { return; }
__afl_connected = 1; if (read(FORKSRV_FD, reply, 4) != 4) { _exit(1); }
if (tmp != status2) {
if (__afl_sharedmem_fuzzing || (__afl_dictionary_len && __afl_dictionary)) { write_error("wrong forkserver message from AFL++ tool");
_exit(1);
if (read(FORKSRV_FD, &was_killed, 4) != 4) _exit(1); }
if (__afl_debug) { // send the set/requested options to forkserver
status = FS_NEW_OPT_MAPSIZE; // we always send the map size
if (__afl_sharedmem_fuzzing) { status |= FS_NEW_OPT_SHDMEM_FUZZ; }
if (__afl_dictionary_len && __afl_dictionary) {
fprintf(stderr, "DEBUG: target forkserver recv: %08x\n", was_killed); status |= FS_NEW_OPT_AUTODICT;
}
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// Now send the parameters for the set options, increasing by option number
// FS_NEW_OPT_MAPSIZE - we always send the map size
status = __afl_map_size;
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// FS_NEW_OPT_SHDMEM_FUZZ - no data
// FS_NEW_OPT_AUTODICT - send autodictionary
if (__afl_dictionary_len && __afl_dictionary) {
// pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1);
} }
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) == while (len != 0) {
(FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ)) {
__afl_map_shm_fuzz(); s32 ret;
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
} if (ret < 1) {
if ((was_killed & (FS_OPT_ENABLED | FS_OPT_AUTODICT)) == write_error("could not send dictionary");
(FS_OPT_ENABLED | FS_OPT_AUTODICT) &&
__afl_dictionary_len && __afl_dictionary) {
// great lets pass the dictionary through the forkserver FD
u32 len = __afl_dictionary_len, offset = 0;
if (write(FORKSRV_FD + 1, &len, 4) != 4) {
write(2, "Error: could not send dictionary len\n",
strlen("Error: could not send dictionary len\n"));
_exit(1); _exit(1);
} }
while (len != 0) { len -= ret;
offset += ret;
s32 ret;
ret = write(FORKSRV_FD + 1, __afl_dictionary + offset, len);
if (ret < 1) {
write(2, "Error: could not send dictionary\n",
strlen("Error: could not send dictionary\n"));
_exit(1);
}
len -= ret;
offset += ret;
}
} else {
// uh this forkserver does not understand extended option passing
// or does not want the dictionary
if (!__afl_fuzz_ptr) already_read_first = 1;
} }
} }
// send welcome message as final message
status = version;
if (write(FORKSRV_FD + 1, msg, 4) != 4) { _exit(1); }
// END forkserver handshake
__afl_connected = 1;
if (__afl_sharedmem_fuzzing) { __afl_map_shm_fuzz(); }
while (1) { while (1) {
int status; int status;
@ -1229,7 +956,7 @@ static void __afl_start_forkserver(void) {
if (read(FORKSRV_FD, &was_killed, 4) != 4) { if (read(FORKSRV_FD, &was_killed, 4) != 4) {
// write_error("read from afl-fuzz"); write_error("read from AFL++ tool");
_exit(1); _exit(1);
} }
@ -2234,7 +1961,8 @@ void __cmplog_ins_hook1(uint8_t arg1, uint8_t arg2, uint8_t attr) {
void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) { void __cmplog_ins_hook2(uint16_t arg1, uint16_t arg2, uint8_t attr) {
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2272,7 +2000,8 @@ void __cmplog_ins_hook4(uint32_t arg1, uint32_t arg2, uint8_t attr) {
// fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr); // fprintf(stderr, "hook4 arg0=%x arg1=%x attr=%u\n", arg1, arg2, attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2310,7 +2039,8 @@ void __cmplog_ins_hook8(uint64_t arg1, uint64_t arg2, uint8_t attr) {
// fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr); // fprintf(stderr, "hook8 arg0=%lx arg1=%lx attr=%u\n", arg1, arg2, attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2353,7 +2083,8 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
// (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1, // (u64)(arg1 >> 64), (u64)arg1, (u64)(arg2 >> 64), (u64)arg2, size + 1,
// attr); // attr);
if (unlikely(!__afl_cmp_map || arg1 == arg2)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(arg1 == arg2 || size > __afl_cmplog_max_len)) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2397,6 +2128,7 @@ void __cmplog_ins_hookN(uint128_t arg1, uint128_t arg2, uint8_t attr,
void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) { void __cmplog_ins_hook16(uint128_t arg1, uint128_t arg2, uint8_t attr) {
if (likely(!__afl_cmp_map)) return; if (likely(!__afl_cmp_map)) return;
if (16 > __afl_cmplog_max_len) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2590,13 +2322,25 @@ void __cmplog_rtn_hook_strn(u8 *ptr1, u8 *ptr2, u64 len) {
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len); // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (likely(!__afl_cmp_map)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(!len)) return; if (unlikely(!len || len > __afl_cmplog_max_len)) return;
int len0 = MIN(len, 31);
int len0 = MIN(len, 32);
int len1 = strnlen(ptr1, len0); int len1 = strnlen(ptr1, len0);
if (len1 < 31) len1 = area_is_valid(ptr1, len1 + 1); if (len1 <= 32) len1 = area_is_valid(ptr1, len1 + 1);
if (len1 > __afl_cmplog_max_len) len1 = 0;
int len2 = strnlen(ptr2, len0); int len2 = strnlen(ptr2, len0);
if (len2 < 31) len2 = area_is_valid(ptr2, len2 + 1); if (len2 <= 32) len2 = area_is_valid(ptr2, len2 + 1);
int l = MAX(len1, len2); if (len2 > __afl_cmplog_max_len) len2 = 0;
int l;
if (!len1)
l = len2;
else if (!len2)
l = len1;
else
l = MAX(len1, len2);
if (l < 2) return; if (l < 2) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
@ -2640,10 +2384,18 @@ void __cmplog_rtn_hook_str(u8 *ptr1, u8 *ptr2) {
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
if (likely(!__afl_cmp_map)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(!ptr1 || !ptr2)) return; if (unlikely(!ptr1 || !ptr2)) return;
int len1 = strnlen(ptr1, 30) + 1; int len1 = strnlen(ptr1, 31) + 1;
int len2 = strnlen(ptr2, 30) + 1; int len2 = strnlen(ptr2, 31) + 1;
int l = MAX(len1, len2); if (len1 > __afl_cmplog_max_len) len1 = 0;
if (l < 3) return; if (len2 > __afl_cmplog_max_len) len2 = 0;
int l;
if (!len1)
l = len2;
else if (!len2)
l = len1;
else
l = MAX(len1, len2);
if (l < 2) return;
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));
@ -2685,7 +2437,7 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
/* /*
u32 i; u32 i;
if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return; if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn arg0="); fprintf(stderr, "rtn arg0=");
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
fprintf(stderr, "%02x", ptr1[i]); fprintf(stderr, "%02x", ptr1[i]);
@ -2698,10 +2450,10 @@ void __cmplog_rtn_hook(u8 *ptr1, u8 *ptr2) {
// fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2); // fprintf(stderr, "RTN1 %p %p\n", ptr1, ptr2);
if (likely(!__afl_cmp_map)) return; if (likely(!__afl_cmp_map)) return;
int l1, l2; int l1, l2;
if ((l1 = area_is_valid(ptr1, 31)) <= 0 || if ((l1 = area_is_valid(ptr1, 32)) <= 0 ||
(l2 = area_is_valid(ptr2, 31)) <= 0) (l2 = area_is_valid(ptr2, 32)) <= 0)
return; return;
int len = MIN(31, MIN(l1, l2)); int len = MIN(__afl_cmplog_max_len, MIN(l1, l2));
// fprintf(stderr, "RTN2 %u\n", len); // fprintf(stderr, "RTN2 %u\n", len);
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
@ -2750,7 +2502,7 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) {
#if 0 #if 0
/* /*
u32 i; u32 i;
if (area_is_valid(ptr1, 31) <= 0 || area_is_valid(ptr2, 31) <= 0) return; if (area_is_valid(ptr1, 32) <= 0 || area_is_valid(ptr2, 32) <= 0) return;
fprintf(stderr, "rtn_n len=%u arg0=", len); fprintf(stderr, "rtn_n len=%u arg0=", len);
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
fprintf(stderr, "%02x", ptr1[i]); fprintf(stderr, "%02x", ptr1[i]);
@ -2762,12 +2514,15 @@ void __cmplog_rtn_hook_n(u8 *ptr1, u8 *ptr2, u64 len) {
// fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len); // fprintf(stderr, "RTN1 %p %p %u\n", ptr1, ptr2, len);
if (likely(!__afl_cmp_map)) return; if (likely(!__afl_cmp_map)) return;
if (unlikely(!len)) return; if (!len) return;
int l = MIN(31, len); int l = MIN(32, len), l1, l2;
if ((l = area_is_valid(ptr1, l)) <= 0 || (l = area_is_valid(ptr2, l)) <= 0) if ((l1 = area_is_valid(ptr1, l)) <= 0 || (l2 = area_is_valid(ptr2, l)) <= 0)
return; return;
len = MIN(l1, l2);
if (len > __afl_cmplog_max_len) return;
// fprintf(stderr, "RTN2 %u\n", l); // fprintf(stderr, "RTN2 %u\n", l);
uintptr_t k = (uintptr_t)__builtin_return_address(0); uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1)); k = (uintptr_t)(default_hash((u8 *)&k, sizeof(uintptr_t)) & (CMP_MAP_W - 1));

View File

@ -1148,12 +1148,16 @@ static void instrument_opt_mode_exclude(aflcc_state_t *aflcc) {
} }
if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM) if (aflcc->instrument_opt_mode && aflcc->compiler_mode != LLVM &&
!((aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER) &&
aflcc->compiler_mode == LTO))
FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode"); FATAL("CTX, CALLER and NGRAM can only be used in LLVM mode");
if (aflcc->instrument_opt_mode && if (aflcc->instrument_opt_mode &&
aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV && aflcc->instrument_opt_mode != INSTRUMENT_OPT_CODECOV &&
aflcc->instrument_mode != INSTRUMENT_CLASSIC) aflcc->instrument_mode != INSTRUMENT_CLASSIC &&
!(aflcc->instrument_opt_mode & INSTRUMENT_OPT_CALLER &&
aflcc->compiler_mode == LTO))
FATAL( FATAL(
"CALLER, CTX and NGRAM instrumentation options can only be used with " "CALLER, CTX and NGRAM instrumentation options can only be used with "
"the LLVM CLASSIC instrumentation mode."); "the LLVM CLASSIC instrumentation mode.");
@ -2917,11 +2921,12 @@ static void maybe_usage(aflcc_state_t *aflcc, int argc, char **argv) {
" AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding " " AFL_LLVM_DOCUMENT_IDS: write all edge IDs and the corresponding "
"functions\n" "functions\n"
" into this file (LTO mode)\n" " into this file (LTO mode)\n"
" AFL_LLVM_LTO_CALLER: activate CALLER/CTX instrumentation\n"
" AFL_LLVM_LTO_CALLER_DEPTH: skip how many empty functions\n"
" AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a " " AFL_LLVM_LTO_DONTWRITEID: don't write the highest ID used to a "
"global var\n" "global var\n"
" AFL_LLVM_LTO_STARTID: from which ID to start counting from for " " AFL_LLVM_LTO_STARTID: from which ID to start counting from for "
"a " "a bb\n"
"bb\n"
" AFL_REAL_LD: use this lld linker instead of the compiled in " " AFL_REAL_LD: use this lld linker instead of the compiled in "
"path\n" "path\n"
" AFL_LLVM_LTO_SKIPINIT: don't inject initialization code " " AFL_LLVM_LTO_SKIPINIT: don't inject initialization code "

View File

@ -389,7 +389,7 @@ static void afl_fauxsrv_execv(afl_forkserver_t *fsrv, char **argv) {
while (1) { while (1) {
uint32_t was_killed; uint32_t was_killed;
int status; u32 status;
/* Wait for parent by reading from the pipe. Exit if read fails. */ /* Wait for parent by reading from the pipe. Exit if read fails. */
@ -524,7 +524,7 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
volatile u8 *stop_soon_p, u8 debug_child_output) { volatile u8 *stop_soon_p, u8 debug_child_output) {
int st_pipe[2], ctl_pipe[2]; int st_pipe[2], ctl_pipe[2];
s32 status; u32 status;
s32 rlen; s32 rlen;
char *ignore_autodict = getenv("AFL_NO_AUTODICT"); char *ignore_autodict = getenv("AFL_NO_AUTODICT");
@ -1017,83 +1017,68 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
if (rlen == 4) { if (rlen == 4) {
/*
* The new fork server model works like this:
* Client: sends "AFLx" in little endian, with x being the forkserver
* protocol version.
* Server: replies with XOR of the message or exits with an error if it
* is not a supported version.
* Client: sends 32 bit of options and then sends all parameters of
* the options, one after another, increasing by option number.
* Ends with "AFLx".
* After the initial protocol version confirmation the server does not
* send any data anymore - except a future option requires this.
*/
if ((status & FS_NEW_ERROR) == FS_NEW_ERROR) {
report_error_and_exit(status & 0x0000ffff);
}
if (status >= 0x41464c00 && status <= 0x41464cff) { if (status >= 0x41464c00 && status <= 0x41464cff) {
FATAL( u32 version = status - 0x41464c00;
"Target uses the new forkserver model, you need to switch to a newer "
"afl-fuzz too!");
} if (!version) {
if (!be_quiet) { OKF("All right - fork server is up."); } FATAL(
"Fork server version is not assigned, this should not happen. "
"Recompile target.");
if (getenv("AFL_DEBUG")) { } else if (version < FS_NEW_VERSION_MIN || version > FS_NEW_VERSION_MAX) {
ACTF("Extended forkserver functions received (%08x).", status); FATAL(
"Fork server version is not not supported. Recompile the target.");
}
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
// workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) == FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
if (fsrv->qemu_mode || fsrv->frida_mode) {
report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
} else {
report_error_and_exit(FS_ERROR_OLD_CMPLOG);
}
} }
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) { u32 keep = status;
status ^= 0xffffffff;
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
fsrv->snapshot = 1; FATAL("Writing to forkserver failed.");
if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
} }
if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) { if (!be_quiet) {
if (fsrv->support_shmem_fuzz) { OKF("All right - new fork server model v%u is up.", version);
fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
}
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
} }
if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) { rlen = read(fsrv->fsrv_st_fd, &status, 4);
u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status); if (getenv("AFL_DEBUG")) {
ACTF("Forkserver options received: (0x%08x)", status);
}
if ((status & FS_NEW_OPT_MAPSIZE)) {
u32 tmp_map_size;
rlen = read(fsrv->fsrv_st_fd, &tmp_map_size, 4);
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; } if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
@ -1110,7 +1095,8 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
FATAL( FATAL(
"Target's coverage map size of %u is larger than the one this " "Target's coverage map size of %u is larger than the one this "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and restart " "AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
"restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile " " afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz", "afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size); tmp_map_size, fsrv->map_size, tmp_map_size);
@ -1119,22 +1105,242 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
fsrv->map_size = tmp_map_size; fsrv->map_size = tmp_map_size;
} else {
fsrv->real_map_size = fsrv->map_size = MAP_SIZE;
} }
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) { if ((status & FS_NEW_OPT_SHDMEM_FUZZ)) {
if (!ignore_autodict) { if (fsrv->support_shmem_fuzz) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) { fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
}
if ((status & FS_NEW_OPT_AUTODICT)) {
u32 dict_size;
if (read(fsrv->fsrv_st_fd, &dict_size, 4) != 4) {
FATAL("Reading from forkserver failed.");
}
if (dict_size < 2 || dict_size > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", dict_size);
}
u32 offset = 0, count = 0;
u8 *dict = ck_alloc(dict_size);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory",
dict_size);
}
while (dict_size != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, dict_size);
if (rlen > 0) {
dict_size -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, dict_size);
}
}
offset = 0;
while (offset < dict_size && (u8)dict[offset] + offset < dict_size) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
}
u32 status2;
rlen = read(fsrv->fsrv_st_fd, &status2, 4);
if (status2 != keep) {
FATAL("Error in forkserver communication (%08x=>%08x)", keep, status2);
}
} else {
WARNF(
"Old fork server model is used by the target, this still works "
"though.");
if (!be_quiet) { OKF("All right - old fork server is up."); }
if (getenv("AFL_DEBUG")) {
ACTF("Extended forkserver functions received (%08x).", status);
}
if ((status & FS_OPT_ERROR) == FS_OPT_ERROR)
report_error_and_exit(FS_OPT_GET_ERROR(status));
if (fsrv->cmplog_binary) {
FATAL("Target was recompiled with outdated CMPLOG, recompile it!\n");
}
if ((status & FS_OPT_ENABLED) == FS_OPT_ENABLED) {
// workaround for recent AFL++ versions
if ((status & FS_OPT_OLD_AFLPP_WORKAROUND) ==
FS_OPT_OLD_AFLPP_WORKAROUND)
status = (status & 0xf0ffffff);
if ((status & FS_OPT_NEWCMPLOG) == 0 && fsrv->cmplog_binary) {
if (fsrv->qemu_mode || fsrv->frida_mode) {
report_error_and_exit(FS_ERROR_OLD_CMPLOG_QEMU);
} else {
report_error_and_exit(FS_ERROR_OLD_CMPLOG);
}
}
if ((status & FS_OPT_SNAPSHOT) == FS_OPT_SNAPSHOT) {
fsrv->snapshot = 1;
if (!be_quiet) { ACTF("Using SNAPSHOT feature."); }
}
if ((status & FS_OPT_SHDMEM_FUZZ) == FS_OPT_SHDMEM_FUZZ) {
if (fsrv->support_shmem_fuzz) {
fsrv->use_shmem_fuzz = 1;
if (!be_quiet) { ACTF("Using SHARED MEMORY FUZZING feature."); }
if ((status & FS_OPT_AUTODICT) == 0 || ignore_autodict) {
u32 send_status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
if (write(fsrv->fsrv_ctl_fd, &send_status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
}
} else {
FATAL(
"Target requested sharedmem fuzzing, but we failed to enable "
"it.");
}
}
if ((status & FS_OPT_MAPSIZE) == FS_OPT_MAPSIZE) {
u32 tmp_map_size = FS_OPT_GET_MAPSIZE(status);
if (!fsrv->map_size) { fsrv->map_size = MAP_SIZE; }
fsrv->real_map_size = tmp_map_size;
if (tmp_map_size % 64) {
tmp_map_size = (((tmp_map_size + 63) >> 6) << 6);
}
if (!be_quiet) { ACTF("Target map size: %u", fsrv->real_map_size); }
if (tmp_map_size > fsrv->map_size) {
FATAL(
"Target's coverage map size of %u is larger than the one this "
"AFL++ is set with (%u). Either set AFL_MAP_SIZE=%u and "
"restart "
" afl-fuzz, or change MAP_SIZE_POW2 in config.h and recompile "
"afl-fuzz",
tmp_map_size, fsrv->map_size, tmp_map_size);
}
fsrv->map_size = tmp_map_size;
}
if ((status & FS_OPT_AUTODICT) == FS_OPT_AUTODICT) {
if (!ignore_autodict) {
if (fsrv->add_extra_func == NULL || fsrv->afl_ptr == NULL) {
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
return;
}
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
// this is not afl-fuzz - or it is cmplog - we deny and return
if (fsrv->use_shmem_fuzz) { if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_SHDMEM_FUZZ); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else { } else {
status = (FS_OPT_ENABLED); status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
} }
@ -1144,82 +1350,63 @@ void afl_fsrv_start(afl_forkserver_t *fsrv, char **argv,
} }
return; if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
} FATAL("Reading from forkserver failed.");
if (!be_quiet) { ACTF("Using AUTODICT feature."); }
if (fsrv->use_shmem_fuzz) {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT | FS_OPT_SHDMEM_FUZZ);
} else {
status = (FS_OPT_ENABLED | FS_OPT_AUTODICT);
}
if (write(fsrv->fsrv_ctl_fd, &status, 4) != 4) {
FATAL("Writing to forkserver failed.");
}
if (read(fsrv->fsrv_st_fd, &status, 4) != 4) {
FATAL("Reading from forkserver failed.");
}
if (status < 2 || (u32)status > 0xffffff) {
FATAL("Dictionary has an illegal size: %d", status);
}
u32 offset = 0, count = 0;
u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory", len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
} }
} if (status < 2 || (u32)status > 0xffffff) {
offset = 0; FATAL("Dictionary has an illegal size: %d", status);
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1, }
(u8)dict[offset]);
offset += (1 + dict[offset]); u32 offset = 0, count = 0;
count++; u32 len = status;
u8 *dict = ck_alloc(len);
if (dict == NULL) {
FATAL("Could not allocate %u bytes of autodictionary memory",
len);
}
while (len != 0) {
rlen = read(fsrv->fsrv_st_fd, dict + offset, len);
if (rlen > 0) {
len -= rlen;
offset += rlen;
} else {
FATAL(
"Reading autodictionary fail at position %u with %u bytes "
"left.",
offset, len);
}
}
offset = 0;
while (offset < (u32)status &&
(u8)dict[offset] + offset < (u32)status) {
fsrv->add_extra_func(fsrv->afl_ptr, dict + offset + 1,
(u8)dict[offset]);
offset += (1 + dict[offset]);
count++;
}
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
} }
if (!be_quiet) { ACTF("Loaded %u autodictionary entries", count); }
ck_free(dict);
} }
} }

View File

@ -11,7 +11,7 @@
Andrea Fioraldi <andreafioraldi@gmail.com> Andrea Fioraldi <andreafioraldi@gmail.com>
Copyright 2016, 2017 Google Inc. All rights reserved. Copyright 2016, 2017 Google Inc. All rights reserved.
Copyright 2019-2024 AFLplusplus Project. All rights reserved. Copyright 2019-2023 AFLplusplus Project. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -87,6 +87,11 @@ static u32 hshape;
static u64 screen_update; static u64 screen_update;
static u64 last_update; static u64 last_update;
// hashmap functions
void hashmap_reset();
bool hashmap_search_and_add(uint8_t type, uint64_t key);
bool hashmap_search_and_add_ptr(uint8_t type, u8 *key);
static struct range *add_range(struct range *ranges, u32 start, u32 end) { static struct range *add_range(struct range *ranges, u32 start, u32 end) {
struct range *r = ck_alloc_nozero(sizeof(struct range)); struct range *r = ck_alloc_nozero(sizeof(struct range));
@ -795,7 +800,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
u64 *o_buf_64 = (u64 *)&orig_buf[idx]; u64 *o_buf_64 = (u64 *)&orig_buf[idx];
u32 *o_buf_32 = (u32 *)&orig_buf[idx]; u32 *o_buf_32 = (u32 *)&orig_buf[idx];
u16 *o_buf_16 = (u16 *)&orig_buf[idx]; u16 *o_buf_16 = (u16 *)&orig_buf[idx];
u8 *o_buf_8 = &orig_buf[idx]; // u8 *o_buf_8 = &orig_buf[idx];
u32 its_len = MIN(len - idx, taint_len); u32 its_len = MIN(len - idx, taint_len);
@ -836,6 +841,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
// necessary for preventing heap access overflow // necessary for preventing heap access overflow
bytes = MIN(bytes, len - idx); bytes = MIN(bytes, len - idx);
if (unlikely(bytes <= 1)) { return 0; }
// reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3 // reverse atoi()/strnu?toll() is expensive, so we only to it in lvl 3
if (afl->cmplog_enable_transform && (lvl & LVL3)) { if (afl->cmplog_enable_transform && (lvl & LVL3)) {
@ -1266,6 +1272,7 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
} }
/*
if (*status != 1) { // u8 if (*status != 1) { // u8
// if (its_len >= 1) // if (its_len >= 1)
@ -1290,6 +1297,8 @@ static u8 cmp_extend_encoding(afl_state_t *afl, struct cmp_header *h,
} }
*/
} }
// If 'S' is set for cmplog mode then we try a scale encoding of the value. // If 'S' is set for cmplog mode then we try a scale encoding of the value.
@ -1881,6 +1890,8 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
hshape = SHAPE_BYTES(h->shape); hshape = SHAPE_BYTES(h->shape);
if (hshape < 2) { return 0; }
if (h->hits > CMP_MAP_H) { if (h->hits > CMP_MAP_H) {
loggeds = CMP_MAP_H; loggeds = CMP_MAP_H;
@ -1906,8 +1917,6 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
#endif #endif
if (hshape < 2) { return 0; }
for (i = 0; i < loggeds; ++i) { for (i = 0; i < loggeds; ++i) {
struct cmp_operands *o = &afl->shm.cmp_map->log[key][i]; struct cmp_operands *o = &afl->shm.cmp_map->log[key][i];
@ -1945,6 +1954,16 @@ static u8 cmp_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
} }
// TODO: add attribute? not sure
if (hshape <= 8 && hashmap_search_and_add(hshape - 1, o->v0) &&
hashmap_search_and_add(hshape - 1, orig_o->v0) &&
hashmap_search_and_add(hshape - 1, o->v1) &&
hashmap_search_and_add(hshape - 1, orig_o->v1)) {
continue;
}
#ifdef _DEBUG #ifdef _DEBUG
fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n", fprintf(stderr, "Handling: %llx->%llx vs %llx->%llx attr=%u shape=%u\n",
orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape); orig_o->v0, o->v0, orig_o->v1, o->v1, h->attribute, hshape);
@ -2219,15 +2238,15 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
} }
if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 31 || l1 > 31 || if (l0 == 0 || l1 == 0 || ol0 == 0 || ol1 == 0 || l0 > 32 || l1 > 32 ||
ol0 > 31 || ol1 > 31) { ol0 > 32 || ol1 > 32) {
l0 = ol0 = hshape; l0 = ol0 = hshape;
} }
u8 lmax = MAX(l0, ol0); u8 lmax = MAX(l0, ol0);
u8 save[40]; u8 save[80];
u32 saved_idx = idx, pre, from = 0, to = 0, i, j; u32 saved_idx = idx, pre, from = 0, to = 0, i, j;
u32 its_len = MIN(MIN(lmax, hshape), len - idx); u32 its_len = MIN(MIN(lmax, hshape), len - idx);
its_len = MIN(its_len, taint_len); its_len = MIN(its_len, taint_len);
@ -2330,7 +2349,7 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
u32 tob64 = 0, fromb64 = 0; u32 tob64 = 0, fromb64 = 0;
u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0; u32 from_0 = 0, from_x = 0, from_X = 0, from_slash = 0, from_up = 0;
u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0; u32 to_0 = 0, to_x = 0, to_slash = 0, to_up = 0;
u8 xor_val[32], arith_val[32], tmp[48]; u8 xor_val[64], arith_val[64], tmp[64];
idx = saved_idx; idx = saved_idx;
its_len = saved_its_len; its_len = saved_its_len;
@ -2615,12 +2634,13 @@ static u8 rtn_extend_encoding(afl_state_t *afl, u8 entry,
} }
memcpy(buf + idx, tmp, hlen + 1 + off); u32 tmp_l = hlen + 1 + off;
memcpy(buf + idx, tmp, tmp_l);
if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; } if (unlikely(its_fuzz(afl, buf, len, status))) { return 1; }
tmp[hlen + 1 + off] = 0; tmp[tmp_l] = 0;
// fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result // fprintf(stderr, "RTN ATTEMPT idx=%u len=%u fromhex %u %s %s result
// %u\n", idx, len, fromhex, tmp, repl, *status); // %u\n", idx, len, fromhex, tmp, repl, *status);
memcpy(buf + idx, save, hlen + 1 + off); memcpy(buf + idx, save, tmp_l);
} }
@ -2755,6 +2775,15 @@ static u8 rtn_fuzz(afl_state_t *afl, u32 key, u8 *orig_buf, u8 *buf, u8 *cbuf,
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
if (hshape <= 8 && hashmap_search_and_add_ptr(hshape - 1, o->v0) &&
hashmap_search_and_add_ptr(hshape - 1, orig_o->v0) &&
hashmap_search_and_add_ptr(hshape - 1, o->v1) &&
hashmap_search_and_add_ptr(hshape - 1, orig_o->v1)) {
continue;
}
t = taint; t = taint;
while (t->next) { while (t->next) {
@ -3021,6 +3050,8 @@ u8 input_to_state_stage(afl_state_t *afl, u8 *orig_buf, u8 *buf, u32 len) {
// Start insertion loop // Start insertion loop
hashmap_reset();
u64 orig_hit_cnt, new_hit_cnt; u64 orig_hit_cnt, new_hit_cnt;
u64 orig_execs = afl->fsrv.total_execs; u64 orig_execs = afl->fsrv.total_execs;
orig_hit_cnt = afl->queued_items + afl->saved_crashes; orig_hit_cnt = afl->queued_items + afl->saved_crashes;

View File

@ -102,7 +102,7 @@ void afl_state_init(afl_state_t *afl, uint32_t map_size) {
afl->stats_update_freq = 1; afl->stats_update_freq = 1;
afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000; afl->stats_file_update_freq_msecs = STATS_UPDATE_SEC * 1000;
afl->stats_avg_exec = 0; afl->stats_avg_exec = 0;
afl->skip_deterministic = 1; afl->skip_deterministic = 0;
afl->sync_time = SYNC_TIME; afl->sync_time = SYNC_TIME;
afl->cmplog_lvl = 2; afl->cmplog_lvl = 2;
afl->min_length = 1; afl->min_length = 1;

View File

@ -1112,7 +1112,7 @@ void show_stats_normal(afl_state_t *afl) {
} else if (likely(afl->skip_deterministic)) { } else if (likely(afl->skip_deterministic)) {
strcpy(tmp, "disabled (default, enable with -D)"); strcpy(tmp, "disabled (-z switch used)");
} else { } else {

View File

@ -170,7 +170,6 @@ static void usage(u8 *argv0, int more_help) {
" -g minlength - set min length of generated fuzz input (default: 1)\n" " -g minlength - set min length of generated fuzz input (default: 1)\n"
" -G maxlength - set max length of generated fuzz input (default: " " -G maxlength - set max length of generated fuzz input (default: "
"%lu)\n" "%lu)\n"
" -D - enable (a new) effective deterministic fuzzing\n"
" -L minutes - use MOpt(imize) mode and set the time limit for " " -L minutes - use MOpt(imize) mode and set the time limit for "
"entering the\n" "entering the\n"
" pacemaker mode (minutes of no new finds). 0 = " " pacemaker mode (minutes of no new finds). 0 = "
@ -213,7 +212,8 @@ static void usage(u8 *argv0, int more_help) {
" -F path - sync to a foreign fuzzer queue directory (requires " " -F path - sync to a foreign fuzzer queue directory (requires "
"-M, can\n" "-M, can\n"
" be specified up to %u times)\n" " be specified up to %u times)\n"
// " -d - skip deterministic fuzzing in -M mode\n" " -z - skip the enhanced deterministic fuzzing\n"
" (note that the old -d and -D flags are ignored.)\n"
" -T text - text banner to show on the screen\n" " -T text - text banner to show on the screen\n"
" -I command - execute this command/script when a new crash is " " -I command - execute this command/script when a new crash is "
"found\n" "found\n"
@ -543,7 +543,7 @@ int main(int argc, char **argv_orig, char **envp) {
// still available: HjJkKqruvwz // still available: HjJkKqruvwz
while ((opt = getopt(argc, argv, while ((opt = getopt(argc, argv,
"+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:" "+a:Ab:B:c:CdDe:E:f:F:g:G:hi:I:l:L:m:M:nNo:Op:P:QRs:S:t:"
"T:UV:WXx:YZ")) > 0) { "T:UV:WXx:YzZ")) > 0) {
switch (opt) { switch (opt) {
@ -959,20 +959,17 @@ int main(int argc, char **argv_orig, char **envp) {
break; break;
case 'D': /* partial deterministic */ case 'd':
case 'D': /* old deterministic */
afl->skip_deterministic = 0; WARNF(
"Parameters -d and -D are deprecated, a new enhanced deterministic "
"fuzzing is active by default, to disable it use -z");
break; break;
case 'd': /* no deterministic */ case 'z': /* no deterministic */
// this is the default and currently a lot of infrastructure enforces afl->skip_deterministic = 1;
// it (e.g. clusterfuzz, fuzzbench) based on that this feature
// originally was bad performance wise. We now have a better
// implementation, hence if it is activated, we do not want to
// deactivate it by such setups.
// afl->skip_deterministic = 1;
break; break;
case 'B': /* load bitmap */ case 'B': /* load bitmap */

149
src/hashmap.c Normal file
View File

@ -0,0 +1,149 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "types.h"
#define TABLE_SIZE 10007 // Use a prime number for better distribution
typedef struct HashNode {
uint64_t key;
struct HashNode *next;
} HashNode;
typedef struct HashMap {
HashNode **table;
} HashMap;
static HashMap *_hashmap;
void hashmap_reset() {
if (unlikely(!_hashmap)) {
_hashmap = (HashMap *)malloc(sizeof(HashMap));
_hashmap->table = (HashNode **)malloc(sizeof(HashNode *) * TABLE_SIZE);
memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
} else {
for (int i = 0; i < TABLE_SIZE; i++) {
HashNode *node = _hashmap->table[i];
while (node) {
HashNode *temp = node;
node = node->next;
free(temp);
}
}
memset((char *)_hashmap->table, 0, sizeof(HashNode *) * TABLE_SIZE);
}
}
static inline unsigned int hash(uint64_t key) {
return key % TABLE_SIZE;
}
// type must be below 8
bool hashmap_search_and_add(uint8_t type, uint64_t key) {
if (unlikely(type >= 8)) return false;
uint64_t val = (key & 0xf8ffffffffffffff) + (type << 56);
unsigned int index = hash(val);
HashNode *node = _hashmap->table[index];
while (node) {
if (node->key == val) return true;
node = node->next;
}
// not found so add it
node = (HashNode *)malloc(sizeof(HashNode));
node->key = val;
node->next = _hashmap->table[index];
_hashmap->table[index] = node;
return false;
}
// type must be below 8
bool hashmap_search_and_add_ptr(uint8_t type, u8 *key) {
if (unlikely(type >= 8)) return false;
uint64_t key_t = 0;
memcpy(((char *)key_t) + (7 - type), key, type + 1);
return hashmap_search_and_add(type, key_t);
}
/* below is not used */
void hashmap_insert(uint64_t key) {
unsigned int index = hash(key);
HashNode *node = (HashNode *)malloc(sizeof(HashNode));
node->key = key;
node->next = _hashmap->table[index];
_hashmap->table[index] = node;
}
bool hashmap_search(uint64_t key) {
unsigned int index = hash(key);
HashNode *node = _hashmap->table[index];
while (node) {
if (node->key == key) return true;
node = node->next;
}
return false;
}
void delete(uint64_t key) {
unsigned int index = hash(key);
HashNode *prev = NULL, *node = _hashmap->table[index];
while (node) {
if (node->key == key) {
if (prev)
prev->next = node->next;
else
_hashmap->table[index] = node->next;
free(node);
return;
}
prev = node;
node = node->next;
}
}
void freeHashMap(HashMap *map) {
free(_hashmap->table);
free(map);
}

View File

@ -62,7 +62,7 @@ test -e ../afl-clang-fast -a -e ../split-switches-pass.so && {
$ECHO "$RED[!] llvm_mode threadsafe instrumentation failed" $ECHO "$RED[!] llvm_mode threadsafe instrumentation failed"
CODE=1 CODE=1
} }
rm -f test-instr.ts.0 test-instr.ts.1 rm -f test-instr.ts.0 test-instr.ts.1 test-instr.ts
} || { } || {
$ECHO "$RED[!] llvm_mode (threadsafe) failed" $ECHO "$RED[!] llvm_mode (threadsafe) failed"
CODE=1 CODE=1