1{
2 lib,
3 stdenv,
4 stdenvNoCC,
5 fetchFromGitHub,
6 callPackage,
7 makeWrapper,
8 clang,
9 llvm,
10 gcc,
11 which,
12 libcgroup,
13 python3,
14 perl,
15 gmp,
16 file,
17 wine ? null,
18 cmocka,
19 llvmPackages,
20}:
21
22# wine fuzzing is only known to work for win32 binaries, and using a mixture of
23# 32 and 64-bit libraries ... complicates things, so it's recommended to build
24# a full 32bit version of this package if you want to do wine fuzzing
25assert (wine != null) -> (stdenv.targetPlatform.system == "i686-linux");
26
27let
28 aflplusplus-qemu = callPackage ./qemu.nix { };
29 qemu-exe-name =
30 if stdenv.targetPlatform.system == "x86_64-linux" then
31 "qemu-x86_64"
32 else if stdenv.targetPlatform.system == "i686-linux" then
33 "qemu-i386"
34 else
35 throw "aflplusplus: no support for ${stdenv.targetPlatform.system}!";
36 libdislocator = callPackage ./libdislocator.nix { inherit aflplusplus; };
37 libtokencap = callPackage ./libtokencap.nix { inherit aflplusplus; };
38 aflplusplus = stdenvNoCC.mkDerivation rec {
39 pname = "aflplusplus";
40 version = "4.32c";
41
42 src = fetchFromGitHub {
43 owner = "AFLplusplus";
44 repo = "AFLplusplus";
45 tag = "v${version}";
46 hash = "sha256-Fhf7dHyHd8IGXq7t1y9TwN9VN8SckLRkgfGGMvmqIqk=";
47 };
48
49 enableParallelBuilding = true;
50
51 # Note: libcgroup isn't needed for building, just for the afl-cgroup
52 # script.
53 nativeBuildInputs = [
54 makeWrapper
55 which
56 clang
57 gcc
58 ];
59 buildInputs = [
60 llvm
61 python3
62 gmp
63 llvmPackages.bintools
64 ]
65 ++ lib.optional (wine != null) python3.pkgs.wrapPython;
66
67 # Flag is already set by package and causes some compiler warnings.
68 # warning: "_FORTIFY_SOURCE" redefined
69 hardeningDisable = [ "fortify" ];
70
71 postPatch = ''
72 # Don't care about this.
73 rm Android.bp
74
75 # Replace the CLANG_BIN variables with the correct path.
76 # Replace "gcc" and friends with full paths in afl-gcc.
77 # Prevents afl-gcc picking up any (possibly incorrect) gcc from the path.
78 # Replace LLVM_BINDIR with a non-existing path to give a hard error when it's used.
79 substituteInPlace src/afl-cc.c \
80 --replace-fail "CLANGPP_BIN" '"${clang}/bin/clang++"' \
81 --replace-fail "CLANG_BIN" '"${clang}/bin/clang"' \
82 --replace-fail '"gcc"' '"${gcc}/bin/gcc"' \
83 --replace-fail '"g++"' '"${gcc}/bin/g++"' \
84 --replace-fail 'getenv("AFL_PATH")' "(getenv(\"AFL_PATH\") ? getenv(\"AFL_PATH\") : \"$out/lib/afl\")"
85
86 substituteInPlace src/afl-ld-lto.c \
87 --replace-fail 'LLVM_BINDIR' '"/nixpkgs-patched-does-not-exist"'
88
89 # Remove the rest of the line
90 sed -i 's|LLVM_BINDIR = .*|LLVM_BINDIR = |' utils/aflpp_driver/GNUmakefile
91 substituteInPlace utils/aflpp_driver/GNUmakefile \
92 --replace-fail 'LLVM_BINDIR = ' 'LLVM_BINDIR = ${clang}/bin/'
93
94 substituteInPlace GNUmakefile.llvm \
95 --replace-fail "\$(LLVM_BINDIR)/clang" "${clang}/bin/clang"
96 '';
97
98 env.NIX_CFLAGS_COMPILE = toString [
99 # Needed with GCC 12
100 "-Wno-error=use-after-free"
101 ];
102
103 makeFlags = [
104 "PREFIX=${placeholder "out"}"
105 "USE_BINDIR=0"
106 ];
107
108 buildPhase = ''
109 runHook preBuild
110
111 common="$makeFlags -j$NIX_BUILD_CORES"
112 make distrib $common
113 make -C qemu_mode/libcompcov $common
114 make -C qemu_mode/unsigaction $common
115
116 runHook postBuild
117 '';
118
119 postInstall = ''
120 # remove afl-clang(++) which are just symlinks to afl-clang-fast
121 rm $out/bin/afl-clang $out/bin/afl-clang++
122
123 # the makefile neglects to install unsigaction
124 cp qemu_mode/unsigaction/unsigaction*.so $out/lib/afl/
125
126 # Install the custom QEMU emulator for binary blob fuzzing.
127 ln -s ${aflplusplus-qemu}/bin/${qemu-exe-name} $out/bin/afl-qemu-trace
128
129 # give user a convenient way of accessing libcompconv.so, libdislocator.so, libtokencap.so
130 cat > $out/bin/get-afl-qemu-libcompcov-so <<END
131 #!${stdenv.shell}
132 echo $out/lib/afl/libcompcov.so
133 END
134 chmod +x $out/bin/get-afl-qemu-libcompcov-so
135 ln -s ${libdislocator}/bin/get-libdislocator-so $out/bin/
136 ln -s ${libtokencap}/bin/get-libtokencap-so $out/bin/
137
138 # Install the cgroups wrapper for asan-based fuzzing.
139 cp utils/asan_cgroups/limit_memory.sh $out/bin/afl-cgroup
140 chmod +x $out/bin/afl-cgroup
141 substituteInPlace $out/bin/afl-cgroup \
142 --replace-fail "cgcreate" "${libcgroup}/bin/cgcreate" \
143 --replace-fail "cgexec" "${libcgroup}/bin/cgexec" \
144 --replace-fail "cgdelete" "${libcgroup}/bin/cgdelete"
145
146 patchShebangs $out/bin
147
148 ''
149 + lib.optionalString (wine != null) ''
150 substitute afl-wine-trace $out/bin/afl-wine-trace \
151 --replace-fail "qemu_mode/unsigaction" "$out/lib/afl"
152 chmod +x $out/bin/afl-wine-trace
153
154 # qemu needs to be fed ELFs, not wrapper scripts, so we have to cheat a bit if we
155 # detect a wrapped wine
156 for winePath in ${wine}/bin/.wine ${wine}/bin/wine; do
157 if [ -x $winePath ]; then break; fi
158 done
159 makeWrapperArgs="--set-default 'AFL_WINE_PATH' '$winePath'" \
160 wrapPythonProgramsIn $out/bin ${python3.pkgs.pefile}
161 '';
162
163 nativeInstallCheckInputs = [
164 perl
165 file
166 cmocka
167 ];
168 doInstallCheck = true;
169 installCheckPhase = ''
170 runHook preInstallCheck
171
172 # replace references to tools in build directory with references to installed locations
173 substituteInPlace test/test-qemu-mode.sh \
174 --replace-fail '../libcompcov.so' '`$out/bin/get-afl-qemu-libcompcov-so`' \
175 --replace-fail '../afl-qemu-trace' '$out/bin/afl-qemu-trace' \
176 --replace-fail '../afl-fuzz' '$out/bin/afl-fuzz' \
177 --replace-fail '../qemu_mode/unsigaction/unsigaction32.so' '$out/lib/afl/unsigaction32.so' \
178 --replace-fail '../qemu_mode/unsigaction/unsigaction64.so' '$out/lib/afl/unsigaction64.so'
179
180 substituteInPlace test/test-libextensions.sh \
181 --replace-fail '../libdislocator.so' '`$out/bin/get-libdislocator-so`' \
182 --replace-fail '../libtokencap.so' '`$out/bin/get-libtokencap-so`'
183 substituteInPlace test/test-llvm.sh \
184 --replace-fail '../afl-cmin.bash' '`$out/bin/afl-cmin.bash`'
185 # perl -pi -e 's|(?<!\.)(?<!-I)(\.\./)([^\s\/]+?)(?<!\.c)(?<!\.s?o)(?=\s)|\$out/bin/\2|g' test/test.sh
186 patchShebangs .
187 cd test && ./test-all.sh
188
189 runHook postInstallCheck
190 '';
191
192 passthru = {
193 inherit libdislocator libtokencap;
194 qemu = aflplusplus-qemu;
195 };
196
197 meta = {
198 description = ''
199 Heavily enhanced version of AFL, incorporating many features
200 and improvements from the community
201 '';
202 homepage = "https://aflplus.plus";
203 changelog = "https://aflplus.plus/docs/changelog";
204 license = lib.licenses.asl20;
205 platforms = [
206 "x86_64-linux"
207 "i686-linux"
208 ];
209 maintainers = with lib.maintainers; [
210 ris
211 mindavi
212 msanft
213 ];
214 };
215 };
216in
217aflplusplus