summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/tools/security/afl/README.md19
-rw-r--r--pkgs/tools/security/afl/default.nix26
-rw-r--r--pkgs/tools/security/afl/qemu-patches/afl-config.h329
-rw-r--r--pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h287
-rw-r--r--pkgs/tools/security/afl/qemu-patches/afl-types.h79
-rw-r--r--pkgs/tools/security/afl/qemu-patches/cpu-exec.patch33
-rw-r--r--pkgs/tools/security/afl/qemu-patches/elfload.patch32
-rw-r--r--pkgs/tools/security/afl/qemu-patches/no-etc-install.patch14
-rw-r--r--pkgs/tools/security/afl/qemu-patches/translate-all.patch18
-rw-r--r--pkgs/tools/security/afl/qemu.nix72
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;
+  };
+}