diff --git a/pkgs/tools/security/afl/default.nix b/pkgs/tools/security/afl/default.nix index 3476606049d1..c90d031e989b 100644 --- a/pkgs/tools/security/afl/default.nix +++ b/pkgs/tools/security/afl/default.nix @@ -3,79 +3,73 @@ }: let - afl-qemu = callPackage ./qemu.nix {}; + afl-qemu = callPackage ./qemu.nix { inherit afl; }; qemu-exe-name = if stdenv.hostPlatform.system == "x86_64-linux" then "qemu-x86_64" else if stdenv.hostPlatform.system == "i686-linux" then "qemu-i386" else throw "afl: no support for ${stdenv.hostPlatform.system}!"; -in + afl = stdenv.mkDerivation rec { + name = "afl-${version}"; + version = "2.52b"; -stdenv.mkDerivation rec { - name = "afl-${version}"; - version = "2.52b"; + src = fetchurl { + url = "http://lcamtuf.coredump.cx/afl/releases/${name}.tgz"; + sha256 = "0ig0ij4n1pwry5dw1hk4q88801jzzy2cric6y2gd6560j55lnqa3"; + }; + enableParallelBuilding = true; - src = fetchurl { - url = "http://lcamtuf.coredump.cx/afl/releases/${name}.tgz"; - sha256 = "0ig0ij4n1pwry5dw1hk4q88801jzzy2cric6y2gd6560j55lnqa3"; - }; + # Note: libcgroup isn't needed for building, just for the afl-cgroup + # script. + nativeBuildInputs = [ makeWrapper which ]; + buildInputs = [ llvm ]; - # Note: libcgroup isn't needed for building, just for the afl-cgroup - # script. - buildInputs = [ makeWrapper llvm which ]; - - buildPhase = '' - make PREFIX=$out - cd llvm_mode - make PREFIX=$out - cd .. - ''; - 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 - - # Install the cgroups wrapper for asan-based fuzzing. - cp experimental/asan_cgroups/limit_memory.sh $out/bin/afl-cgroup - chmod +x $out/bin/afl-cgroup - substituteInPlace $out/bin/afl-cgroup \ - --replace "cgcreate" "${libcgroup}/bin/cgcreate" \ - --replace "cgexec" "${libcgroup}/bin/cgexec" \ - --replace "cgdelete" "${libcgroup}/bin/cgdelete" - - # Patch shebangs before wrapping - patchShebangs $out/bin - - # Wrap afl-clang-fast(++) with a *different* AFL_PATH, because it - # has totally different semantics in that case(?) - and also set a - # proper AFL_CC and AFL_CXX so we don't pick up the wrong one out - # of $PATH. - for x in $out/bin/afl-clang-fast $out/bin/afl-clang-fast++; do - wrapProgram $x \ - --prefix AFL_PATH : "$out/lib/afl" \ - --run 'export AFL_CC=''${AFL_CC:-${clang}/bin/clang} AFL_CXX=''${AFL_CXX:-${clang}/bin/clang++}' - done - ''; - - passthru = { - qemu = afl-qemu; - }; - - meta = { - description = "Powerful fuzzer via genetic algorithms and instrumentation"; - longDescription = '' - American fuzzy lop is a fuzzer that employs a novel type of - compile-time instrumentation and genetic algorithms to - automatically discover clean, interesting test cases that - trigger new internal states in the targeted binary. This - substantially improves the functional coverage for the fuzzed - code. The compact synthesized corpora produced by the tool are - also useful for seeding other, more labor or resource-intensive - testing regimes down the road. + makeFlags = [ "PREFIX=$(out)" ]; + postBuild = '' + make -C llvm_mode $makeFlags -j$NIX_BUILD_CORES ''; - homepage = "http://lcamtuf.coredump.cx/afl/"; - license = stdenv.lib.licenses.asl20; - platforms = ["x86_64-linux" "i686-linux"]; - maintainers = [ stdenv.lib.maintainers.thoughtpolice ]; + postInstall = '' + # Install the custom QEMU emulator for binary blob fuzzing. + cp ${afl-qemu}/bin/${qemu-exe-name} $out/bin/afl-qemu-trace + + # Install the cgroups wrapper for asan-based fuzzing. + cp experimental/asan_cgroups/limit_memory.sh $out/bin/afl-cgroup + chmod +x $out/bin/afl-cgroup + substituteInPlace $out/bin/afl-cgroup \ + --replace "cgcreate" "${libcgroup}/bin/cgcreate" \ + --replace "cgexec" "${libcgroup}/bin/cgexec" \ + --replace "cgdelete" "${libcgroup}/bin/cgdelete" + + # Patch shebangs before wrapping + patchShebangs $out/bin + + # Wrap afl-clang-fast(++) with a *different* AFL_PATH, because it + # has totally different semantics in that case(?) - and also set a + # proper AFL_CC and AFL_CXX so we don't pick up the wrong one out + # of $PATH. + for x in $out/bin/afl-clang-fast $out/bin/afl-clang-fast++; do + wrapProgram $x \ + --prefix AFL_PATH : "$out/lib/afl" \ + --run 'export AFL_CC=''${AFL_CC:-${clang}/bin/clang} AFL_CXX=''${AFL_CXX:-${clang}/bin/clang++}' + done + ''; + + passthru.qemu = afl-qemu; + + meta = { + description = "Powerful fuzzer via genetic algorithms and instrumentation"; + longDescription = '' + American fuzzy lop is a fuzzer that employs a novel type of + compile-time instrumentation and genetic algorithms to + automatically discover clean, interesting test cases that + trigger new internal states in the targeted binary. This + substantially improves the functional coverage for the fuzzed + code. The compact synthesized corpora produced by the tool are + also useful for seeding other, more labor or resource-intensive + testing regimes down the road. + ''; + homepage = "http://lcamtuf.coredump.cx/afl/"; + license = stdenv.lib.licenses.asl20; + platforms = ["x86_64-linux" "i686-linux"]; + maintainers = [ stdenv.lib.maintainers.thoughtpolice ]; + }; }; -} +in afl diff --git a/pkgs/tools/security/afl/qemu-patches/afl-config.h b/pkgs/tools/security/afl/qemu-patches/afl-config.h deleted file mode 100644 index cbf48881ade2..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/afl-config.h +++ /dev/null @@ -1,335 +0,0 @@ -/* - american fuzzy lop - vaguely configurable bits - ---------------------------------------------- - - Written and maintained by Michal Zalewski - - 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 1 and HAVOC_STACK_POW2 - stacking = 2^n - - In other words, the default (n = 7) produces 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) - -/* Block normalization steps for afl-tmin: */ - -#define TMIN_SET_MIN_SIZE 4 -#define TMIN_SET_STEPS 128 - -/* 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' and used for parsing - configuration files: */ - -#define MAX_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 deleted file mode 100644 index e4a470b55230..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/afl-qemu-cpu-inl.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - american fuzzy lop - high-performance binary-only instrumentation - ----------------------------------------------------------------- - - Written by Andrew Griffiths and - Michal Zalewski - - 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 -#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 in the child process in forkserver mode: */ - -static unsigned char afl_fork_child; -unsigned int afl_forksrv_pid; - -/* 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); - - /* With AFL_INST_RATIO set to a low value, we want to touch the bitmap - so that the parent doesn't give up on us. */ - - if (inst_r) afl_area_ptr[0] = 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; - - afl_forksrv_pid = getpid(); - - /* 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 deleted file mode 100644 index 58d6be51e2d0..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/afl-types.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - american fuzzy lop - type definitions and minor macros - ------------------------------------------------------ - - Written and maintained by Michal Zalewski - - 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 -#include - -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 , 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 deleted file mode 100644 index 75a7ea450eff..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/cpu-exec.patch +++ /dev/null @@ -1,33 +0,0 @@ ---- qemu-2.3.0/cpu-exec.c.orig 2014-12-09 14:45:40.000000000 +0000 -+++ qemu-2.3.0/cpu-exec.c 2015-02-20 22:07:02.966000000 +0000 -@@ -28,6 +28,8 @@ - #include "exec/memory-internal.h" - #include "qemu/rcu.h" - -+#include "afl-qemu-cpu-inl.h" -+ - /* -icount align implementation. */ - - typedef struct SyncClocks { -@@ -296,8 +298,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)) { -@@ -492,6 +497,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 deleted file mode 100644 index 325c917d15a3..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/elfload.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- qemu-2.3.0/linux-user/elfload.c.orig 2014-12-09 14:45:42.000000000 +0000 -+++ qemu-2.3.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 */ - - /* -@@ -1889,6 +1891,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) { -@@ -1922,9 +1926,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 index 81d29feea3de..5dfbfd780f1c 100644 --- a/pkgs/tools/security/afl/qemu-patches/no-etc-install.patch +++ b/pkgs/tools/security/afl/qemu-patches/no-etc-install.patch @@ -2,13 +2,12 @@ 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)" +@@ -601,7 +601,7 @@ install-localstatedir: + endif --install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig \ --install-datadir install-localstatedir + +-install: all $(if $(BUILD_DOCS),install-doc) install-datadir install-localstatedir +install: all $(if $(BUILD_DOCS),install-doc) install-datadir ifneq ($(TOOLS),) - $(call install-prog,$(TOOLS),$(DESTDIR)$(bindir)) + $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir)) endif diff --git a/pkgs/tools/security/afl/qemu-patches/qemu-2.10.0-glibc-2.27.patch b/pkgs/tools/security/afl/qemu-patches/qemu-2.10.0-glibc-2.27.patch new file mode 100644 index 000000000000..6cc663dc1fb9 --- /dev/null +++ b/pkgs/tools/security/afl/qemu-patches/qemu-2.10.0-glibc-2.27.patch @@ -0,0 +1,28 @@ +A modified version of qemu commit 75e5b70e6b5dcc4f2219992d7cffa462aa406af0 +diff --git a/configure b/configure +index 9c8aa5a..99ccc17 100755 +--- a/configure ++++ b/configure +@@ -3855,7 +3855,7 @@ fi + # check if memfd is supported + memfd=no + cat > $TMPC << EOF +-#include ++#include + + int main(void) + { +diff --git a/util/memfd.c b/util/memfd.c +index 4571d1a..412e94a 100644 +--- a/util/memfd.c ++++ b/util/memfd.c +@@ -31,9 +31,7 @@ + + #include "qemu/memfd.h" + +-#ifdef CONFIG_MEMFD +-#include +-#elif defined CONFIG_LINUX ++#if defined CONFIG_LINUX && !defined CONFIG_MEMFD + #include + #include diff --git a/pkgs/tools/security/afl/qemu-patches/qemu-2.3.0-glibc-2.26.patch b/pkgs/tools/security/afl/qemu-patches/qemu-2.3.0-glibc-2.26.patch deleted file mode 100644 index 1c447c4051e8..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/qemu-2.3.0-glibc-2.26.patch +++ /dev/null @@ -1,121 +0,0 @@ -diff --git a/user-exec.c b/user-exec.c -index 8f57e8a..957f9f7 100644 ---- a/user-exec.c -+++ b/user-exec.c -@@ -57,7 +57,7 @@ static void exception_action(CPUState *cpu) - void cpu_resume_from_signal(CPUState *cpu, void *puc) - { - #ifdef __linux__ -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - #elif defined(__OpenBSD__) - struct sigcontext *uc = puc; - #endif -@@ -171,7 +171,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - #elif defined(__OpenBSD__) - struct sigcontext *uc = puc; - #else -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - #endif - unsigned long pc; - int trapno; -@@ -226,7 +226,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - #elif defined(__OpenBSD__) - struct sigcontext *uc = puc; - #else -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - #endif - - pc = PC_sig(uc); -@@ -288,7 +288,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - - #ifdef __APPLE__ - #include --typedef struct ucontext SIGCONTEXT; -+typedef ucontext_t SIGCONTEXT; - /* All Registers access - only for local access */ - #define REG_sig(reg_name, context) \ - ((context)->uc_mcontext->ss.reg_name) -@@ -331,7 +331,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - ucontext_t *uc = puc; - #else -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - #endif - unsigned long pc; - int is_write; -@@ -358,7 +358,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - uint32_t *pc = uc->uc_mcontext.sc_pc; - uint32_t insn = *pc; - int is_write = 0; -@@ -456,7 +456,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - #if defined(__NetBSD__) - ucontext_t *uc = puc; - #else -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - #endif - unsigned long pc; - int is_write; -@@ -483,7 +483,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - int cpu_signal_handler(int host_signum, void *pinfo, void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - uintptr_t pc = uc->uc_mcontext.pc; - uint32_t insn = *(uint32_t *)pc; - bool is_write; -@@ -512,7 +512,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - unsigned long pc; - int is_write; - -@@ -534,7 +534,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - int cpu_signal_handler(int host_signum, void *pinfo, void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - unsigned long ip; - int is_write = 0; - -@@ -565,7 +565,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - unsigned long pc; - uint16_t *pinsn; - int is_write = 0; -@@ -618,7 +618,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - greg_t pc = uc->uc_mcontext.pc; - int is_write; - -@@ -634,7 +634,7 @@ int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) - { - siginfo_t *info = pinfo; -- struct ucontext *uc = puc; -+ ucontext_t *uc = puc; - unsigned long pc = uc->uc_mcontext.sc_iaoq[0]; - uint32_t insn = *(uint32_t *)pc; - int is_write = 0; diff --git a/pkgs/tools/security/afl/qemu-patches/syscall.patch b/pkgs/tools/security/afl/qemu-patches/syscall.patch deleted file mode 100644 index 75d39386164e..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/syscall.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- qemu-2.3.0/linux-user/syscall.c.orig 2014-12-09 14:45:43.000000000 +0000 -+++ qemu-2.3.0/linux-user/syscall.c 2015-03-27 06:33:00.736000000 +0000 -@@ -227,7 +227,21 @@ - _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo) - _syscall3(int,sys_syslog,int,type,char*,bufp,int,len) - #if defined(TARGET_NR_tgkill) && defined(__NR_tgkill) --_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig) -+ -+extern unsigned int afl_forksrv_pid; -+ -+static int sys_tgkill(int tgid, int pid, int sig) { -+ -+ /* Workaround for -lpthread to make abort() work properly, without -+ killing the forkserver due to a prematurely cached PID. */ -+ -+ if (afl_forksrv_pid && afl_forksrv_pid == pid && sig == SIGABRT) -+ pid = tgid = getpid(); -+ -+ return syscall(__NR_sys_tgkill, pid, tgid, sig); -+ -+} -+ - #endif - #if defined(TARGET_NR_tkill) && defined(__NR_tkill) - _syscall2(int,sys_tkill,int,tid,int,sig) diff --git a/pkgs/tools/security/afl/qemu-patches/translate-all.patch b/pkgs/tools/security/afl/qemu-patches/translate-all.patch deleted file mode 100644 index 180b3a55ab25..000000000000 --- a/pkgs/tools/security/afl/qemu-patches/translate-all.patch +++ /dev/null @@ -1,18 +0,0 @@ ---- qemu-2.3.0/translate-all.c.orig 2014-12-09 14:45:46.000000000 +0000 -+++ qemu-2.3.0/translate-all.c 2015-01-28 22:37:42.383000000 +0000 -@@ -393,8 +393,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 index 82de6474e598..a007eb3913db 100644 --- a/pkgs/tools/security/afl/qemu.nix +++ b/pkgs/tools/security/afl/qemu.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchurl, python2, zlib, pkgconfig, glib, ncurses, perl +{ stdenv, fetchurl, afl, python2, zlib, pkgconfig, glib, ncurses, perl , attr, libcap, vde2, texinfo, libuuid, flex, bison, lzo, snappy , libaio, libcap_ng, gnutls, pixman, autoconf , writeText @@ -7,59 +7,65 @@ with stdenv.lib; let - n = "qemu-2.3.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); - + qemuName = "qemu-2.10.0"; + aflName = afl.name; cpuTarget = if stdenv.hostPlatform.system == "x86_64-linux" then "x86_64-linux-user" else if stdenv.hostPlatform.system == "i686-linux" then "i386-linux-user" else throw "afl: no support for ${stdenv.hostPlatform.system}!"; in stdenv.mkDerivation rec { - name = "afl-${n}"; + name = "afl-${qemuName}"; - src = fetchurl { - url = "http://wiki.qemu.org/download/${n}.tar.bz2"; - sha256 = "120m53c3p28qxmfzllicjzr8syjv6v4d9rsyrgkp7gnmcgvvgfmn"; - }; + srcs = [ + (fetchurl { + url = "http://wiki.qemu.org/download/${qemuName}.tar.bz2"; + sha256 = "0j3dfxzrzdp1w21k21fjvmakzc6lcha1rsclaicwqvbf63hkk7vy"; + }) + afl.src + ]; - buildInputs = - [ python2 zlib pkgconfig glib pixman ncurses perl attr libcap - vde2 texinfo libuuid flex bison lzo snappy autoconf - libcap_ng gnutls - ] - ++ optionals (hasSuffix "linux" stdenv.hostPlatform.system) [ libaio ]; + sourceRoot = qemuName; + + postUnpack = '' + cp ${aflName}/types.h $sourceRoot/afl-types.h + substitute ${aflName}/config.h $sourceRoot/afl-config.h \ + --replace "types.h" "afl-types.h" + substitute ${aflName}/qemu_mode/patches/afl-qemu-cpu-inl.h $sourceRoot/afl-qemu-cpu-inl.h \ + --replace "../../config.h" "afl-config.h" + substituteInPlace ${aflName}/qemu_mode/patches/cpu-exec.diff \ + --replace "../patches/afl-qemu-cpu-inl.h" "afl-qemu-cpu-inl.h" + ''; + + nativeBuildInputs = [ + python2 perl pkgconfig flex bison autoconf texinfo + ]; + + buildInputs = [ + zlib glib pixman ncurses attr libcap + vde2 libuuid lzo snappy libcap_ng gnutls + ] ++ optionals (stdenv.isLinux) [ libaio ]; enableParallelBuilding = true; - patches = - [ ./qemu-patches/elfload.patch - ./qemu-patches/cpu-exec.patch - ./qemu-patches/no-etc-install.patch - ./qemu-patches/translate-all.patch - ./qemu-patches/syscall.patch - ./qemu-patches/qemu-2.3.0-glibc-2.26.patch - ]; - - preConfigure = '' - cp ${aflTypesFile} afl-types.h - cp ${aflConfigFile} afl-config.h - cp ${aflHeaderFile} afl-qemu-cpu-inl.h - ''; + patches = [ + # patches extracted from afl source + "../${aflName}/qemu_mode/patches/cpu-exec.diff" + "../${aflName}/qemu_mode/patches/elfload.diff" + "../${aflName}/qemu_mode/patches/syscall.diff" + # nix-specific patches to make installation more well-behaved + ./qemu-patches/no-etc-install.patch + ./qemu-patches/qemu-2.10.0-glibc-2.27.patch + ]; configureFlags = [ "--disable-system" "--enable-linux-user" - "--enable-guest-base" "--disable-gtk" "--disable-sdl" "--disable-vnc" "--target-list=${cpuTarget}" + "--enable-pie" + "--enable-kvm" "--sysconfdir=/etc" "--localstatedir=/var" ];