1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
{ lib, stdenv, stdenvNoCC, fetchFromGitHub, callPackage, makeWrapper
, clang, llvm, gcc, which, libcgroup, python, perl, gmp
, file, wine ? null, fetchpatch
}:
# wine fuzzing is only known to work for win32 binaries, and using a mixture of
# 32 and 64-bit libraries ... complicates things, so it's recommended to build
# a full 32bit version of this package if you want to do wine fuzzing
assert (wine != null) -> (stdenv.targetPlatform.system == "i686-linux");
let
aflplusplus-qemu = callPackage ./qemu.nix { inherit aflplusplus; };
qemu-exe-name = if stdenv.targetPlatform.system == "x86_64-linux" then "qemu-x86_64"
else if stdenv.targetPlatform.system == "i686-linux" then "qemu-i386"
else throw "aflplusplus: no support for ${stdenv.targetPlatform.system}!";
libdislocator = callPackage ./libdislocator.nix { inherit aflplusplus; };
libtokencap = callPackage ./libtokencap.nix { inherit aflplusplus; };
aflplusplus = stdenvNoCC.mkDerivation rec {
pname = "aflplusplus";
version = "2.65c";
src = fetchFromGitHub {
owner = "AFLplusplus";
repo = "AFLplusplus";
rev = version;
sha256 = "1np2a3kypb2m8nyv6qnij18yzn41pl8619jzydci40br4vxial9l";
};
enableParallelBuilding = true;
# Note: libcgroup isn't needed for building, just for the afl-cgroup
# script.
nativeBuildInputs = [ makeWrapper which clang gcc ];
buildInputs = [ llvm python gmp ]
++ lib.optional (wine != null) python.pkgs.wrapPython;
postPatch = ''
# Replace the CLANG_BIN variables with the correct path
substituteInPlace llvm_mode/afl-clang-fast.c \
--replace "CLANGPP_BIN" '"${clang}/bin/clang++"' \
--replace "CLANG_BIN" '"${clang}/bin/clang"' \
--replace 'getenv("AFL_PATH")' "(getenv(\"AFL_PATH\") ? getenv(\"AFL_PATH\") : \"$out/lib/afl\")"
# Replace "gcc" and friends with full paths in afl-gcc
# Prevents afl-gcc picking up any (possibly incorrect) gcc from the path
substituteInPlace src/afl-gcc.c \
--replace '"gcc"' '"${gcc}/bin/gcc"' \
--replace '"g++"' '"${gcc}/bin/g++"' \
--replace '"gcj"' '"gcj-UNSUPPORTED"' \
--replace '"clang"' '"clang-UNSUPPORTED"' \
--replace '"clang++"' '"clang++-UNSUPPORTED"'
'';
makeFlags = [ "PREFIX=$(out)" ];
buildPhase = ''
common="$makeFlags -j$NIX_BUILD_CORES"
make all $common
make radamsa $common
make -C gcc_plugin CC=${gcc}/bin/gcc CXX=${gcc}/bin/g++ $common
make -C llvm_mode $common
make -C qemu_mode/libcompcov $common
make -C qemu_mode/unsigaction $common
'';
postInstall = ''
# remove afl-clang(++) which are just symlinks to afl-clang-fast
rm $out/bin/afl-clang $out/bin/afl-clang++
# the makefile neglects to install unsigaction
cp qemu_mode/unsigaction/unsigaction*.so $out/lib/afl/
# Install the custom QEMU emulator for binary blob fuzzing.
cp ${aflplusplus-qemu}/bin/${qemu-exe-name} $out/bin/afl-qemu-trace
# give user a convenient way of accessing libcompconv.so, libdislocator.so, libtokencap.so
cat > $out/bin/get-afl-qemu-libcompcov-so <<END
#!${stdenv.shell}
echo $out/lib/afl/libcompcov.so
END
chmod +x $out/bin/get-afl-qemu-libcompcov-so
cp ${libdislocator}/bin/get-libdislocator-so $out/bin/
cp ${libtokencap}/bin/get-libtokencap-so $out/bin/
# Install the cgroups wrapper for asan-based fuzzing.
cp examples/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"
patchShebangs $out/bin
'' + lib.optionalString (wine != null) ''
substitute afl-wine-trace $out/bin/afl-wine-trace \
--replace "qemu_mode/unsigaction" "$out/lib/afl"
chmod +x $out/bin/afl-wine-trace
# qemu needs to be fed ELFs, not wrapper scripts, so we have to cheat a bit if we
# detect a wrapped wine
for winePath in ${wine}/bin/.wine ${wine}/bin/wine; do
if [ -x $winePath ]; then break; fi
done
makeWrapperArgs="--set-default 'AFL_WINE_PATH' '$winePath'" \
wrapPythonProgramsIn $out/bin ${python.pkgs.pefile}
'';
installCheckInputs = [ perl file ];
doInstallCheck = true;
installCheckPhase = ''
# replace references to tools in build directory with references to installed locations
substituteInPlace test/test.sh \
--replace '../libcompcov.so' '`$out/bin/get-afl-qemu-libcompcov-so`' \
--replace '../libdislocator.so' '`$out/bin/get-libdislocator-so`' \
--replace '../libtokencap.so' '`$out/bin/get-libtokencap-so`'
perl -pi -e 's|(?<!\.)(?<!-I)(\.\./)([^\s\/]+?)(?<!\.c)(?<!\.s?o)(?=\s)|\$out/bin/\2|g' test/test.sh
cd test && ./test.sh
'';
passthru = {
inherit libdislocator libtokencap;
qemu = aflplusplus-qemu;
};
meta = {
description = ''
A heavily enhanced version of AFL, incorporating many features
and improvements from the community
'';
homepage = "https://aflplus.plus";
license = lib.licenses.asl20;
platforms = ["x86_64-linux" "i686-linux"];
maintainers = with lib.maintainers; [ ris mindavi ];
};
};
in aflplusplus
|