GCC Plugin Instrumentation
Relevant source files
The following files were used as context for generating this wiki page:GCC Plugin Instrumentation is a method within AFL++ that uses a GCC plugin for true compiler-level instrumentation. This approach provides an alternative to the assembly-level rewriting of the obsolete afl-gcc and the more commonly used LLVM-based instrumentation. The primary wrappers for this feature are afl-gcc-fast and afl-g++-fast.
The main advantages of this method include better compiler optimizations, leading to faster execution for some CPU-bound targets, and CPU-independent instrumentation. This allows fuzzing on non-x86 architectures. It supports several advanced features, including Selective Instrumentation, CMPLOG, Persistent Mode, and Deferred Initialization.
Sources: instrumentation/README.gcc_plugin.md:12-25
How to Use
To use the GCC plugin, you must have GCC version 4.5.0 or newer, along with the corresponding plugin development headers. On Debian-based systems, this can be installed via the gcc-VERSION-plugin-dev package.
Sources: instrumentation/README.gcc_plugin.md:30-32
Build and Compilation
The build process generates the afl-gcc-fast and afl-g++-fast compiler wrappers. These wrappers then invoke the actual GCC compiler with the AFL++ plugin.
The following diagram illustrates the compilation flow:
This diagram shows the process of compiling a target with afl-gcc-fast.
Compilation Steps:
-
Build AFL++: Run
makein the AFL++ root directory. This will createafl-gcc-fastandafl-g++-fast. -
Set Compilers: Point the
CCandCXXenvironment variables to the AFL++ wrappers. The system'sgccandg++must match the version for which the plugin headers were installed. -
Configure and Build Target:
CC=/path/to/afl/afl-gcc-fast CXX=/path/to/afl/afl-g++-fast export CC CXX ./configure [...options...] make
Sources: instrumentation/README.gcc_plugin.md:36-50, src/afl-cc.c:1342-1345
Environment Variables
Several environment variables control the behavior of the GCC plugin instrumentation.
| Variable | Description |
|---|---|
AFL_CC / AFL_CXX | Specifies the path to the actual C/C++ compiler (e.g., gcc-10). This is necessary if the default gcc/g++ is not the version required by the plugin. |
AFL_GCC_CMPLOG | If set, enables the CMPLOG instrumentation to log comparison operands, aiding Redqueen-style mutations. |
AFL_GCC_ALLOWLIST | Path to a file containing a list of source files or functions to be instrumented. An alias for AFL_LLVM_ALLOWLIST. |
AFL_GCC_DENYLIST | Path to a file containing a list of source files or functions to be excluded from instrumentation. An alias for AFL_LLVM_DENYLIST. |
AFL_GCC_DISABLE_VERSION_CHECK | Disables the GCC version check, which can be useful when compiling a plugin that differs from the system-installed version. |
AFL_INST_RATIO | Honored by afl-gcc-fast to control the percentage of branches to instrument. |
AFL_USE_ASAN / AFL_HARDEN | Standard AFL++ environment variables for enabling sanitizers and hardening, which are supported by the GCC plugin wrapper. |
Sources: instrumentation/README.gcc_plugin.md:34-35, 52-54, 76-78, instrumentation/afl-gcc-common.h:97-108
Architecture
The GCC plugin instrumentation is managed by the afl-cc compiler wrapper. When afl-cc is invoked as afl-gcc-fast or when the GCC_PLUGIN mode is selected, it modifies the arguments passed to the real GCC compiler to load the AFL++ instrumentation plugin.
Sources: src/afl-cc.c:269-273, 1342-1345
afl-cc Wrapper
The afl-cc binary is the central component. Its logic for handling GCC plugin mode can be summarized as:
- Mode Detection:
afl-ccdetermines it should operate inGCC_PLUGINmode based on its invocation name (afl-gcc-fast) or environment variables (AFL_CC_COMPILER=GCC_PLUGIN). - Plugin Injection: It adds the
-fplugin=/path/to/afl-gcc-pass.soargument to the GCC command line. - CMPLOG Handling: If
AFL_GCC_CMPLOGis set, it also injectsafl-gcc-cmplog-pass.soandafl-gcc-cmptrs-pass.so. - Argument Filtering: It removes arguments that are incompatible with the plugin, such as
-pipe.
This sequence diagram shows the interaction:
This diagram shows how afl-cc acts as a wrapper to inject the GCC plugin during compilation.
Sources: src/afl-cc.c:1342-1345, 1515-1518
afl-gcc-pass.so Plugin
This shared object is the core of the instrumentation. It is a GCC plugin that operates on the GIMPLE intermediate representation of the code.
The plugin's logic is contained within the afl_base_pass struct, which inherits from gimple_opt_pass. Its main responsibilities are:
- Traversing the code's basic blocks.
- Inserting the AFL++ coverage instrumentation.
- Handling selective instrumentation by checking functions and source files against an allow/deny list.
Sources: instrumentation/afl-gcc-common.h:43-50
Key Features
Selective Instrumentation
The GCC plugin supports two methods for instrumenting only specific parts of a target program, which can help focus the fuzzer and reduce noise.
Sources: instrumentation/README.instrument_list.md:8-12
1. Source Code Directives
You can enable or disable coverage directly within the source code using macros. This requires adding __AFL_COVERAGE(); after the includes.
__AFL_COVERAGE_ON();: Enable coverage from this point.__AFL_COVERAGE_OFF();: Disable coverage from this point.__AFL_COVERAGE_DISCARD();: Reset all coverage gathered so far.__AFL_COVERAGE_SKIP();: Mark the current test case as unimportant.
Sources: instrumentation/README.instrument_list.md:20-33, src/afl-cc.c:641-657
2. Allow/Deny Lists
A more flexible method is to provide a file that specifies which source files or functions to include or exclude from instrumentation. This is controlled by AFL_GCC_ALLOWLIST or AFL_GCC_DENYLIST.
The list file format supports comments (#) and can specify files and functions using prefixes:
src: path/to/file.cfun: function_name
If no prefix is given, the plugin infers the type based on whether the entry contains a / or .. UNIX-style pattern matching (*, ?) is also supported.
The logic for checking the list is as follows:
This diagram shows the decision process for instrumenting a function based on deny and allow lists.
Sources: instrumentation/README.instrument_list.md:39-95, instrumentation/afl-gcc-common.h:182-348
CMPLOG
The GCC plugin supports CMPLOG (comparative logging), a feature inspired by Redqueen that helps solve magic-byte comparisons. It is enabled by setting the AFL_GCC_CMPLOG=1 environment variable before compilation. The afl-cc wrapper detects this and loads afl-gcc-cmplog-pass.so and afl-gcc-cmptrs-pass.so to instrument comparison instructions.
Sources: instrumentation/README.gcc_plugin.md:76-78, src/afl-cc.c:1342-1345
Testing
The functionality of the GCC plugin is verified by the test/test-gcc-plugin.sh script. This script performs a series of checks to ensure the instrumentation works as expected.
The test flow is as follows:
- Basic Compilation & Instrumentation Check:
- Compiles
test-instr.cusingafl-gcc-fast. - Runs
afl-showmapwith two different inputs. - Verifies that the resulting coverage maps are different.
- Checks if the number of instrumented tuples is within a reasonable range.
- Compiles
- Hardened Mode Check:
- Compiles
test-compcov.cwithAFL_HARDEN=1. - Uses
nmto check for stack protection symbols (stack_chk_fail, etc.).
- Compiles
- Allowlist Feature Check:
- Creates an
instrumentlist.txtto excludetest-compcov.c. - Compiles with
AFL_GCC_INSTRUMENT_FILEset. - Runs
afl-showmapand asserts that "Captured 0 tuples", confirming that instrumentation was skipped.
- Creates an
- Persistent Mode Check:
- Compiles
persistent_demo.cwithafl-gcc-fast. - Runs
afl-showmapto verify that the persistent mode feature compiles and works correctly.
- Compiles
Sources: test/test-gcc-plugin.sh
A snippet from the test script demonstrates the allowlist verification:
# from test/test-gcc-plugin.sh
echo foobar.c > instrumentlist.txt
AFL_GCC_INSTRUMENT_FILE=instrumentlist.txt ../afl-gcc-fast -o test-compcov test-compcov.c > /dev/null 2>&1
test -x test-compcov && test_compcov_binary_functionality ./test-compcov && {
echo 1 | AFL_QUIET=1 ../afl-showmap -m ${MEM_LIMIT} -o - -r -- ./test-compcov 2>&1 | grep -q "Captured 0 tuples" && {
$ECHO "$GREEN[+] gcc_plugin instrumentlist feature works correctly"
} || {
$ECHO "$RED[!] gcc_plugin instrumentlist feature failed"
CODE=1
}
}
Sources: test/test-gcc-plugin.sh:84-96
Conclusion
The GCC plugin instrumentation provides a powerful and efficient way to instrument targets for fuzzing with AFL++. It offers performance comparable to or better than other methods for certain targets and integrates seamlessly with advanced AFL++ features like CMPLOG and selective instrumentation. Its CPU-agnostic nature also makes it a valuable tool for fuzzing on diverse hardware platforms.