aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvan Hauser <vh@thc.org>2019-07-14 20:04:26 +0200
committerGitHub <noreply@github.com>2019-07-14 20:04:26 +0200
commit054976c3903771e2267cfcf67f38fec3ced2ab77 (patch)
tree21e2f2e0bbe93341c3813d96576c5e83f62195d0
parent4a80dbdd10aedd3a3e70a0631aeb4e01438b634c (diff)
parentda8e03e18a1d01cb4ea26fc8efb25c4e7708a0b5 (diff)
downloadafl++-054976c3903771e2267cfcf67f38fec3ced2ab77.tar.gz
Merge pull request #14 from vanhauser-thc/shared_memory_mmap_refactor
Shared memory mmap refactor
-rw-r--r--Makefile77
-rw-r--r--afl-analyze.c85
-rw-r--r--afl-as.h46
-rw-r--r--afl-common.c69
-rw-r--r--afl-common.h5
-rw-r--r--afl-fuzz.c143
-rw-r--r--afl-gcc.c4
-rw-r--r--afl-showmap.c88
-rw-r--r--afl-tmin.c90
-rw-r--r--llvm_mode/Makefile64
-rw-r--r--llvm_mode/afl-clang-fast.c4
-rw-r--r--llvm_mode/afl-llvm-rt.o.c27
-rw-r--r--sharedmem.c137
-rw-r--r--sharedmem.h6
14 files changed, 480 insertions, 365 deletions
diff --git a/Makefile b/Makefile
index 0d0d6b79..60dfde18 100644
--- a/Makefile
+++ b/Makefile
@@ -13,6 +13,9 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
+# For Heiko:
+#TEST_MMAP=1
+
PROGNAME = afl
VERSION = $(shell grep '^\#define VERSION ' config.h | cut -d '"' -f2)
@@ -46,7 +49,8 @@ endif
COMM_HDR = alloc-inl.h config.h debug.h types.h
-ifeq "$(shell echo '\#include <Python.h>XXXvoid main() {}' | sed 's/XXX/\n/g' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 && echo 1 || echo 0 )" "1"
+
+ifeq "$(shell echo '\#include <Python.h>@int main() {return 0; }' | tr @ '\n' | $(CC) -x c - -o .test -I$(PYTHON_INCLUDE) -lpython2.7 2>/dev/null && echo 1 || echo 0 )" "1"
PYTHON_OK=1
PYFLAGS=-DUSE_PYTHON -I$(PYTHON_INCLUDE) -lpython2.7
else
@@ -54,15 +58,31 @@ else
PYFLAGS=
endif
-all: test_x86 test_python27 $(PROGS) afl-as test_build all_done
+
+ifeq "$(shell echo '\#include <sys/ipc.h>@\#include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 )" "1"
+ SHMAT_OK=1
+else
+ SHMAT_OK=0
+ CFLAGS+=-DUSEMMAP=1
+ LDFLAGS+=-Wno-deprecated-declarations -lrt
+endif
+
+ifeq "$(TEST_MMAP)" "1"
+ SHMAT_OK=0
+ CFLAGS+=-DUSEMMAP=1
+ LDFLAGS+=-Wno-deprecated-declarations -lrt
+endif
+
+
+all: test_x86 test_shm test_python27 ready $(PROGS) afl-as test_build all_done
+
ifndef AFL_NO_X86
test_x86:
@echo "[*] Checking for the ability to compile x86 code..."
- @echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
- @rm -f .test
- @echo "[+] Everything seems to be working, ready to compile."
+ @echo 'main() { __asm__("xorb %al, %al"); }' | $(CC) -w -x c - -o .test1 || ( echo; echo "Oops, looks like your compiler can't generate x86 code."; echo; echo "Don't panic! You can use the LLVM or QEMU mode, but see docs/INSTALL first."; echo "(To ignore this error, set AFL_NO_X86=1 and try again.)"; echo; exit 1 )
+ @rm -f .test1
else
@@ -71,6 +91,21 @@ test_x86:
endif
+
+ifeq "$(SHMAT_OK)" "1"
+
+test_shm:
+ @echo "[+] shmat seems to be working."
+ @rm -f .test2
+
+else
+
+test_shm:
+ @echo "[-] shmat seems not to be working, switching to mmap implementation"
+
+endif
+
+
ifeq "$(PYTHON_OK)" "1"
test_python27:
@@ -84,6 +119,10 @@ test_python27:
endif
+
+ready:
+ @echo "[+] Everything seems to be working, ready to compile."
+
afl-gcc: afl-gcc.c $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
set -e; for i in afl-g++ afl-clang afl-clang++; do ln -sf afl-gcc $$i; done
@@ -92,21 +131,28 @@ afl-as: afl-as.c afl-as.h $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
ln -sf afl-as as
-afl-fuzz: afl-fuzz.c $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS) $(PYFLAGS)
+afl-common.o : afl-common.c
+ $(CC) $(CFLAGS) -c afl-common.c
-afl-showmap: afl-showmap.c $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
+sharedmem.o : sharedmem.c
+ $(CC) $(CFLAGS) -c sharedmem.c
-afl-tmin: afl-tmin.c $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
+afl-fuzz: afl-fuzz.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS) $(PYFLAGS)
-afl-analyze: afl-analyze.c $(COMM_HDR) | test_x86
- $(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
+afl-showmap: afl-showmap.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS)
+
+afl-tmin: afl-tmin.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS)
+
+afl-analyze: afl-analyze.c afl-common.o sharedmem.o $(COMM_HDR) | test_x86
+ $(CC) $(CFLAGS) $@.c afl-common.o sharedmem.o -o $@ $(LDFLAGS)
afl-gotcpu: afl-gotcpu.c $(COMM_HDR) | test_x86
$(CC) $(CFLAGS) $@.c -o $@ $(LDFLAGS)
+
ifndef AFL_NO_X86
test_build: afl-gcc afl-as afl-showmap
@@ -125,16 +171,17 @@ test_build: afl-gcc afl-as afl-showmap
endif
+
all_done: test_build
@if [ ! "`which clang 2>/dev/null`" = "" ]; then echo "[+] LLVM users: see llvm_mode/README.llvm for a faster alternative to afl-gcc."; fi
- @echo "[+] All done! Be sure to review README - it's pretty short and useful."
+ @echo "[+] All done! Be sure to review the README - it's pretty short and useful."
@if [ "`uname`" = "Darwin" ]; then printf "\nWARNING: Fuzzing on MacOS X is slow because of the unusually high overhead of\nfork() on this OS. Consider using Linux or *BSD. You can also use VirtualBox\n(virtualbox.org) to put AFL inside a Linux or *BSD VM.\n\n"; fi
@! tty <&1 >/dev/null || printf "\033[0;30mNOTE: If you can read this, your terminal probably uses white background.\nThis will make the UI hard to read. See docs/status_screen.txt for advice.\033[0m\n" 2>/dev/null
.NOTPARALLEL: clean
clean:
- rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.0.tar.xz afl-qemu-trace
+ rm -f $(PROGS) afl-as as afl-g++ afl-clang afl-clang++ *.o *~ a.out core core.[1-9][0-9]* *.stackdump test .test .test1 .test2 test-instr .test-instr0 .test-instr1 qemu_mode/qemu-3.1.0.tar.xz afl-qemu-trace
rm -rf out_dir qemu_mode/qemu-3.1.0
$(MAKE) -C llvm_mode clean
$(MAKE) -C libdislocator clean
diff --git a/afl-analyze.c b/afl-analyze.c
index 44be73f9..be470317 100644
--- a/afl-analyze.c
+++ b/afl-analyze.c
@@ -26,6 +26,8 @@
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
+#include "sharedmem.h"
+#include "afl-common.h"
#include <stdio.h>
#include <unistd.h>
@@ -47,7 +49,7 @@
static s32 child_pid; /* PID of the tested program */
-static u8* trace_bits; /* SHM with instrumentation bitmap */
+ u8* trace_bits; /* SHM with instrumentation bitmap */
static u8 *in_file, /* Analyzer input test case */
*prog_in, /* Targeted program input file */
@@ -64,8 +66,7 @@ static u32 in_len, /* Input data length */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
-static s32 shm_id, /* ID of the SHM region */
- dev_null_fd = -1; /* FD to /dev/null */
+static s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 edges_only, /* Ignore hit counts? */
use_hex_offsets, /* Show hex offsets? */
@@ -76,6 +77,7 @@ static volatile u8
child_timed_out; /* Child timed out? */
+
/* Constants used for describing byte behavior. */
#define RESP_NONE 0x00 /* Changing byte is a no-op. */
@@ -141,37 +143,11 @@ static inline u8 anything_set(void) {
}
-/* Get rid of shared memory and temp files (atexit handler). */
+/* Get rid of temp files (atexit handler). */
-static void remove_shm(void) {
+static void at_exit_handler(void) {
unlink(prog_in); /* Ignore errors */
- shmctl(shm_id, IPC_RMID, NULL);
-
-}
-
-
-/* Configure shared memory. */
-
-static void setup_shm(void) {
-
- u8* shm_str;
-
- shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
-
- if (shm_id < 0) PFATAL("shmget() failed");
-
- atexit(remove_shm);
-
- shm_str = alloc_printf("%d", shm_id);
-
- setenv(SHM_ENV_VAR, shm_str, 1);
-
- ck_free(shm_str);
-
- trace_bits = shmat(shm_id, NULL, 0);
-
- if (!trace_bits) PFATAL("shmat() failed");
}
@@ -750,48 +726,6 @@ static void setup_signal_handlers(void) {
}
-/* Detect @@ in args. */
-
-static void detect_file_args(char** argv) {
-
- u32 i = 0;
- u8* cwd = getcwd(NULL, 0);
-
- if (!cwd) PFATAL("getcwd() failed");
-
- while (argv[i]) {
-
- u8* aa_loc = strstr(argv[i], "@@");
-
- if (aa_loc) {
-
- u8 *aa_subst, *n_arg;
-
- /* Be sure that we're always using fully-qualified paths. */
-
- if (prog_in[0] == '/') aa_subst = prog_in;
- else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
-
- /* Construct a replacement argv value. */
-
- *aa_loc = 0;
- n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
- argv[i] = n_arg;
- *aa_loc = '@';
-
- if (prog_in[0] != '/') ck_free(aa_subst);
-
- }
-
- i++;
-
- }
-
- free(cwd); /* not tracked */
-
-}
-
-
/* Display usage hints. */
static void usage(u8* argv0) {
@@ -1036,13 +970,14 @@ int main(int argc, char** argv) {
use_hex_offsets = !!getenv("AFL_ANALYZE_HEX");
- setup_shm();
+ setup_shm(0);
+ atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment();
find_binary(argv[optind]);
- detect_file_args(argv + optind);
+ detect_file_args(argv + optind, prog_in);
if (qemu_mode)
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
diff --git a/afl-as.h b/afl-as.h
index 9e91375d..4748eda7 100644
--- a/afl-as.h
+++ b/afl-as.h
@@ -221,6 +221,29 @@ static const u8* main_payload_32 =
" testl %eax, %eax\n"
" je __afl_setup_abort\n"
"\n"
+#ifdef USEMMAP
+ " pushl $384 /* shm_open mode 0600 */\n"
+ " pushl $2 /* flags O_RDWR */\n"
+ " pushl %eax /* SHM file path */\n"
+ " call shm_open\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $-1, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+ " pushl $0 /* mmap off */\n"
+ " pushl %eax /* shm fd */\n"
+ " pushl $1 /* mmap flags */\n"
+ " pushl $3 /* mmap prot */\n"
+ " pushl $"STRINGIFY(MAP_SIZE)" /* mmap len */\n"
+ " pushl $0 /* mmap addr */\n"
+ " call mmap\n"
+ " addl $12, %esp\n"
+ "\n"
+ " cmpl $-1, %eax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#else
" pushl %eax\n"
" call atoi\n"
" addl $4, %esp\n"
@@ -234,6 +257,7 @@ static const u8* main_payload_32 =
" cmpl $-1, %eax\n"
" je __afl_setup_abort\n"
"\n"
+#endif
" /* Store the address of the SHM region. */\n"
"\n"
" movl %eax, __afl_area_ptr\n"
@@ -503,6 +527,27 @@ static const u8* main_payload_64 =
" testq %rax, %rax\n"
" je __afl_setup_abort\n"
"\n"
+#ifdef USEMMAP
+ " movl $384, %edx /* shm_open mode 0600 */\n"
+ " movl $2, %esi /* flags O_RDWR */\n"
+ " movq %rax, %rdi /* SHM file path */\n"
+ CALL_L64("shm_open")
+ "\n"
+ " cmpq $-1, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+ " movl $0, %r9d\n"
+ " movl %eax, %r8d\n"
+ " movl $1, %ecx\n"
+ " movl $3, %edx\n"
+ " movl $"STRINGIFY(MAP_SIZE)", %esi\n"
+ " movl $0, %edi\n"
+ CALL_L64("mmap")
+ "\n"
+ " cmpq $-1, %rax\n"
+ " je __afl_setup_abort\n"
+ "\n"
+#else
" movq %rax, %rdi\n"
CALL_L64("atoi")
"\n"
@@ -514,6 +559,7 @@ static const u8* main_payload_64 =
" cmpq $-1, %rax\n"
" je __afl_setup_abort\n"
"\n"
+#endif
" /* Store the address of the SHM region. */\n"
"\n"
" movq %rax, %rdx\n"
diff --git a/afl-common.c b/afl-common.c
new file mode 100644
index 00000000..1c5e5bfe
--- /dev/null
+++ b/afl-common.c
@@ -0,0 +1,69 @@
+/*
+ gather some functions common to multiple executables
+
+ detect_file_args
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <strings.h>
+
+#include "debug.h"
+#include "alloc-inl.h"
+
+/* Detect @@ in args. */
+#ifndef __glibc__
+#include <unistd.h>
+#endif
+void detect_file_args(char** argv, u8* prog_in) {
+
+ u32 i = 0;
+#ifdef __GLIBC__
+ u8* cwd = getcwd(NULL, 0); /* non portable glibc extension */
+#else
+ u8* cwd;
+ char *buf;
+ long size = pathconf(".", _PC_PATH_MAX);
+ if ((buf = (char *)malloc((size_t)size)) != NULL) {
+ cwd = getcwd(buf, (size_t)size); /* portable version */
+ } else {
+ PFATAL("getcwd() failed");
+ }
+#endif
+
+ if (!cwd) PFATAL("getcwd() failed");
+
+ while (argv[i]) {
+
+ u8* aa_loc = strstr(argv[i], "@@");
+
+ if (aa_loc) {
+
+ u8 *aa_subst, *n_arg;
+
+ if (!prog_in) FATAL("@@ syntax is not supported by this tool.");
+
+ /* Be sure that we're always using fully-qualified paths. */
+
+ if (prog_in[0] == '/') aa_subst = prog_in;
+ else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
+
+ /* Construct a replacement argv value. */
+
+ *aa_loc = 0;
+ n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
+ argv[i] = n_arg;
+ *aa_loc = '@';
+
+ if (prog_in[0] != '/') ck_free(aa_subst);
+
+ }
+
+ i++;
+
+ }
+
+ free(cwd); /* not tracked */
+
+}
+
diff --git a/afl-common.h b/afl-common.h
new file mode 100644
index 00000000..07afb75d
--- /dev/null
+++ b/afl-common.h
@@ -0,0 +1,5 @@
+#ifndef __AFLCOMMON_H
+#define __AFLCOMMON_H
+
+void detect_file_args(char **argv, u8 *prog_in);
+#endif
diff --git a/afl-fuzz.c b/afl-fuzz.c
index d8d45223..b6645c0f 100644
--- a/afl-fuzz.c
+++ b/afl-fuzz.c
@@ -31,6 +31,8 @@
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
+#include "sharedmem.h"
+#include "afl-common.h"
#include <stdio.h>
#include <unistd.h>
@@ -223,7 +225,7 @@ static s32 forksrv_pid, /* PID of the fork server */
child_pid = -1, /* PID of the fuzzed program */
out_dir_fd = -1; /* FD of the lock file */
-EXP_ST u8* trace_bits; /* SHM with instrumentation bitmap */
+ u8* trace_bits; /* SHM with instrumentation bitmap */
EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */
@@ -231,8 +233,6 @@ EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
static u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */
-static s32 shm_id; /* ID of the SHM region */
-
static volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen = 1, /* Window resized? */
child_timed_out; /* Traced process timed out? */
@@ -1530,15 +1530,6 @@ static inline void classify_counts(u32* mem) {
#endif /* ^__x86_64__ */
-/* Get rid of shared memory (atexit handler). */
-
-static void remove_shm(void) {
-
- shmctl(shm_id, IPC_RMID, NULL);
-
-}
-
-
/* Compact trace bytes into a smaller bitmap. We effectively just drop the
count information here. This is called only sporadically, for some
new paths. */
@@ -1692,40 +1683,6 @@ static void cull_queue(void) {
}
-/* Configure shared memory and virgin_bits. This is called at startup. */
-
-EXP_ST void setup_shm(void) {
-
- u8* shm_str;
-
- if (!in_bitmap) memset(virgin_bits, 255, MAP_SIZE);
-
- memset(virgin_tmout, 255, MAP_SIZE);
- memset(virgin_crash, 255, MAP_SIZE);
-
- shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
-
- if (shm_id < 0) PFATAL("shmget() failed");
-
- atexit(remove_shm);
-
- shm_str = alloc_printf("%d", shm_id);
-
- /* If somebody is asking us to fuzz instrumented binaries in dumb mode,
- we don't want them to detect instrumentation, since we won't be sending
- fork server commands. This should be replaced with better auto-detection
- later on, perhaps? */
-
- if (!dumb_mode) setenv(SHM_ENV_VAR, shm_str, 1);
-
- ck_free(shm_str);
-
- trace_bits = shmat(shm_id, NULL, 0);
-
- if (!trace_bits) PFATAL("shmat() failed");
-
-}
-
/* Load postprocessor, if available. */
@@ -7549,20 +7506,16 @@ static u8 pilot_fuzzing(char** argv) {
stage_finds[STAGE_FLIP1] += new_hit_cnt - orig_hit_cnt;
stage_cycles[STAGE_FLIP1] += stage_max;
-
-
-
/* Two walking bits. */
stage_name = "bitflip 2/1";
stage_short = "flip2";
stage_max = (len << 3) - 1;
-
-
-
-
-
+#if !defined(__arm__) && !defined(__arm64__)
+ if (f_data[0] != 0xCF || f_data[1] != 0xFA || f_data[2] != 0xED)
+ FATAL("Program '%s' is not a 64-bit Mach-O binary", target_path);
+#endif
orig_hit_cnt = new_hit_cnt;
@@ -11828,58 +11781,6 @@ static void check_asan_opts(void) {
}
-/* Detect @@ in args. */
-
-EXP_ST void detect_file_args(char** argv) {
-
- u32 i = 0;
- u8* cwd = getcwd(NULL, 0);
-
- if (!cwd) PFATAL("getcwd() failed");
-
- while (argv[i]) {
-
- u8* aa_loc = strstr(argv[i], "@@");
-
- if (aa_loc) {
-
- u8 *aa_subst, *n_arg;
-
- /* If we don't have a file name chosen yet, use a safe default. */
-
- if (!out_file) {
- if (file_extension) {
- out_file = alloc_printf("%s/.cur_input.%s", out_dir, file_extension);
- } else {
- out_file = alloc_printf("%s/.cur_input", out_dir);
- }
- }
-
- /* Be sure that we're always using fully-qualified paths. */
-
- if (out_file[0] == '/') aa_subst = out_file;
- else aa_subst = alloc_printf("%s/%s", cwd, out_file);
-
- /* Construct a replacement argv value. */
-
- *aa_loc = 0;
- n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
- argv[i] = n_arg;
- *aa_loc = '@';
-
- if (out_file[0] != '/') ck_free(aa_subst);
-
- }
-
- i++;
-
- }
-
- free(cwd); /* not tracked */
-
-}
-
-
/* Set up signal handlers. More complicated that needs to be, because libc on
Solaris doesn't resume interrupted reads(), sets SA_RESETHAND when you call
siginterrupt(), and does other stupid things. */
@@ -12469,7 +12370,12 @@ int main(int argc, char** argv) {
check_cpu_governor();
setup_post();
- setup_shm();
+ setup_shm(dumb_mode);
+
+ if (!in_bitmap) memset(virgin_bits, 255, MAP_SIZE);
+ memset(virgin_tmout, 255, MAP_SIZE);
+ memset(virgin_crash, 255, MAP_SIZE);
+
init_count_class16();
setup_dirs_fds();
@@ -12495,7 +12401,28 @@ int main(int argc, char** argv) {
if (!timeout_given) find_timeout();
- detect_file_args(argv + optind + 1);
+ /* If we don't have a file name chosen yet, use a safe default. */
+
+ if (!out_file) {
+ u32 i = optind + 1;
+ while (argv[i]) {
+
+ u8* aa_loc = strstr(argv[i], "@@");
+
+ if (aa_loc && !out_file) {
+ if (file_extension) {
+ out_file = alloc_printf("%s/.cur_input.%s", out_dir, file_extension);
+ } else {
+ out_file = alloc_printf("%s/.cur_input", out_dir);
+ }
+ detect_file_args(argv + optind + 1, out_file);
+ break;
+ }
+
+ i++;
+
+ }
+ }
if (!out_file) setup_stdio_file();
diff --git a/afl-gcc.c b/afl-gcc.c
index 8d3988c7..467a9bc1 100644
--- a/afl-gcc.c
+++ b/afl-gcc.c
@@ -252,6 +252,10 @@ static void edit_params(u32 argc, char** argv) {
}
+#ifdef USEMMAP
+ cc_params[cc_par_cnt++] = "-lrt";
+#endif
+
if (!getenv("AFL_DONT_OPTIMIZE")) {
#if defined(__FreeBSD__) && defined(__x86_64__)
diff --git a/afl-showmap.c b/afl-showmap.c
index 316490d8..1382e5f0 100644
--- a/afl-showmap.c
+++ b/afl-showmap.c
@@ -28,6 +28,8 @@
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
+#include "sharedmem.h"
+#include "afl-common.h"
#include <stdio.h>
#include <unistd.h>
@@ -48,7 +50,7 @@
static s32 child_pid; /* PID of the tested program */
-static u8* trace_bits; /* SHM with instrumentation bitmap */
+ u8* trace_bits; /* SHM with instrumentation bitmap */
static u8 *out_file, /* Trace output file */
*doc_path, /* Path to docs */
@@ -59,8 +61,6 @@ static u32 exec_tmout; /* Exec timeout (ms) */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
-static s32 shm_id; /* ID of the SHM region */
-
static u8 quiet_mode, /* Hide non-essential messages? */
edges_only, /* Ignore hit counts? */
cmin_mode, /* Generate output in afl-cmin mode? */
@@ -72,6 +72,7 @@ static volatile u8
child_timed_out, /* Child timed out? */
child_crashed; /* Child crashed? */
+
/* Classify tuple counts. Instead of mapping to individual bits, as in
afl-fuzz.c, we map to more user-friendly numbers between 1 and 8. */
@@ -126,39 +127,6 @@ static void classify_counts(u8* mem, const u8* map) {
}
-/* Get rid of shared memory (atexit handler). */
-
-static void remove_shm(void) {
-
- shmctl(shm_id, IPC_RMID, NULL);
-
-}
-
-
-/* Configure shared memory. */
-
-static void setup_shm(void) {
-
- u8* shm_str;
-
- shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
-
- if (shm_id < 0) PFATAL("shmget() failed");
-
- atexit(remove_shm);
-
- shm_str = alloc_printf("%d", shm_id);
-
- setenv(SHM_ENV_VAR, shm_str, 1);
-
- ck_free(shm_str);
-
- trace_bits = shmat(shm_id, NULL, 0);
-
- if (!trace_bits) PFATAL("shmat() failed");
-
-}
-
/* Write results. */
static u32 write_results(void) {
@@ -413,50 +381,6 @@ static void setup_signal_handlers(void) {
}
-/* Detect @@ in args. */
-
-static void detect_file_args(char** argv) {
-
- u32 i = 0;
- u8* cwd = getcwd(NULL, 0);
-
- if (!cwd) PFATAL("getcwd() failed");
-
- while (argv[i]) {
-
- u8* aa_loc = strstr(argv[i], "@@");
-
- if (aa_loc) {
-
- u8 *aa_subst, *n_arg;
-
- if (!at_file) FATAL("@@ syntax is not supported by this tool.");
-
- /* Be sure that we're always using fully-qualified paths. */
-
- if (at_file[0] == '/') aa_subst = at_file;
- else aa_subst = alloc_printf("%s/%s", cwd, at_file);
-
- /* Construct a replacement argv value. */
-
- *aa_loc = 0;
- n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
- argv[i] = n_arg;
- *aa_loc = '@';
-
- if (at_file[0] != '/') ck_free(aa_subst);
-
- }
-
- i++;
-
- }
-
- free(cwd); /* not tracked */
-
-}
-
-
/* Show banner. */
static void show_banner(void) {
@@ -741,7 +665,7 @@ int main(int argc, char** argv) {
if (optind == argc || !out_file) usage(argv[0]);
- setup_shm();
+ setup_shm(0);
setup_signal_handlers();
set_up_environment();
@@ -753,7 +677,7 @@ int main(int argc, char** argv) {
ACTF("Executing '%s'...\n", target_path);
}
- detect_file_args(argv + optind);
+ detect_file_args(argv + optind, at_file);
if (qemu_mode)
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
diff --git a/afl-tmin.c b/afl-tmin.c
index a42be6e9..d6fd27fc 100644
--- a/afl-tmin.c
+++ b/afl-tmin.c
@@ -26,6 +26,8 @@
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
+#include "sharedmem.h"
+#include "afl-common.h"
#include <stdio.h>
#include <unistd.h>
@@ -50,8 +52,8 @@ static s32 forksrv_pid, /* PID of the fork server */
static s32 fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */
-static u8 *trace_bits, /* SHM with instrumentation bitmap */
- *mask_bitmap; /* Mask for trace bits (-B) */
+ u8 *trace_bits; /* SHM with instrumentation bitmap */
+static u8 *mask_bitmap; /* Mask for trace bits (-B) */
static u8 *in_file, /* Minimizer input test case */
*out_file, /* Minimizer output file */
@@ -73,8 +75,7 @@ static u32 in_len, /* Input data length */
static u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
-static s32 shm_id, /* ID of the SHM region */
- dev_null_fd = -1; /* FD to /dev/null */
+static s32 dev_null_fd = -1; /* FD to /dev/null */
static u8 crash_mode, /* Crash-centric mode? */
exit_crash, /* Treat non-zero exit as crash? */
@@ -159,42 +160,12 @@ static inline u8 anything_set(void) {
}
+/* Get rid of temp files (atexit handler). */
-/* Get rid of shared memory and temp files (atexit handler). */
-
-static void remove_shm(void) {
-
+static void at_exit_handler(void) {
if (prog_in) unlink(prog_in); /* Ignore errors */
- shmctl(shm_id, IPC_RMID, NULL);
-
-}
-
-
-/* Configure shared memory. */
-
-static void setup_shm(void) {
-
- u8* shm_str;
-
- shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
-
- if (shm_id < 0) PFATAL("shmget() failed");
-
- atexit(remove_shm);
-
- shm_str = alloc_printf("%d", shm_id);
-
- setenv(SHM_ENV_VAR, shm_str, 1);
-
- ck_free(shm_str);
-
- trace_bits = shmat(shm_id, NULL, 0);
-
- if (!trace_bits) PFATAL("shmat() failed");
-
}
-
/* Read initial file. */
static void read_initial_file(void) {
@@ -911,48 +882,6 @@ static void setup_signal_handlers(void) {
}
-/* Detect @@ in args. */
-
-static void detect_file_args(char** argv) {
-
- u32 i = 0;
- u8* cwd = getcwd(NULL, 0);
-
- if (!cwd) PFATAL("getcwd() failed");
-
- while (argv[i]) {
-
- u8* aa_loc = strstr(argv[i], "@@");
-
- if (aa_loc) {
-
- u8 *aa_subst, *n_arg;
-
- /* Be sure that we're always using fully-qualified paths. */
-
- if (prog_in[0] == '/') aa_subst = prog_in;
- else aa_subst = alloc_printf("%s/%s", cwd, prog_in);
-
- /* Construct a replacement argv value. */
-
- *aa_loc = 0;
- n_arg = alloc_printf("%s%s%s", argv[i], aa_subst, aa_loc + 2);
- argv[i] = n_arg;
- *aa_loc = '@';
-
- if (prog_in[0] != '/') ck_free(aa_subst);
-
- }
-
- i++;
-
- }
-
- free(cwd); /* not tracked */
-
-}
-
-
/* Display usage hints. */
static void usage(u8* argv0) {
@@ -1245,13 +1174,14 @@ int main(int argc, char** argv) {
if (optind == argc || !in_file || !out_file) usage(argv[0]);
- setup_shm();
+ setup_shm(0);
+ atexit(at_exit_handler);
setup_signal_handlers();
set_up_environment();
find_binary(argv[optind]);
- detect_file_args(argv + optind);
+ detect_file_args(argv + optind, prog_in);
if (qemu_mode)
use_argv = get_qemu_argv(argv[0], argv + optind, argc - optind);
diff --git a/llvm_mode/Makefile b/llvm_mode/Makefile
index 2947dc9b..d0d4b690 100644
--- a/llvm_mode/Makefile
+++ b/llvm_mode/Makefile
@@ -16,6 +16,9 @@
# http://www.apache.org/licenses/LICENSE-2.0
#
+# For Heiko:
+#TEST_MMAP=1
+
PREFIX ?= /usr/local
HELPER_PATH = $(PREFIX)/lib/afl
BIN_PATH = $(PREFIX)/bin
@@ -23,7 +26,7 @@ BIN_PATH = $(PREFIX)/bin
VERSION = $(shell grep '^\#define VERSION ' ../config.h | cut -d '"' -f2)
LLVM_CONFIG ?= llvm-config
-#LLVM_OK = $(shell $(LLVM_CONFIG) --version | egrep -q '^[5-6]' && echo 0 || echo 1 )
+LLVMVER = $(shell $(LLVM_CONFIG) --version)
LLVM_UNSUPPORTED = $(shell $(LLVM_CONFIG) --version | egrep -q '^9|3.0' && echo 1 || echo 0 )
LLVM_MAJOR = ($shell $(LLVM_CONFIG) --version | sed 's/\..*//')
@@ -39,7 +42,7 @@ endif
CFLAGS ?= -O3 -funroll-loops
CFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \
-DAFL_PATH=\"$(HELPER_PATH)\" -DBIN_PATH=\"$(BIN_PATH)\" \
- -DVERSION=\"$(VERSION)\"
+ -DVERSION=\"$(VERSION)\"
ifdef AFL_TRACE_PC
CFLAGS += -DUSE_TRACE_PC=1
endif
@@ -51,12 +54,16 @@ CXXFLAGS += -Wall -D_FORTIFY_SOURCE=2 -g -Wno-pointer-sign \
CLANG_CFL = `$(LLVM_CONFIG) --cxxflags` -Wl,-znodelete -fno-rtti -fpic $(CXXFLAGS)
CLANG_LFL = `$(LLVM_CONFIG) --ldflags` $(LDFLAGS)
-# User teor2345 reports that this is required to make things work on MacOS X.
+# User teor2345 reports that this is required to make things work on MacOS X.
ifeq "$(shell uname)" "Darwin"
CLANG_LFL += -Wl,-flat_namespace -Wl,-undefined,suppress
endif
+ifeq "$(shell uname)" "OpenBSD"
+ CLANG_LFL += `$(LLVM_CONFIG) --libdir`/libLLVM.so.0.0
+endif
+
# We were using llvm-config --bindir to get the location of clang, but
# this seems to be busted on some distros, so using the one in $PATH is
# probably better.
@@ -66,13 +73,53 @@ ifeq "$(origin CC)" "default"
CXX = clang++
endif
+# sanity check.
+# Are versions of clang --version and llvm-config --version equal?
+CLANGVER = $(shell $(CC) --version | sed -E -ne '/^.*([0-9]\.[0-9]\.[0-9]).*/s//\1/p')
+
+
+ifeq "$(shell echo '\#include <sys/ipc.h>@\#include <sys/shm.h>@int main() { int _id = shmget(IPC_PRIVATE, 65536, IPC_CREAT | IPC_EXCL | 0600); shmctl(_id, IPC_RMID, 0); return 0;}' | tr @ '\n' | $(CC) -x c - -o .test2 2>/dev/null && echo 1 || echo 0 )" "1"
+ SHMAT_OK=1
+else
+ SHMAT_OK=0
+ CFLAGS+=-DUSEMMAP=1
+ LDFLAGS += -lrt
+endif
+
+ifeq "$(TEST_MMAP)" "1"
+ SHMAT_OK=0
+ CFLAGS+=-DUSEMMAP=1
+ LDFLAGS += -lrt
+endif
+
+
ifndef AFL_TRACE_PC
PROGS = ../afl-clang-fast ../libLLVMInsTrim.so ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so
else
PROGS = ../afl-clang-fast ../afl-llvm-rt.o ../afl-llvm-rt-32.o ../afl-llvm-rt-64.o ../compare-transform-pass.so ../split-compares-pass.so ../split-switches-pass.so
endif
-all: test_deps $(PROGS) test_build all_done
+ifneq "$(CLANGVER)" "$(LLVMVER)"
+ CC = $(shell llvm-config --bindir)/clang
+ CXX = $(shell llvm-config --bindir)/clang++
+endif
+
+all: test_deps test_shm $(PROGS) test_build all_done
+
+
+ifeq "$(SHMAT_OK)" "1"
+
+test_shm:
+ @echo "[+] shmat seems to be working."
+ @rm -f .test2
+
+else
+
+test_shm:
+ @echo "[-] shmat seems not to be working, switching to mmap implementation"
+
+endif
+
test_deps:
ifndef AFL_TRACE_PC
@@ -83,6 +130,13 @@ else
endif
@echo "[*] Checking for working '$(CC)'..."
@which $(CC) >/dev/null 2>&1 || ( echo "[-] Oops, can't find '$(CC)'. Make sure that it's in your \$$PATH (or set \$$CC and \$$CXX)."; exit 1 )
+ @echo "[*] Checking for matching versions of '$(CC)' and '$(LLVM_CONFIG)'"
+ifneq "$(CLANGVER)" "$(LLVMVER)"
+ @echo "WARNING: we have llvm-config version $(LLVMVER) and a clang version $(CLANGVER)"
+ @echo "Retrying with the clang compiler from llvm: CC=`llvm-config --bindir`/clang"
+else
+ @echo "we have llvm-config version $(LLVMVER) with a clang version $(CLANGVER), good."
+endif
@echo "[*] Checking for '../afl-showmap'..."
@test -f ../afl-showmap || ( echo "[-] Oops, can't find '../afl-showmap'. Be sure to compile AFL first."; exit 1 )
@echo "[+] All set and ready to build."
@@ -129,5 +183,5 @@ all_done: test_build
.NOTPARALLEL: clean
clean:
- rm -f *.o *.so *~ a.out core core.[1-9][0-9]* test-instr .test-instr0 .test-instr1
+ rm -f *.o *.so *~ a.out core core.[1-9][0-9]* .test2 test-instr .test-instr0 .test-instr1
rm -f $(PROGS) ../afl-clang-fast++
diff --git a/llvm_mode/afl-clang-fast.c b/llvm_mode/afl-clang-fast.c
index 2034f10a..249eea7d 100644
--- a/llvm_mode/afl-clang-fast.c
+++ b/llvm_mode/afl-clang-fast.c
@@ -248,6 +248,10 @@ static void edit_params(u32 argc, char** argv) {
}
+#ifdef USEMMAP
+ cc_params[cc_par_cnt++] = "-lrt";
+#endif
+
cc_params[cc_par_cnt++] = "-D__AFL_HAVE_MANUAL_CONTROL=1";
cc_params[cc_par_cnt++] = "-D__AFL_COMPILER=1";
cc_params[cc_par_cnt++] = "-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1";
diff --git a/llvm_mode/afl-llvm-rt.o.c b/llvm_mode/afl-llvm-rt.o.c
index 342dcc90..debde204 100644
--- a/llvm_mode/afl-llvm-rt.o.c
+++ b/llvm_mode/afl-llvm-rt.o.c
@@ -44,6 +44,9 @@
# define CONST_PRIO 0
#endif /* ^USE_TRACE_PC */
+#include <sys/mman.h>
+#include <fcntl.h>
+
/* Globals needed by the injected instrumentation. The __afl_area_initial region
is used for instrumentation output before __afl_map_shm() has a chance to run.
@@ -71,10 +74,34 @@ static void __afl_map_shm(void) {
hacky .init code to work correctly in projects such as OpenSSL. */
if (id_str) {
+#ifdef USEMMAP
+ const char *shm_file_path = id_str;
+ int shm_fd = -1;
+ unsigned char *shm_base = NULL;
+
+ /* create the shared memory segment as if it was a file */
+ shm_fd = shm_open(shm_file_path, O_RDWR, 0600);
+ if (shm_fd == -1) {
+ printf("shm_open() failed\n");
+ exit(1);
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
+ if (shm_base == MAP_FAILED) {
+ close(shm_fd);
+ shm_fd = -1;
+ printf("mmap() failed\n");
+ exit(2);
+ }
+
+ __afl_area_ptr = shm_base;
+#else
u32 shm_id = atoi(id_str);
__afl_area_ptr = shmat(shm_id, NULL, 0);
+#endif
/* Whooooops. */
diff --git a/sharedmem.c b/sharedmem.c
new file mode 100644
index 00000000..3fd38444
--- /dev/null
+++ b/sharedmem.c
@@ -0,0 +1,137 @@
+/*
+
+ */
+
+#define AFL_MAIN
+
+#include "config.h"
+#include "types.h"
+#include "debug.h"
+#include "alloc-inl.h"
+#include "hash.h"
+#include "sharedmem.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <dirent.h>
+#include <fcntl.h>
+
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/mman.h>
+
+#ifndef USEMMAP
+ #include <sys/ipc.h>
+ #include <sys/shm.h>
+#endif
+
+extern unsigned char*trace_bits;
+
+#ifdef USEMMAP
+/* ================ Proteas ================ */
+int g_shm_fd = -1;
+unsigned char *g_shm_base = NULL;
+char g_shm_file_path[L_tmpnam];
+/* ========================================= */
+#else
+static s32 shm_id; /* ID of the SHM region */
+#endif
+
+/* Get rid of shared memory (atexit handler). */
+
+void remove_shm(void) {
+#ifdef USEMMAP
+ if (g_shm_base != NULL) {
+ munmap(g_shm_base, MAP_SIZE);
+ g_shm_base = NULL;
+ }
+
+ if (g_shm_fd != -1) {
+ close(g_shm_fd);
+ g_shm_fd = -1;
+ }
+#else
+ shmctl(shm_id, IPC_RMID, NULL);
+#endif
+}
+
+
+/* Configure shared memory. */
+
+void setup_shm(unsigned char dumb_mode) {
+#ifdef USEMMAP
+ /* generate random file name for multi instance */
+
+ /* thanks to f*cking glibc we can not use tmpnam securely, it generates a security warning that cannot be suppressed */
+ /* so we do this worse workaround */
+ snprintf(g_shm_file_path, L_tmpnam, "/afl_%d_%ld", getpid(), random());
+
+ /* create the shared memory segment as if it was a file */
+ g_shm_fd = shm_open(g_shm_file_path, O_CREAT | O_RDWR | O_EXCL, 0600);
+ if (g_shm_fd == -1) {
+ PFATAL("shm_open() failed");
+ }
+
+ /* configure the size of the shared memory segment */
+ if (ftruncate(g_shm_fd, MAP_SIZE)) {
+ PFATAL("setup_shm(): ftruncate() failed");
+ }
+
+ /* map the shared memory segment to the address space of the process */
+ g_shm_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, g_shm_fd, 0);
+ if (g_shm_base == MAP_FAILED) {
+ close(g_shm_fd);
+ g_shm_fd = -1;
+ PFATAL("mmap() failed");
+ }
+
+ atexit(remove_shm);
+
+ /* If somebody is asking us to fuzz instrumented binaries in dumb mode,
+ we don't want them to detect instrumentation, since we won't be sending
+ fork server commands. This should be replaced with better auto-detection
+ later on, perhaps? */
+
+ if (!dumb_mode) setenv(SHM_ENV_VAR, g_shm_file_path, 1);
+
+ trace_bits = g_shm_base;
+
+ if (!trace_bits) PFATAL("mmap() failed");
+
+#else
+ u8* shm_str;
+
+ shm_id = shmget(IPC_PRIVATE, MAP_SIZE, IPC_CREAT | IPC_EXCL | 0600);
+
+ if (shm_id < 0) PFATAL("shmget() failed");
+
+ atexit(remove_shm);
+
+ shm_str = alloc_printf("%d", shm_id);
+
+ setenv(SHM_ENV_VAR, shm_str, 1);
+
+ /* If somebody is asking us to fuzz instrumented binaries in dumb mode,
+ we don't want them to detect instrumentation, since we won't be sending
+ fork server commands. This should be replaced with better auto-detection
+ later on, perhaps? */
+
+ if (!dumb_mode) setenv(SHM_ENV_VAR, shm_str, 1);
+
+ ck_free(shm_str);
+
+ trace_bits = shmat(shm_id, NULL, 0);
+
+ if (!trace_bits) PFATAL("shmat() failed");
+
+#endif
+}
+
diff --git a/sharedmem.h b/sharedmem.h
new file mode 100644
index 00000000..53a85fcb
--- /dev/null
+++ b/sharedmem.h
@@ -0,0 +1,6 @@
+#ifndef __SHAREDMEM_H
+#define __SHAREDMEM_H
+
+void setup_shm(unsigned char dumb_mode);
+void remove_shm(void);
+#endif