diff options
-rw-r--r-- | pkgs/tools/security/afl/README.md | 19 | ||||
-rw-r--r-- | pkgs/tools/security/afl/default.nix | 26 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/afl-config.h | 329 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h | 287 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/afl-types.h | 79 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/cpu-exec.patch | 33 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/elfload.patch | 32 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/no-etc-install.patch | 14 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu-patches/translate-all.patch | 18 | ||||
-rw-r--r-- | pkgs/tools/security/afl/qemu.nix | 72 |
10 files changed, 907 insertions, 2 deletions
diff --git a/pkgs/tools/security/afl/README.md b/pkgs/tools/security/afl/README.md new file mode 100644 index 00000000000..7d954461773 --- /dev/null +++ b/pkgs/tools/security/afl/README.md @@ -0,0 +1,19 @@ +Updating the QEMU patches +========================= + +When updating to the latest American Fuzzy Lop, make sure to check for +any new patches to qemu for binary fuzzing support: + +https://github.com/mirrorer/afl/tree/master/qemu_mode + +Be sure to check the build script and make sure it's also using the +right QEMU version and options in `qemu.nix`: + +https://github.com/mirrorer/afl/blob/master/qemu_mode/build_qemu_support.sh + +`afl-config.h` and `afl-qemu-cpu-inl.h` are part of the afl source +code, and copied from `config.h` and `afl-qemu-cpu-inl.h` +appropriately. The QEMU patches need to be slightly adjusted to +`#include` these files (the patches try to otherwise include files +like `../../config.h` which causes the build to fail). See `qemu.nix` +for details. diff --git a/pkgs/tools/security/afl/default.nix b/pkgs/tools/security/afl/default.nix index b1c37331042..ed9b6d56edb 100644 --- a/pkgs/tools/security/afl/default.nix +++ b/pkgs/tools/security/afl/default.nix @@ -1,5 +1,11 @@ -{ stdenv, fetchurl, bash }: +{ stdenv, fetchurl, bash, callPackage, makeWrapper }: +let + afl-qemu = callPackage ./qemu.nix {}; + qemu-exe-name = if stdenv.system == "x86_64-linux" then "qemu-x86_64" + else if stdenv.system == "i686-linux" then "qemu-i386" + else throw "afl: no support for ${stdenv.system}!"; +in stdenv.mkDerivation rec { name = "afl-${version}"; version = "1.57b"; @@ -9,8 +15,24 @@ stdenv.mkDerivation rec { sha256 = "05dwh2kgz31702y339bvbs0b3ffadxgxk8cqqhs2i0ggx5bnl5p4"; }; + buildInputs = [ makeWrapper ]; + buildPhase = "make PREFIX=$out"; - installPhase = "make install PREFIX=$out"; + installPhase = '' + # Do the normal installation + make install PREFIX=$out + + # Install the custom QEMU emulator for binary blob fuzzing. + cp ${afl-qemu}/bin/${qemu-exe-name} $out/bin/afl-qemu-trace + + # Wrap every program with a custom $AFL_PATH; I believe there is a + # bug in afl which causes it to fail to find `afl-qemu-trace` + # relative to `afl-fuzz` or `afl-showmap`, so we instead set + # $AFL_PATH as a workaround, which allows it to be found. + for x in `ls $out/bin/afl-*`; do + wrapProgram $x --prefix AFL_PATH : "$out/bin" + done + ''; meta = { description = "Powerful fuzzer via genetic algorithms and instrumentation"; diff --git a/pkgs/tools/security/afl/qemu-patches/afl-config.h b/pkgs/tools/security/afl/qemu-patches/afl-config.h new file mode 100644 index 00000000000..051b38ffbca --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/afl-config.h @@ -0,0 +1,329 @@ +/* + american fuzzy lop - vaguely configurable bits + ---------------------------------------------- + + Written and maintained by Michal Zalewski <lcamtuf@google.com> + + Copyright 2013, 2014, 2015 Google Inc. 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 _HAVE_CONFIG_H +#define _HAVE_CONFIG_H + +#include "afl-types.h" + +/****************************************************** + * * + * Settings that may be of interest to power users: * + * * + ******************************************************/ + +/* Comment out to disable terminal colors: */ + +#define USE_COLOR + +/* Comment out to disable fancy ANSI boxes and use poor man's 7-bit UI: */ + +#define FANCY_BOXES + +/* Default timeout for fuzzed code (milliseconds): */ + +#define EXEC_TIMEOUT 1000 + +/* Timeout rounding factor when auto-scaling (milliseconds): */ + +#define EXEC_TM_ROUND 20 + +/* Default memory limit for child process (MB): */ + +#ifndef __x86_64__ +# define MEM_LIMIT 25 +#else +# define MEM_LIMIT 50 +#endif /* ^!__x86_64__ */ + +/* Default memory limit when running in QEMU mode (MB): */ + +#define MEM_LIMIT_QEMU 200 + +/* Number of calibration cycles per every new test case (and for test + cases that show variable behavior): */ + +#define CAL_CYCLES 10 +#define CAL_CYCLES_LONG 40 + +/* The same, but when AFL_NO_VAR_CHECK is set in the environment: */ + +#define CAL_CYCLES_NO_VAR 4 + +/* Number of subsequent hangs before abandoning an input file: */ + +#define HANG_LIMIT 250 + +/* Maximum number of unique hangs or crashes to record: */ + +#define KEEP_UNIQUE_HANG 500 +#define KEEP_UNIQUE_CRASH 5000 + +/* Baseline number of random tweaks during a single 'havoc' stage: */ + +#define HAVOC_CYCLES 5000 + +/* Maximum multiplier for the above (should be a power of two, beware + of 32-bit int overflows): */ + +#define HAVOC_MAX_MULT 16 + +/* Absolute minimum number of havoc cycles (after all adjustments): */ + +#define HAVOC_MIN 10 + +/* Maximum stacking for havoc-stage tweaks. The actual value is calculated + like this: + + n = random between 0 and HAVOC_STACK_POW2 + stacking = 2^n + + In other words, the default (n = 7) produces 1, 2, 4, 8, 16, 32, 64, or + 128 stacked tweaks: */ + +#define HAVOC_STACK_POW2 7 + +/* Caps on block sizes for cloning and deletion operations. Each of these + ranges has a 33% probability of getting picked, except for the first + two cycles where smaller blocks are favored: */ + +#define HAVOC_BLK_SMALL 32 +#define HAVOC_BLK_MEDIUM 128 +#define HAVOC_BLK_LARGE 1500 + +/* Probabilities of skipping non-favored entries in the queue, expressed as + percentages: */ + +#define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */ +#define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */ +#define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */ + +/* Splicing cycle count: */ + +#define SPLICE_CYCLES 20 + +/* Nominal per-splice havoc cycle length: */ + +#define SPLICE_HAVOC 500 + +/* Maximum offset for integer addition / subtraction stages: */ + +#define ARITH_MAX 35 + +/* Limits for the test case trimmer. The absolute minimum chunk size; and + the starting and ending divisors for chopping up the input file: */ + +#define TRIM_MIN_BYTES 4 +#define TRIM_START_STEPS 16 +#define TRIM_END_STEPS 1024 + +/* Maximum size of input file, in bytes (keep under 100MB): */ + +#define MAX_FILE (1 * 1024 * 1024) + +/* The same, for the test case minimizer: */ + +#define TMIN_MAX_FILE (10 * 1024 * 1024) + +/* Maximum dictionary token size (-x), in bytes: */ + +#define MAX_DICT_FILE 128 + +/* Length limits for auto-detected dictionary tokens: */ + +#define MIN_AUTO_EXTRA 3 +#define MAX_AUTO_EXTRA 32 + +/* Maximum number of user-specified dictionary tokens to use in deterministic + steps; past this point, the "extras/user" step will be still carried out, + but with proportionally lower odds: */ + +#define MAX_DET_EXTRAS 200 + +/* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing + (first value), and to keep in memory as candidates. The latter should be much + higher than the former. */ + +#define USE_AUTO_EXTRAS 50 +#define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 10) + +/* Scaling factor for the effector map used to skip some of the more + expensive deterministic steps. The actual divisor is set to + 2^EFF_MAP_SCALE2 bytes: */ + +#define EFF_MAP_SCALE2 3 + +/* Minimum input file length at which the effector logic kicks in: */ + +#define EFF_MIN_LEN 128 + +/* Maximum effector density past which everything is just fuzzed + unconditionally (%): */ + +#define EFF_MAX_PERC 90 + +/* UI refresh frequency (Hz): */ + +#define UI_TARGET_HZ 5 + +/* Fuzzer stats file and plot update intervals (sec): */ + +#define STATS_UPDATE_SEC 60 +#define PLOT_UPDATE_SEC 5 + +/* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */ + +#define AVG_SMOOTHING 16 + +/* Sync interval (every n havoc cycles): */ + +#define SYNC_INTERVAL 5 + +/* Output directory reuse grace period (minutes): */ + +#define OUTPUT_GRACE 25 + +/* Uncomment to use simple file names (id_NNNNNN): */ + +// #define SIMPLE_FILES + +/* List of interesting values to use in fuzzing. */ + +#define INTERESTING_8 \ + -128, /* Overflow signed 8-bit when decremented */ \ + -1, /* */ \ + 0, /* */ \ + 1, /* */ \ + 16, /* One-off with common buffer size */ \ + 32, /* One-off with common buffer size */ \ + 64, /* One-off with common buffer size */ \ + 100, /* One-off with common buffer size */ \ + 127 /* Overflow signed 8-bit when incremented */ + +#define INTERESTING_16 \ + -32768, /* Overflow signed 16-bit when decremented */ \ + -129, /* Overflow signed 8-bit */ \ + 128, /* Overflow signed 8-bit */ \ + 255, /* Overflow unsig 8-bit when incremented */ \ + 256, /* Overflow unsig 8-bit */ \ + 512, /* One-off with common buffer size */ \ + 1000, /* One-off with common buffer size */ \ + 1024, /* One-off with common buffer size */ \ + 4096, /* One-off with common buffer size */ \ + 32767 /* Overflow signed 16-bit when incremented */ + +#define INTERESTING_32 \ + -2147483648LL, /* Overflow signed 32-bit when decremented */ \ + -100663046, /* Large negative number (endian-agnostic) */ \ + -32769, /* Overflow signed 16-bit */ \ + 32768, /* Overflow signed 16-bit */ \ + 65535, /* Overflow unsig 16-bit when incremented */ \ + 65536, /* Overflow unsig 16 bit */ \ + 100663045, /* Large positive number (endian-agnostic) */ \ + 2147483647 /* Overflow signed 32-bit when incremented */ + +/*********************************************************** + * * + * Really exotic stuff you probably don't want to touch: * + * * + ***********************************************************/ + +/* Call count interval between reseeding the libc PRNG from /dev/urandom: */ + +#define RESEED_RNG 10000 + +/* Maximum line length passed from GCC to 'as': */ + +#define MAX_AS_LINE 8192 + +/* Environment variable used to pass SHM ID to the called program. */ + +#define SHM_ENV_VAR "__AFL_SHM_ID" + +/* Other less interesting, internal-only variables. */ + +#define CLANG_ENV_VAR "__AFL_CLANG_MODE" +#define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK" + +/* Distinctive bitmap signature used to indicate failed execution: */ + +#define EXEC_FAIL_SIG 0xfee1dead + +/* Distinctive exit code used to indicate MSAN trip condition: */ + +#define MSAN_ERROR 86 + +/* Designated file descriptors for forkserver commands (the application will + use FORKSRV_FD and FORKSRV_FD + 1): */ + +#define FORKSRV_FD 198 + +/* Fork server init timeout multiplier: we'll wait the user-selected + timeout plus this much for the fork server to spin up. */ + +#define FORK_WAIT_MULT 10 + +/* Calibration timeout adjustments, to be a bit more generous when resuming + fuzzing sessions or trying to calibrate already-added internal finds. + The first value is a percentage, the other is in milliseconds: */ + +#define CAL_TMOUT_PERC 125 +#define CAL_TMOUT_ADD 50 + +/* Number of chances to calibrate a case before giving up: */ + +#define CAL_CHANCES 3 + +/* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than + 2; you probably want to keep it under 18 or so for performance reasons + (adjusting AFL_INST_RATIO when compiling is probably a better way to solve + problems with complex programs). You need to recompile the target binary + after changing this - otherwise, SEGVs may ensue. */ + +#define MAP_SIZE_POW2 16 +#define MAP_SIZE (1 << MAP_SIZE_POW2) + +/* Maximum allocator request size (keep well under INT_MAX): */ + +#define MAX_ALLOC 0x40000000 + +/* A made-up hashing seed: */ + +#define HASH_CONST 0xa5b35705 + +/* Constants for afl-gotcpu to control busy loop timing: */ + +#define CTEST_TARGET_MS 5000 +#define CTEST_BUSY_CYCLES (10 * 1000 * 1000) + +/* Uncomment this to use inferior block-coverage-based instrumentation. Note + that you need to recompile the target binary for this to have any effect: */ + +// #define COVERAGE_ONLY + +/* Uncomment this to ignore hit counts and output just one bit per tuple. + As with the previous setting, you will need to recompile the target + binary: */ + +// #define SKIP_COUNTS + +/* Uncomment this to use instrumentation data to record newly discovered paths, + but do not use them as seeds for fuzzing. This is useful for conveniently + measuring coverage that could be attained by a "dumb" fuzzing algorithm: */ + +// #define IGNORE_FINDS + +#endif /* ! _HAVE_CONFIG_H */ diff --git a/pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h b/pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h new file mode 100644 index 00000000000..7d5a47669e4 --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h @@ -0,0 +1,287 @@ +/* + american fuzzy lop - high-performance binary-only instrumentation + ----------------------------------------------------------------- + + Written by Andrew Griffiths <agriffiths@google.com> and + Michal Zalewski <lcamtuf@google.com> + + Idea & design very much by Andrew Griffiths. + + Copyright 2015 Google Inc. 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 + + This code is a shim patched into the separately-distributed source + code of QEMU 2.2.0. It leverages the built-in QEMU tracing functionality + to implement AFL-style instrumentation and to take care of the remaining + parts of the AFL fork server logic. + + The resulting QEMU binary is essentially a standalone instrumentation + tool; for an example of how to leverage it for other purposes, you can + have a look at afl-showmap.c. + + */ + +#include <sys/shm.h> +#include "afl-config.h" + +/*************************** + * VARIOUS AUXILIARY STUFF * + ***************************/ + +/* A snippet patched into tb_find_slow to inform the parent process that + we have hit a new block that hasn't been translated yet, and to tell + it to translate within its own context, too (this avoids translation + overhead in the next forked-off copy). */ + +#define AFL_QEMU_CPU_SNIPPET1 do { \ + afl_request_tsl(pc, cs_base, flags); \ + } while (0) + +/* This snippet kicks in when the instruction pointer is positioned at + _start and does the usual forkserver stuff, not very different from + regular instrumentation injected via afl-as.h. */ + +#define AFL_QEMU_CPU_SNIPPET2 do { \ + if(tb->pc == afl_entry_point) { \ + afl_setup(); \ + afl_forkserver(env); \ + } \ + afl_maybe_log(tb->pc); \ + } while (0) + +/* We use one additional file descriptor to relay "needs translation" + messages between the child and the fork server. */ + +#define TSL_FD (FORKSRV_FD - 1) + +/* This is equivalent to afl-as.h: */ + +static unsigned char *afl_area_ptr; + +/* Exported variables populated by the code patched into elfload.c: */ + +abi_ulong afl_entry_point, /* ELF entry point (_start) */ + afl_start_code, /* .text start pointer */ + afl_end_code; /* .text end pointer */ + +/* Set on the child in forkserver mode: */ + +static unsigned char afl_fork_child; + +/* Instrumentation ratio: */ + +static unsigned int afl_inst_rms = MAP_SIZE; + +/* Function declarations. */ + +static void afl_setup(void); +static void afl_forkserver(CPUArchState*); +static inline void afl_maybe_log(abi_ulong); + +static void afl_wait_tsl(CPUArchState*, int); +static void afl_request_tsl(target_ulong, target_ulong, uint64_t); + +static TranslationBlock *tb_find_slow(CPUArchState*, target_ulong, + target_ulong, uint64_t); + + +/* Data structure passed around by the translate handlers: */ + +struct afl_tsl { + target_ulong pc; + target_ulong cs_base; + uint64_t flags; +}; + + +/************************* + * ACTUAL IMPLEMENTATION * + *************************/ + + +/* Set up SHM region and initialize other stuff. */ + +static void afl_setup(void) { + + char *id_str = getenv(SHM_ENV_VAR), + *inst_r = getenv("AFL_INST_RATIO"); + + int shm_id; + + if (inst_r) { + + unsigned int r; + + r = atoi(inst_r); + + if (r > 100) r = 100; + if (!r) r = 1; + + afl_inst_rms = MAP_SIZE * r / 100; + + } + + if (id_str) { + + shm_id = atoi(id_str); + afl_area_ptr = shmat(shm_id, NULL, 0); + + if (afl_area_ptr == (void*)-1) exit(1); + + } + + if (getenv("AFL_INST_LIBS")) { + + afl_start_code = 0; + afl_end_code = (abi_ulong)-1; + + } + +} + + +/* Fork server logic, invoked once we hit _start. */ + +static void afl_forkserver(CPUArchState *env) { + + static unsigned char tmp[4]; + + if (!afl_area_ptr) return; + + /* Tell the parent that we're alive. If the parent doesn't want + to talk, assume that we're not running in forkserver mode. */ + + if (write(FORKSRV_FD + 1, tmp, 4) != 4) return; + + /* All right, let's await orders... */ + + while (1) { + + pid_t child_pid; + int status, t_fd[2]; + + /* Whoops, parent dead? */ + + if (read(FORKSRV_FD, tmp, 4) != 4) exit(2); + + /* Establish a channel with child to grab translation commands. We'll + read from t_fd[0], child will write to TSL_FD. */ + + if (pipe(t_fd) || dup2(t_fd[1], TSL_FD) < 0) exit(3); + close(t_fd[1]); + + child_pid = fork(); + if (child_pid < 0) exit(4); + + if (!child_pid) { + + /* Child process. Close descriptors and run free. */ + + afl_fork_child = 1; + close(FORKSRV_FD); + close(FORKSRV_FD + 1); + close(t_fd[0]); + return; + + } + + /* Parent. */ + + close(TSL_FD); + + if (write(FORKSRV_FD + 1, &child_pid, 4) != 4) exit(5); + + /* Collect translation requests until child dies and closes the pipe. */ + + afl_wait_tsl(env, t_fd[0]); + + /* Get and relay exit status to parent. */ + + if (waitpid(child_pid, &status, WUNTRACED) < 0) exit(6); + if (write(FORKSRV_FD + 1, &status, 4) != 4) exit(7); + + } + +} + + +/* The equivalent of the tuple logging routine from afl-as.h. */ + +static inline void afl_maybe_log(abi_ulong cur_loc) { + + static abi_ulong prev_loc; + + /* Optimize for cur_loc > afl_end_code, which is the most likely case on + Linux systems. */ + + if (cur_loc > afl_end_code || cur_loc < afl_start_code || !afl_area_ptr) + return; + + /* Looks like QEMU always maps to fixed locations, so we can skip this: + cur_loc -= afl_start_code; */ + + /* Instruction addresses may be aligned. Let's mangle the value to get + something quasi-uniform. */ + + cur_loc = (cur_loc >> 4) ^ (cur_loc << 8); + cur_loc &= MAP_SIZE - 1; + + /* Implement probabilistic instrumentation by looking at scrambled block + address. This keeps the instrumented locations stable across runs. */ + + if (cur_loc >= afl_inst_rms) return; + + afl_area_ptr[cur_loc ^ prev_loc]++; + prev_loc = cur_loc >> 1; + +} + + +/* This code is invoked whenever QEMU decides that it doesn't have a + translation of a particular block and needs to compute it. When this happens, + we tell the parent to mirror the operation, so that the next fork() has a + cached copy. */ + +static void afl_request_tsl(target_ulong pc, target_ulong cb, uint64_t flags) { + + struct afl_tsl t; + + if (!afl_fork_child) return; + + t.pc = pc; + t.cs_base = cb; + t.flags = flags; + + if (write(TSL_FD, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) + return; + +} + + +/* This is the other side of the same channel. Since timeouts are handled by + afl-fuzz simply killing the child, we can just wait until the pipe breaks. */ + +static void afl_wait_tsl(CPUArchState *env, int fd) { + + struct afl_tsl t; + + while (1) { + + /* Broken pipe means it's time to return to the fork server routine. */ + + if (read(fd, &t, sizeof(struct afl_tsl)) != sizeof(struct afl_tsl)) + break; + + tb_find_slow(env, t.pc, t.cs_base, t.flags); + + } + + close(fd); + +} + diff --git a/pkgs/tools/security/afl/qemu-patches/afl-types.h b/pkgs/tools/security/afl/qemu-patches/afl-types.h new file mode 100644 index 00000000000..58d6be51e2d --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/afl-types.h @@ -0,0 +1,79 @@ +/* + american fuzzy lop - type definitions and minor macros + ------------------------------------------------------ + + Written and maintained by Michal Zalewski <lcamtuf@google.com> + + Copyright 2013, 2014, 2015 Google Inc. 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 _HAVE_TYPES_H +#define _HAVE_TYPES_H + +#include <stdint.h> +#include <stdlib.h> + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; + +/* + + Ugh. There is an unintended compiler / glibc #include glitch caused by + combining the u64 type an %llu in format strings, necessitating a workaround. + + In essence, the compiler is always looking for 'unsigned long long' for %llu. + On 32-bit systems, the u64 type (aliased to uint64_t) is expanded to + 'unsigned long long' in <bits/types.h>, so everything checks out. + + But on 64-bit systems, it is #ifdef'ed in the same file as 'unsigned long'. + Now, it only happens in circumstances where the type happens to have the + expected bit width, *but* the compiler does not know that... and complains + about 'unsigned long' being unsafe to pass to %llu. + + */ + +#ifdef __x86_64__ +typedef unsigned long long u64; +#else +typedef uint64_t u64; +#endif /* ^sizeof(...) */ + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#ifndef MIN +# define MIN(_a,_b) ((_a) > (_b) ? (_b) : (_a)) +# define MAX(_a,_b) ((_a) > (_b) ? (_a) : (_b)) +#endif /* !MIN */ + +#define SWAP16(_x) ({ \ + u16 _ret = (_x); \ + (u16)((_ret << 8) | (_ret >> 8)); \ + }) + +#define SWAP32(_x) ({ \ + u32 _ret = (_x); \ + (u32)((_ret << 24) | (_ret >> 24) | \ + ((_ret << 8) & 0x00FF0000) | \ + ((_ret >> 8) & 0x0000FF00)); \ + }) + +#define R(x) (random() % (x)) + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define MEM_BARRIER() \ + asm volatile("" ::: "memory") + +#endif /* ! _HAVE_TYPES_H */ diff --git a/pkgs/tools/security/afl/qemu-patches/cpu-exec.patch b/pkgs/tools/security/afl/qemu-patches/cpu-exec.patch new file mode 100644 index 00000000000..29b65e71b9a --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/cpu-exec.patch @@ -0,0 +1,33 @@ +--- qemu-2.2.0/cpu-exec.c.orig 2014-12-09 14:45:40.000000000 +0000 ++++ qemu-2.2.0/cpu-exec.c 2015-02-20 22:07:02.966000000 +0000 +@@ -25,6 +25,8 @@ + #include "sysemu/qtest.h" + #include "qemu/timer.h" + ++#include "afl-qemu-cpu-inl.h" ++ + /* -icount align implementation. */ + + typedef struct SyncClocks { +@@ -262,8 +264,11 @@ + } + not_found: + /* if no translated code available, then translate it now */ ++ + tb = tb_gen_code(cpu, pc, cs_base, flags, 0); + ++ AFL_QEMU_CPU_SNIPPET1; ++ + found: + /* Move the last found TB to the head of the list */ + if (likely(*ptb1)) { +@@ -455,6 +460,9 @@ + next_tb = 0; + tcg_ctx.tb_ctx.tb_invalidated_flag = 0; + } ++ ++ AFL_QEMU_CPU_SNIPPET2; ++ + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + qemu_log("Trace %p [" TARGET_FMT_lx "] %s\n", + tb->tc_ptr, tb->pc, lookup_symbol(tb->pc)); diff --git a/pkgs/tools/security/afl/qemu-patches/elfload.patch b/pkgs/tools/security/afl/qemu-patches/elfload.patch new file mode 100644 index 00000000000..65f1572e9a7 --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/elfload.patch @@ -0,0 +1,32 @@ +--- qemu-2.2.0/linux-user/elfload.c.orig 2014-12-09 14:45:42.000000000 +0000 ++++ qemu-2.2.0/linux-user/elfload.c 2015-01-28 02:51:23.719000000 +0000 +@@ -28,6 +28,8 @@ + + #define ELF_OSABI ELFOSABI_SYSV + ++extern abi_ulong afl_entry_point, afl_start_code, afl_end_code; ++ + /* from personality.h */ + + /* +@@ -1886,6 +1888,8 @@ + info->brk = 0; + info->elf_flags = ehdr->e_flags; + ++ if (!afl_entry_point) afl_entry_point = info->entry; ++ + for (i = 0; i < ehdr->e_phnum; i++) { + struct elf_phdr *eppnt = phdr + i; + if (eppnt->p_type == PT_LOAD) { +@@ -1919,9 +1923,11 @@ + if (elf_prot & PROT_EXEC) { + if (vaddr < info->start_code) { + info->start_code = vaddr; ++ if (!afl_start_code) afl_start_code = vaddr; + } + if (vaddr_ef > info->end_code) { + info->end_code = vaddr_ef; ++ if (!afl_end_code) afl_end_code = vaddr_ef; + } + } + if (elf_prot & PROT_WRITE) { diff --git a/pkgs/tools/security/afl/qemu-patches/no-etc-install.patch b/pkgs/tools/security/afl/qemu-patches/no-etc-install.patch new file mode 100644 index 00000000000..81d29feea3d --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/no-etc-install.patch @@ -0,0 +1,14 @@ +diff --git a/Makefile b/Makefile +index d6b9dc1..ce7c493 100644 +--- a/Makefile ++++ b/Makefile +@@ -384,8 +384,7 @@ install-confdir: + install-sysconfig: install-datadir install-confdir + $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)" + +-install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \ +-install-datadir install-localstatedir ++install: all $(if $(BUILD_DOCS),install-doc) install-datadir + ifneq ($(TOOLS),) + $(call install-prog,$(TOOLS),$(DESTDIR)$(bindir)) + endif diff --git a/pkgs/tools/security/afl/qemu-patches/translate-all.patch b/pkgs/tools/security/afl/qemu-patches/translate-all.patch new file mode 100644 index 00000000000..89163b607fd --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/translate-all.patch @@ -0,0 +1,18 @@ +--- qemu-2.2.0/translate-all.c.orig 2014-12-09 14:45:46.000000000 +0000 ++++ qemu-2.2.0/translate-all.c 2015-01-28 22:37:42.383000000 +0000 +@@ -387,8 +387,13 @@ + /* We can't use g_malloc because it may recurse into a locked mutex. */ + # define ALLOC(P, SIZE) \ + do { \ +- P = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, \ +- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \ ++ void* _tmp = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, \ ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); \ ++ if (_tmp == (void*)-1) { \ ++ qemu_log(">>> Out of memory for stack, bailing out. <<<\n"); \ ++ exit(1); \ ++ } \ ++ (P) = _tmp; \ + } while (0) + #else + # define ALLOC(P, SIZE) \ diff --git a/pkgs/tools/security/afl/qemu.nix b/pkgs/tools/security/afl/qemu.nix new file mode 100644 index 00000000000..929f9fba9a6 --- /dev/null +++ b/pkgs/tools/security/afl/qemu.nix @@ -0,0 +1,72 @@ +{ stdenv, fetchurl, python, zlib, pkgconfig, glib, ncurses, perl +, attr, libcap, vde2, alsaLib, texinfo, libuuid, flex, bison, lzo, snappy +, libaio, libcap_ng, gnutls, pixman, autoconf +, writeText +}: + +with stdenv.lib; + +let + n = "qemu-2.2.0"; + + aflHeaderFile = writeText "afl-qemu-cpu-inl.h" + (builtins.readFile ./qemu-patches/afl-qemu-cpu-inl.h); + aflConfigFile = writeText "afl-config.h" + (builtins.readFile ./qemu-patches/afl-config.h); + aflTypesFile = writeText "afl-types.h" + (builtins.readFile ./qemu-patches/afl-types.h); + + cpuTarget = if stdenv.system == "x86_64-linux" then "x86_64-linux-user" + else if stdenv.system == "i686-linux" then "i386-linux-user" + else throw "afl: no support for ${stdenv.system}!"; +in +stdenv.mkDerivation rec { + name = "afl-${n}"; + + src = fetchurl { + url = "http://wiki.qemu.org/download/${n}.tar.bz2"; + sha256 = "1703c3scl5n07gmpilg7g2xzyxnr7jczxgx6nn4m8kv9gin9p35n"; + }; + + buildInputs = + [ python zlib pkgconfig glib pixman ncurses perl attr libcap + vde2 texinfo libuuid flex bison lzo snappy autoconf + libcap_ng gnutls + ] + ++ optionals (hasSuffix "linux" stdenv.system) [ libaio ]; + + enableParallelBuilding = true; + + patches = + [ ./qemu-patches/elfload.patch + ./qemu-patches/cpu-exec.patch + ./qemu-patches/no-etc-install.patch + ./qemu-patches/translate-all.patch + ]; + + preConfigure = '' + cp ${aflTypesFile} afl-types.h + cp ${aflConfigFile} afl-config.h + cp ${aflHeaderFile} afl-qemu-cpu-inl.h + ''; + + configureFlags = + [ "--disable-system" + "--enable-linux-user" + "--enable-guest-base" + "--disable-gtk" + "--disable-sdl" + "--disable-vnc" + "--target-list=${cpuTarget}" + "--sysconfdir=/etc" + "--localstatedir=/var" + ]; + + meta = with stdenv.lib; { + homepage = http://www.qemu.org/; + description = "Fork of QEMU with American Fuzzy Lop instrumentation support"; + license = licenses.gpl2Plus; + maintainers = with maintainers; [ thoughtpolice ]; + platforms = platforms.linux; + }; +} |