Brifing

Optimizing Fuzz Testing Workflows with AFL++

Practical techniques to enhance software defect discovery using advanced AFL++ fuzzing strategies.

1Fuzzing as a Standard Practice

Fuzz testing remains underutilized despite its ability to uncover critical software defects. By applying these techniques to source-available C and C++ projects on glibc-based Linux, developers can identify bugs that traditional testing misses. Everything is potentially broken, and systematic fuzzing provides a reliable mechanism to find low-hanging fruit in complex codebases.

2Leveraging Sanitizers for Visibility

Effective fuzzing requires robust assertions, which sanitizers provide automatically. Always enable Address Sanitizer (ASan) and Undefined Behavior Sanitizer (UBSan) during compilation. Configure ASAN_OPTIONS to abort on error and disable symbolization for debugger compatibility. Increasing sensitivity by detecting use-after-return bugs significantly improves the likelihood of catching elusive memory-related vulnerabilities during execution.

3Optimizing Memory Allocation Patterns

Default ASan configurations often fail to detect bugs beyond the initial 4KiB of memory allocations. To improve isolation and bug detection, increase the max_malloc_fill_size to cover all allocations. This ensures that uninitialized memory is filled with a pattern, preventing hidden bugs from persisting across tests and improving overall test reliability.

4Adopting AFL++ Persistent Mode

While in-place fuzzing is convenient, persistent mode using afl-gcc-fast or afl-clang-fast is essential for performance. It operates an order of magnitude faster than standard methods. Use a standardized template to manage the fuzzing loop, ensuring that buffers are correctly handled and that the target process resets efficiently between test iterations.

5Simplifying Build Configurations

Avoid complex build systems by including necessary source files directly into the fuzzing template. This technique allows you to test arbitrary functions, including static ones, without modifying original source code. By treating the fuzz test as a single translation unit, you bypass the need for separate object file management during development.

6Handling Tightly Coupled Components

When programs are not designed for testing, use preprocessor macros to substitute problematic symbols or remove main functions. This allows for rapid, drive-by security reviews of open-source projects. By creating a controlled environment, you can generate simple, reproducible bug reports that demonstrate crashes without requiring extensive modifications to the original codebase structure.

7Ensuring Test Isolation

Persistent mode requires strict isolation between tests to prevent state contamination. Reset all global variables and avoid passing uninitialized memory to targets. If a program relies on global state, such as internal buffers, ensure they are cleared before each iteration. This prevents difficult-to-reproduce bugs caused by stale data from previous test runs.

8Correct Buffer Handling Practices

Never pass raw AFL++ buffers directly to the target, as this hides read overflows. Always create a size-fit copy of the input data. This ensures that ASan can accurately detect overflows and allows for necessary modifications, such as appending null terminators, which are often required by standard C library functions.

9Managing File System Interfaces

When targets require file system paths, use memfd_create to generate memory file descriptors. This avoids disk I/O, reduces SSD wear, and enables parallel fuzzing by providing unique paths via /proc. For interfaces expecting FILE pointers, utilize fdmemopen to create streams directly from memory buffers without needing to manage file descriptor lifecycles.

10Reducing Fixed Buffer Sizes

Programs often contain overly generous fixed buffer sizes that hide potential overflows. During fuzz testing, manually reduce these limits to force the code into worst-case execution paths. This technique helps trigger crashes more quickly, allowing you to identify vulnerabilities that would otherwise remain dormant under normal, non-fuzzed operating conditions.

Original article: Hacker News (news.ycombinator.com) — Optimizing Fuzz Testing Workflows with AFL++