Skip to content

Commit 8034d91

Browse files
committed
Add AFL++ fuzzing instrumentation capability
For AFL itself, when enabled via the AFL variable will search for the base afl-cc/afl-c++ compiler wrappers, and if found use them. Then any options specified at configuration time such as the speicifc mode or options must be specified. Because of the nature of having to change the compiler, this file must be included at a very early stage before the compilers are detected and verified. Since it supports sanitizers, the sanitizers file has been updated to add the appropriate flags when AFL is enabled.
1 parent f757425 commit 8034d91

File tree

3 files changed

+187
-0
lines changed

3 files changed

+187
-0
lines changed

README.md

+36
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ This is a collection of quite useful scripts that expand the possibilities for b
1515
- [1b - Via target commands](#1b---via-target-commands)
1616
- [Example 2: Target instrumented, but with regex pattern of files to be excluded from report](#example-2-target-instrumented-but-with-regex-pattern-of-files-to-be-excluded-from-report)
1717
- [Example 3: Target added to the 'ccov' and 'ccov-all' targets](#example-3-target-added-to-the-ccov-and-ccov-all-targets)
18+
- [AFL Fuzzing Instrumentation `afl-fuzzing.cmake`](#afl-fuzzing-instrumentation-afl-fuzzingcmake)
19+
- [Usage](#usage-1)
1820
- [Compiler Options `compiler-options.cmake`](#compiler-options-compiler-optionscmake)
1921
- [Dependency Graph `dependency-graph.cmake`](#dependency-graph-dependency-graphcmake)
2022
- [Required Arguments](#required-arguments)
@@ -182,6 +184,40 @@ add_executable(theExe main.cpp non_covered.cpp)
182184
target_code_coverage(theExe AUTO ALL EXCLUDE non_covered.cpp test/*) # As an executable target, adds to the 'ccov' and ccov-all' targets, and the reports will exclude the non-covered.cpp file, and any files in a test/ folder.
183185
```
184186

187+
## AFL Fuzzing Instrumentation [`afl-fuzzing.cmake`](afl-fuzzing.cmake)
188+
189+
> American fuzzy lop is a security-oriented fuzzer that employs a novel type of compile-time instrumentation and genetic algorithms to automatically discover clean, interesting test cases that trigger new internal states in the targeted binary. This substantially improves the functional coverage for the fuzzed code. The compact synthesized corpora produced by the tool are also useful for seeding other, more labor- or resource-intensive testing regimes down the road.
190+
>
191+
> [american fuzzy lop](https://lcamtuf.coredump.cx/afl/)
192+
193+
NOTE: This actually works based off the still-developed daughter project [AFL++](https://aflplus.plus/).
194+
195+
### Usage
196+
197+
To enable the use of AFL instrumentation, this file needs to be included into the CMake scripts at any point *before* any of the compilers are setup by CMake, typically at/before the first call to project(), or any part before compiler detection/validation occurs. This is since CMake does not support changing the compiler after it has been set:
198+
199+
```
200+
cmake_minimum_required(VERSION 3.4)
201+
include(cmake/afl-fuzzing.cmake)
202+
project(Example C CXX)
203+
```
204+
205+
Using `-DAFL=ON` will search for and switch to the AFL++ compiler wrappers that will instrument builds, or error if it cannot.
206+
207+
Using `-DAFL_MODE=<MODE>` will attempt to use the specified instrumentation type, see [here](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md). Options are:
208+
- LTO
209+
- LLVM
210+
- GCC-PLUGIN
211+
- CLANG
212+
- GCC
213+
214+
Using `-DAFL_ENV_OPTIONS=<...;...>` allows adding any number of AFL++'s instrumentation enabled via environment variables, and these will be prefixed to the build calls (see `afl-cc -hh`).
215+
216+
As an example, a CMake configuration such as this:
217+
```cmake .. -DAFL_MODE=LTO -DAFL_ENV_OPTIONS=AFL_LLVM_THREADSAFE_INST=1;AFL_LLVM_LAF_ALL=1```
218+
would result in build commands such as this:
219+
```AFL_LLVM_THREADSAFE_INST=1 AFL_LLVM_LAF_ALL=1 afl-clang-lto --afl-lto <...>```
220+
185221
## Compiler Options [`compiler-options.cmake`](compiler-options.cmake)
186222

187223
Allows for easy use of some pre-made compiler options for the major compilers.

afl-fuzzing.cmake

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#
2+
# Copyright (C) 2022 by George Cave - [email protected]
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
# use this file except in compliance with the License. You may obtain a copy of
6+
# the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
# License for the specific language governing permissions and limitations under
14+
# the License.
15+
16+
# USAGE: To enable the use of AFL instrumentation, this file needs to be
17+
# included into the CMake scripts at any point *before* any of the compilers are
18+
# setup by CMake, typically at/before the first call to project(), or any part
19+
# before compiler detection/validation occurs.
20+
#
21+
# This is since CMake does not support changing the compiler after it has been
22+
# set.
23+
#
24+
# For example for CMakeLists.txt:
25+
# ~~~
26+
# cmake_minimum_required(VERSION 3.15)
27+
# include(cmake/afl-fuzzing.cmake)
28+
# project(FoE-Engine C CXX)
29+
# ~~~
30+
# And then configuring CMake with: `cmake .. -DAFL_MODE=LTO
31+
# -DAFL_ENV_OPTIONS=AFL_LLVM_THREADSAFE_INST=1;AFL_LLVM_LAF_ALL=1`
32+
#
33+
# Would setup the AFL compiler to use the LTO mode (afl-clang-lto), and prefix
34+
# any build calls to have the two given environment settings, ie:
35+
# `AFL_LLVM_THREADSAFE_INST=1 AFL_LLVM_LAF_ALL=1 afl-clang-lto <...>`
36+
#
37+
# NOTE: If using multiple ENV_OPTIONS, delimit via semi-colons and it will be
38+
# separated correctly.
39+
40+
# Options
41+
option(AFL "Switch to using an AFL compiler" OFF)
42+
set(AFL_MODE
43+
""
44+
CACHE
45+
STRING
46+
"Use a specific AFL instrumentation mode: LTO, LLVM, GCC-PLUGIN, CLANG, GCC"
47+
)
48+
set(AFL_ENV_OPTIONS
49+
""
50+
CACHE STRING
51+
"Add environmental settings to build calls (check `afl-cc -hh`)")
52+
53+
# Sets up for AFL fuzzing by detecting finding and using AFL compilers and
54+
# setting a few flags and environmental build flags as requested.
55+
if(AFL)
56+
find_program(AFL_C_COMPILER afl-cc)
57+
find_program(AFL_CXX_COMPILER afl-c++)
58+
59+
if(AFL_C_COMPILER AND AFL_CXX_COMPILER)
60+
if((CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER STREQUAL AFL_C_COMPILER)
61+
OR (CMAKE_CXX_COMPILER AND NOT CMAKE_CXX_COMPILER STREQUAL
62+
AFL_CXX_COMPILER))
63+
# CMake doesn't support changing compilers after they've been set
64+
message(
65+
FATAL_ERROR
66+
"Cannot change to AFL compilers after they have been previously set. Clear the cache, reconfigure and ensure setup_afl is called before the first C or CXX compiler is set, typically before the first project() call."
67+
)
68+
else()
69+
# Set the AFL compiler
70+
message(STATUS "Changed to AFL compiler")
71+
set(CMAKE_C_COMPILER ${AFL_C_COMPILER})
72+
set(CMAKE_CXX_COMPILER ${AFL_CXX_COMPILER})
73+
74+
# Set a specific AFL mode for both compile and link stages
75+
if(AFL_MODE MATCHES "[Ll][Tt][Oo]")
76+
message(STATUS "Set AFL to Clang-LTO mode")
77+
add_compile_options(--afl-lto)
78+
add_link_options(--afl-lto)
79+
elseif(AFL_MODE MATCHES "[Ll][Ll][Vv][Mm]")
80+
message(STATUS "Set AFL to Clang-LLVM mode")
81+
add_compile_options(--afl-llvm)
82+
add_link_options(--afl-llvm)
83+
elseif(AFL_MODE MATCHES "[Gg][Cc][Cc][-_][Pp][Ll][Uu][Gg][Ii][Nn]")
84+
message(STATUS "Set AFL to GCC-Plugin mode")
85+
add_compile_options(--afl-gcc-plugin)
86+
add_link_options(--afl-gcc-plugin)
87+
elseif(AFL_MODE MATCHES "[Ll][Tt][Oo]")
88+
message(STATUS "Set AFL to Clang mode")
89+
add_compile_options(--afl-clang)
90+
add_link_options(--afl-clang)
91+
elseif(AFL_MODE MATCHES "[Ll][Tt][Oo]")
92+
message(STATUS "Set AFL to GCC mode")
93+
add_compile_options(--afl-gcc)
94+
add_link_options(--afl-gcc)
95+
endif()
96+
97+
# Add specified environment options
98+
if(AFL_ENV_OPTIONS)
99+
set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_C_COMPILER_LAUNCHER}
100+
${AFL_ENV_OPTIONS})
101+
set(CMAKE_CXX_COMPILER_LAUNCHER ${CMAKE_CXX_COMPILER_LAUNCHER}
102+
${AFL_ENV_OPTIONS})
103+
endif()
104+
endif()
105+
else()
106+
message(FATAL_ERROR "Usable AFL compiler was not found!")
107+
endif()
108+
endif()

sanitizers.cmake

+43
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ function(append value)
3030
endforeach(variable)
3131
endfunction()
3232

33+
function(append_quoteless value)
34+
foreach(variable ${ARGN})
35+
set(${variable}
36+
${${variable}} ${value}
37+
PARENT_SCOPE)
38+
endforeach(variable)
39+
endfunction()
40+
3341
function(test_san_flags return_var flags)
3442
set(QUIET_BACKUP ${CMAKE_REQUIRED_QUIET})
3543
set(CMAKE_REQUIRED_QUIET TRUE)
@@ -60,6 +68,11 @@ if(USE_SANITIZER)
6068
if(SANITIZER_ADDR_AVAILABLE)
6169
message(STATUS " Building with Address sanitizer")
6270
append("${SANITIZER_ADDR_FLAG}" SANITIZER_SELECTED_FLAGS)
71+
72+
if(AFL)
73+
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
74+
CMAKE_CXX_COMPILER_LAUNCHER)
75+
endif()
6376
else()
6477
message(
6578
FATAL_ERROR
@@ -84,6 +97,11 @@ if(USE_SANITIZER)
8497
message(STATUS " Building with Memory sanitizer")
8598
endif()
8699
append("${SANITIZER_MEM_FLAG}" SANITIZER_SELECTED_FLAGS)
100+
101+
if(AFL)
102+
append_quoteless(AFL_USE_MSAN=1 CMAKE_C_COMPILER_LAUNCHER
103+
CMAKE_CXX_COMPILER_LAUNCHER)
104+
endif()
87105
else()
88106
message(
89107
FATAL_ERROR
@@ -102,6 +120,11 @@ if(USE_SANITIZER)
102120
if(SANITIZER_UB_AVAILABLE)
103121
message(STATUS " Building with Undefined Behaviour sanitizer")
104122
append("${SANITIZER_UB_FLAG}" SANITIZER_SELECTED_FLAGS)
123+
124+
if(AFL)
125+
append_quoteless(AFL_USE_UBSAN=1 CMAKE_C_COMPILER_LAUNCHER
126+
CMAKE_CXX_COMPILER_LAUNCHER)
127+
endif()
105128
else()
106129
message(
107130
FATAL_ERROR
@@ -117,6 +140,11 @@ if(USE_SANITIZER)
117140
if(SANITIZER_THREAD_AVAILABLE)
118141
message(STATUS " Building with Thread sanitizer")
119142
append("${SANITIZER_THREAD_FLAG}" SANITIZER_SELECTED_FLAGS)
143+
144+
if(AFL)
145+
append_quoteless(AFL_USE_TSAN=1 CMAKE_C_COMPILER_LAUNCHER
146+
CMAKE_CXX_COMPILER_LAUNCHER)
147+
endif()
120148
else()
121149
message(
122150
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
@@ -131,6 +159,11 @@ if(USE_SANITIZER)
131159
if(SANITIZER_LEAK_AVAILABLE)
132160
message(STATUS " Building with Leak sanitizer")
133161
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)
162+
163+
if(AFL)
164+
append_quoteless(AFL_USE_LSAN=1 CMAKE_C_COMPILER_LAUNCHER
165+
CMAKE_CXX_COMPILER_LAUNCHER)
166+
endif()
134167
else()
135168
message(
136169
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
@@ -145,6 +178,11 @@ if(USE_SANITIZER)
145178
if(SANITIZER_CFI_AVAILABLE)
146179
message(STATUS " Building with Control Flow Integrity(CFI) sanitizer")
147180
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)
181+
182+
if(AFL)
183+
append_quoteless(AFL_USE_CFISAN=1 CMAKE_C_COMPILER_LAUNCHER
184+
CMAKE_CXX_COMPILER_LAUNCHER)
185+
endif()
148186
else()
149187
message(
150188
FATAL_ERROR
@@ -167,6 +205,11 @@ if(USE_SANITIZER)
167205
if(USE_SANITIZER MATCHES "([Aa]ddress)")
168206
message(STATUS "Building with Address sanitizer")
169207
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
208+
209+
if(AFL)
210+
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
211+
CMAKE_CXX_COMPILER_LAUNCHER)
212+
endif()
170213
else()
171214
message(
172215
FATAL_ERROR

0 commit comments

Comments
 (0)