Skip to content

Commit 73d0d02

Browse files
authored
Merge pull request #110 from trailofbits/aflpp-improvements-from-skills-pr15
Update AFL++ documentation with bug fixes and improvements
2 parents 9fbf879 + e16c495 commit 73d0d02

File tree

1 file changed

+45
-26
lines changed
  • content/docs/fuzzing/c-cpp/11-aflpp

1 file changed

+45
-26
lines changed

content/docs/fuzzing/c-cpp/11-aflpp/index.md

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The AFL++ fuzzer has many dependencies, such as LLVM, Python, and Rust. We recom
2424
<td><strong>Method</strong></td>
2525
<td><strong>When should I use it?</strong></td>
2626
<td>
27-
<strong>Supported compiler versions (<code>afl-clang/afl-gcc --version</code>)</strong>
27+
<strong>Supported compiler versions (<code>afl-clang-fast/afl-gcc --version</code>)</strong>
2828
</td>
2929
</tr>
3030
<tr>
@@ -57,7 +57,7 @@ The AFL++ fuzzer has many dependencies, such as LLVM, Python, and Rust. We recom
5757
</li>
5858
</ul>
5959
</td>
60-
<td>As of writing for version 4.09c of the image Clang 14 & GCC 11</td>
60+
<td>As of writing for version 4.35c of the image Clang 19 & GCC 11</td>
6161
</tr>
6262
<tr>
6363
<td>Docker (from source)</td>
@@ -88,7 +88,7 @@ The AFL++ fuzzer has many dependencies, such as LLVM, Python, and Rust. We recom
8888
</td>
8989
<td>
9090
Adjustable by setting the environment variable
91-
<code>LLVM_CONFIG</code> for example to <code>llvm-config-14</code>.
91+
<code>LLVM_CONFIG</code> for example to <code>llvm-config-18</code>.
9292
</td>
9393
</tr>
9494
</table>
@@ -100,12 +100,14 @@ The AFL++ fuzzer has many dependencies, such as LLVM, Python, and Rust. We recom
100100
If you run a recent Debian or Ubuntu version, the packaged version in the official Ubuntu repositories is an easy choice. At the time of writing, Ubuntu 23.10 packages AFL++ 4.08c and Debian 12 version 4.04c. Note that this will limit you to the Clang version supported by the packaged AFL++ version.
101101

102102

103+
Note: Check which Clang version AFL++ uses on your distribution before installing `lld`. Run `afl-cc --version` to verify, then install the matching `lld` version (e.g., `lld-17`).
104+
103105
```shell
104-
apt install afl++ lld-14
106+
apt install afl++ lld-17
105107
```
106108

107109

108-
Installing the `lld` package is required for the optional LTO mode that we will describe later. Depending on the Clang version AFL++ uses on your Linux distributions, you may want to install a specific version of `lld` like `lld-16`. Verify the output of `afl-cc --version`.
110+
Installing the `lld` package is required for the optional LTO mode that we will describe later. Depending on the Clang version AFL++ uses on your Linux distributions, you may want to install a specific version of `lld` like `lld-17`. Verify the output of `afl-cc --version`.
109111

110112

111113
### Docker (from Docker Hub) {#docker-from-docker-hub}
@@ -198,7 +200,7 @@ reboot
198200
./afl++ <host/docker> afl-system-config
199201
```
200202

201-
After the reboot check whether the changes performed by `afl-persistent-config` were correctly applied by executing `cat` `/proc/cmdline`. The output should include `mitigations=off`. If not, then the grub bootloader was configured incorrectly: Verify the configuration in the file `/etc/default/grub` and the directory `/etc/default/grub.d/`. If any of the configuration files incorrectly overwrites `GRUB_CMDLINE_LINUX_DEFAULT` then mitigations are potentially not applied. This is for example true for cloud environments that use [cloudinit](https://cloud-init.io/).
203+
After the reboot check whether the changes performed by `afl-persistent-config` were correctly applied by executing `cat` `/proc/cmdline`. The output should include `mitigations=off`. If not, then the grub bootloader was configured incorrectly: Verify the configuration in the file `/etc/default/grub` and the directory `/etc/default/grub.d/`. If any of the configuration files incorrectly overwrites `GRUB_CMDLINE_LINUX_DEFAULT` then mitigations are potentially not applied. This is for example true for cloud environments that use [cloud-init](https://cloudinit.readthedocs.io/).
202204

203205

204206
{{< hint danger >}}
@@ -209,50 +211,48 @@ After the reboot check whether the changes performed by `afl-persistent-config`
209211

210212
Creating a binary that fuzzes the SUT is straightforward. The resulting binary will use the harness and the AFL++ runtime.
211213

212-
The AFL++ fuzzer offers multiple compilation modes, including [LTO](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.lto.md), [LLVM](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.llvm.md), [GCC](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.gcc_plugin.md), and a legacy Clang mode. Refer to the linked documentation for more information about each. In order to decide for one, refer to the following figure:
214+
The AFL++ fuzzer offers multiple compilation modes, including [LTO](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.lto.md), [LLVM](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.llvm.md), and [GCC](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.gcc_plugin.md). Refer to the linked documentation for more information about each. In order to decide for one, refer to the following figure:
213215

214216

215217
{{< resourceFigure "aflpp-decision.drawio.svg" />}}
216218

217219

218-
Depending on the mode you choose, use a different compilation command: `afl-clang-lto`, `afl-clang-fast`, `afl-gcc`, or `afl-clang`, respectively. The C++ versions are also available by appending `++`, which gives, e.g., `afl-clang-lto++`. The LTO mode is recommended because it features a better and faster instrumentation of the SUT. However, this depends on your project whether LTO mode works. Give it a try and fall back to the other modes if compilation fails.
220+
Depending on the mode you choose, use a different compilation command: `afl-clang-lto`, `afl-clang-fast`, or `afl-gcc`, respectively. The C++ versions are also available by appending `++`, which gives, e.g., `afl-clang-lto++`. The LTO mode is recommended because it features a better and faster instrumentation of the SUT. However, this depends on your project whether LTO mode works. Give it a try and fall back to the other modes if compilation fails.
219221

220222
If you use the Clang compiler and want to use the LLVM mode, then the following command produces a binary `fuzzer`. Essentially, we are replacing the call to `clang++` with `afl-clang-fast++`. We are reusing the `harness.cc` and `main.cc` from the [introduction]({{% relref "fuzzing#introduction-to-fuzzers" %}})
221223

222224

223-
{{< tooltipHighlight shell
225+
{{< tooltipHighlight shell
224226
"Custom script (see above)"
225227
"Run on host or within Docker"
226228
"AFL++ compiler that uses Clang"
227229
"Skips the main function"
228-
"Adds debug symbols"
229230
"Sets production optimization level"
230231
"Enables libFuzzer"
231232
>}}
232-
./afl++ <host/docker> afl-clang-fast++ -DNO_MAIN -g -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
233+
./afl++ <host/docker> afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
233234
{{< / tooltipHighlight >}}
234235
235236

236237
If your project depends on the GCC compiler, then consider using the [gcc_plugin](https://github.com/AFLplusplus/AFLplusplus/blob/stable/instrumentation/README.gcc_plugin.md):
237238

238-
{{< tooltipHighlight shell
239+
{{< tooltipHighlight shell
239240
"Custom script (see above)"
240241
"Run on host or within Docker"
241242
"AFL++ compiler that uses GCC"
242243
"Skips the main function"
243-
"Adds debug symbols"
244244
"Sets production optimization level"
245245
"Enables libFuzzer"
246246
>}}
247-
./afl++ <host/docker> afl-g++-fast -DNO_MAIN -g -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
247+
./afl++ <host/docker> afl-g++-fast -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main.cc -o fuzz
248248
{{< / tooltipHighlight >}}
249249
250250

251251
{{< hint info >}}
252252
PRO TIP: The GCC version of your system and the GCC version that was used to compile the AFL++ GCC plugin must match. If they do not match (e.g., if you upgrade GCC), then you will get an error when using the GCC support.
253253
{{< /hint >}}
254254

255-
We also enable debug symbols using `-g` and set the optimization level to `-O2`, which is a reasonable optimization level for fuzzing because it is likely the level used during production.
255+
We set the optimization level to `-O2`, which is a reasonable optimization level for fuzzing because it is likely the level used during production. Note that `-g` is not necessary, it is added by default by the AFL++ compilers.
256256

257257
Many things are happening behind the scenes when using AFL++:
258258

@@ -270,7 +270,7 @@ To launch a fuzzing campaign, first create a seeds directory. This represents th
270270

271271
```shell
272272
mkdir seeds
273-
echo "a" > seeds/minimal_seed
273+
echo "aaaa" > seeds/minimal_seed
274274
```
275275

276276
Finally, we can launch the campaign.
@@ -280,10 +280,10 @@ Finally, we can launch the campaign.
280280
```
281281

282282
{{< hint info >}}
283-
PRO TIP: In order to demonstrate how to set environment variables with the afl++ script, try setting the environment variable AFL_PIZZA_MODE to 1 if you enjoy pineapple pizza:
284-
283+
PRO TIP: In order to demonstrate how to set environment variables with the afl++ script, try setting the environment variable AFL_FAST_CAL to 1 to speed up the initial calibration phase:
284+
285285
```shell
286-
./afl++ <host/docker> AFL_PIZZA_MODE=1 afl-fuzz -i seeds -o out -- ./fuzz
286+
./afl++ <host/docker> AFL_FAST_CAL=1 afl-fuzz -i seeds -o out -- ./fuzz
287287
```
288288
{{< /hint >}}
289289

@@ -357,7 +357,7 @@ Refer to the help page for more information about libFuzzer-compatible binaries
357357
The AFL++ fuzzer offers many options. The following options can be most useful with the `afl-fuzz` tool.
358358

359359
* **-G 4000** The maximum length of the test input. By default, AFL++ uses 1048576 bytes. Setting this at least a few times higher than the minimal input size is advised. As a rule of thumb, we recommend finding a minimal realistic input and then doubling that. Note that larger input sizes lead to longer execution times and do not necessarily lead to a larger input space being explored.
360-
* **-t 10000** AFL++ aborts the execution of a test case after n milliseconds. It makes sense to set this to something reasonably low. The goal is also to find inputs that cause the SUT to hang for an unreasonably long amount of time. For example, parsing a reasonable-sized PNG image should not take longer than a few hundred milliseconds. So setting this to a few seconds is usually enough not to get false positives.
360+
* **-t 1000** AFL++ aborts the execution of a test case after n milliseconds (default is 1000ms). It makes sense to set this to something reasonably low. The goal is also to find inputs that cause the SUT to hang for an unreasonably long amount of time. For example, parsing a reasonable-sized PNG image should not take longer than a few hundred milliseconds. So setting this to a few seconds is usually enough not to get false positives.
361361
* **-m 1000** The memory limit for test cases in megabytes. By default, this is set to 0, which means no limit. This should be set to a reasonable value like 1000. If this is set too low then you will see false positives, because occasionally test cases may take just slightly longer than usual (e.g., because of system load).
362362
* **-x ./dict.dict** Specifies a dictionary file that guides the fuzzer and allows the fuzzer to discover interesting test cases more quickly. For more details about this, see [Fuzzing dictionary]({{% relref 02-dictionary %}}).
363363

@@ -423,7 +423,7 @@ The example above reads now from standard input. It aborts for the input "abc".
423423
424424
425425
```shell
426-
./afl++ <host/docker> afl-clang-fast++ -g -O2 main_stdin.c -o fuzz_stdin
426+
./afl++ <host/docker> afl-clang-fast++ -O2 main_stdin.c -o fuzz_stdin
427427
```
428428

429429

@@ -584,7 +584,7 @@ As usual, we use the AFL++ compiler wrappers to create an instrumented binary.
584584

585585

586586
```shell
587-
./afl++ <host/docker> afl-clang-fast++ -g -O2 main_file.c -o fuzz_file
587+
./afl++ <host/docker> afl-clang-fast++ -O2 main_file.c -o fuzz_file
588588
```
589589

590590

@@ -658,7 +658,7 @@ We can now compile the instrumented binary and start the fuzzing as usual:
658658

659659

660660
```shell
661-
./afl++ <host/docker> afl-clang-fast++ -g -O2 main_arg.c -o fuzz_arg
661+
./afl++ <host/docker> afl-clang-fast++ -O2 main_arg.c -o fuzz_arg
662662
./afl++ <host/docker> afl-fuzz -i seeds -o out -- ./fuzz_arg
663663
```
664664

@@ -798,6 +798,25 @@ kill $(jobs -p)
798798
More information and advanced use cases can be found [here](https://aflplus.plus/docs/parallel_fuzzing/) and [here](https://aflplus.plus/docs/fuzzing_in_depth/#c-using-multiple-cores).
799799

800800

801+
## CMPLOG {#cmplog}
802+
803+
CMPLOG/RedQueen is the best path constraint solving mechanism available in any fuzzer.
804+
To enable it, the fuzz target needs to be instrumented for it.
805+
Before building the fuzzing target set the environment variable:
806+
807+
```shell
808+
./afl++ <host/docker> AFL_LLVM_CMPLOG=1 make
809+
```
810+
811+
No special action is needed for compiling and linking the harness.
812+
813+
To run a fuzzer instance with a CMPLOG instrumented fuzzing target, add `-c0` to the command line arguments:
814+
815+
```shell
816+
./afl++ <host/docker> afl-fuzz -c0 -S cmplog -i seeds -o state -- ./fuzz 1>cmplog.log 2>cmplog.error &
817+
```
818+
819+
801820
## AddressSanitizer {#addresssanitizer}
802821

803822
ASan helps detect memory errors that may otherwise go unnoticed. For instance, the following heap buffer overflow is usually not detectable without ASan.
@@ -829,7 +848,7 @@ To enable AddressSanitizer when using AFL++, set the environment variable `AFL_U
829848
For example, to use ASan to find the bug in main_asan.cc, first compile using the corresponding flags:
830849
831850
```shell
832-
./afl++ <host/docker> AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN -g -O2 -fsanitize=fuzzer harness.cc main_asan.cc -o fuzz
851+
./afl++ <host/docker> AFL_USE_ASAN=1 afl-clang-fast++ -DNO_MAIN=1 -O2 -fsanitize=fuzzer harness.cc main_asan.cc -o fuzz
833852
```
834853

835854
When running the fuzzer, the above heap-buffer overflow will be discovered by the fuzzer. The settable memory limit via the `-m` flag is not supported with ASan because ASan allocates a huge amount of virtual memory: 20TB, which exceeds any reasonable memory limit.
@@ -933,7 +952,7 @@ add_executable(buggy_program main.cc)
933952
934953
add_executable(fuzz main.cc harness.cc)
935954
target_compile_definitions(fuzz PRIVATE NO_MAIN=1)
936-
target_compile_options(fuzz PRIVATE -g -O2 -fsanitize=fuzzer)
955+
target_compile_options(fuzz PRIVATE -O2 -fsanitize=fuzzer-no-link)
937956
target_link_libraries(fuzz -fsanitize=fuzzer)
938957
```
939958
{{< /customFigure >}}
@@ -968,6 +987,6 @@ More examples of different build systems can be found [here](https://aflplus.plu
968987

969988
## Additional resources {#additional-resources}
970989

971-
* [PAFL++: Combining Incremental Steps of Fuzzing Research.](https://www.usenix.org/system/files/woot20-paper-fioraldi.pdf)** Paper about AFL++.
990+
* **[AFL++: Combining Incremental Steps of Fuzzing Research.](https://www.usenix.org/system/files/woot20-paper-fioraldi.pdf)** Paper about AFL++.
972991
* **[Fuzzing in Depth.](https://aflplus.plus/docs/fuzzing_in_depth/)** Advanced documentation by the AFL++ team.
973992
* **[AFL++ Under The Hood.](https://blog.ritsec.club/posts/afl-under-hood/)** Blog post about AFL++ internals.

0 commit comments

Comments
 (0)