Skip to content

Commit

Permalink
Add AFL++ fuzzing instrumentation capability
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
StableCoder committed Jan 24, 2022
1 parent f757425 commit 8034d91
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ This is a collection of quite useful scripts that expand the possibilities for b
- [1b - Via target commands](#1b---via-target-commands)
- [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)
- [Example 3: Target added to the 'ccov' and 'ccov-all' targets](#example-3-target-added-to-the-ccov-and-ccov-all-targets)
- [AFL Fuzzing Instrumentation `afl-fuzzing.cmake`](#afl-fuzzing-instrumentation-afl-fuzzingcmake)
- [Usage](#usage-1)
- [Compiler Options `compiler-options.cmake`](#compiler-options-compiler-optionscmake)
- [Dependency Graph `dependency-graph.cmake`](#dependency-graph-dependency-graphcmake)
- [Required Arguments](#required-arguments)
Expand Down Expand Up @@ -182,6 +184,40 @@ add_executable(theExe main.cpp non_covered.cpp)
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.
```

## AFL Fuzzing Instrumentation [`afl-fuzzing.cmake`](afl-fuzzing.cmake)

> 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.
>
> [american fuzzy lop](https://lcamtuf.coredump.cx/afl/)
NOTE: This actually works based off the still-developed daughter project [AFL++](https://aflplus.plus/).

### Usage

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:

```
cmake_minimum_required(VERSION 3.4)
include(cmake/afl-fuzzing.cmake)
project(Example C CXX)
```

Using `-DAFL=ON` will search for and switch to the AFL++ compiler wrappers that will instrument builds, or error if it cannot.

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:
- LTO
- LLVM
- GCC-PLUGIN
- CLANG
- GCC

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`).

As an example, a CMake configuration such as this:
```cmake .. -DAFL_MODE=LTO -DAFL_ENV_OPTIONS=AFL_LLVM_THREADSAFE_INST=1;AFL_LLVM_LAF_ALL=1```
would result in build commands such as this:
```AFL_LLVM_THREADSAFE_INST=1 AFL_LLVM_LAF_ALL=1 afl-clang-lto --afl-lto <...>```

## Compiler Options [`compiler-options.cmake`](compiler-options.cmake)

Allows for easy use of some pre-made compiler options for the major compilers.
Expand Down
108 changes: 108 additions & 0 deletions afl-fuzzing.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#
# Copyright (C) 2022 by George Cave - [email protected]
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.

# USAGE: 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.
#
# For example for CMakeLists.txt:
# ~~~
# cmake_minimum_required(VERSION 3.15)
# include(cmake/afl-fuzzing.cmake)
# project(FoE-Engine C CXX)
# ~~~
# And then configuring CMake with: `cmake .. -DAFL_MODE=LTO
# -DAFL_ENV_OPTIONS=AFL_LLVM_THREADSAFE_INST=1;AFL_LLVM_LAF_ALL=1`
#
# Would setup the AFL compiler to use the LTO mode (afl-clang-lto), and prefix
# any build calls to have the two given environment settings, ie:
# `AFL_LLVM_THREADSAFE_INST=1 AFL_LLVM_LAF_ALL=1 afl-clang-lto <...>`
#
# NOTE: If using multiple ENV_OPTIONS, delimit via semi-colons and it will be
# separated correctly.

# Options
option(AFL "Switch to using an AFL compiler" OFF)
set(AFL_MODE
""
CACHE
STRING
"Use a specific AFL instrumentation mode: LTO, LLVM, GCC-PLUGIN, CLANG, GCC"
)
set(AFL_ENV_OPTIONS
""
CACHE STRING
"Add environmental settings to build calls (check `afl-cc -hh`)")

# Sets up for AFL fuzzing by detecting finding and using AFL compilers and
# setting a few flags and environmental build flags as requested.
if(AFL)
find_program(AFL_C_COMPILER afl-cc)
find_program(AFL_CXX_COMPILER afl-c++)

if(AFL_C_COMPILER AND AFL_CXX_COMPILER)
if((CMAKE_C_COMPILER AND NOT CMAKE_C_COMPILER STREQUAL AFL_C_COMPILER)
OR (CMAKE_CXX_COMPILER AND NOT CMAKE_CXX_COMPILER STREQUAL
AFL_CXX_COMPILER))
# CMake doesn't support changing compilers after they've been set
message(
FATAL_ERROR
"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."
)
else()
# Set the AFL compiler
message(STATUS "Changed to AFL compiler")
set(CMAKE_C_COMPILER ${AFL_C_COMPILER})
set(CMAKE_CXX_COMPILER ${AFL_CXX_COMPILER})

# Set a specific AFL mode for both compile and link stages
if(AFL_MODE MATCHES "[Ll][Tt][Oo]")
message(STATUS "Set AFL to Clang-LTO mode")
add_compile_options(--afl-lto)
add_link_options(--afl-lto)
elseif(AFL_MODE MATCHES "[Ll][Ll][Vv][Mm]")
message(STATUS "Set AFL to Clang-LLVM mode")
add_compile_options(--afl-llvm)
add_link_options(--afl-llvm)
elseif(AFL_MODE MATCHES "[Gg][Cc][Cc][-_][Pp][Ll][Uu][Gg][Ii][Nn]")
message(STATUS "Set AFL to GCC-Plugin mode")
add_compile_options(--afl-gcc-plugin)
add_link_options(--afl-gcc-plugin)
elseif(AFL_MODE MATCHES "[Ll][Tt][Oo]")
message(STATUS "Set AFL to Clang mode")
add_compile_options(--afl-clang)
add_link_options(--afl-clang)
elseif(AFL_MODE MATCHES "[Ll][Tt][Oo]")
message(STATUS "Set AFL to GCC mode")
add_compile_options(--afl-gcc)
add_link_options(--afl-gcc)
endif()

# Add specified environment options
if(AFL_ENV_OPTIONS)
set(CMAKE_C_COMPILER_LAUNCHER ${CMAKE_C_COMPILER_LAUNCHER}
${AFL_ENV_OPTIONS})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CMAKE_CXX_COMPILER_LAUNCHER}
${AFL_ENV_OPTIONS})
endif()
endif()
else()
message(FATAL_ERROR "Usable AFL compiler was not found!")
endif()
endif()
43 changes: 43 additions & 0 deletions sanitizers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ function(append value)
endforeach(variable)
endfunction()

function(append_quoteless value)
foreach(variable ${ARGN})
set(${variable}
${${variable}} ${value}
PARENT_SCOPE)
endforeach(variable)
endfunction()

function(test_san_flags return_var flags)
set(QUIET_BACKUP ${CMAKE_REQUIRED_QUIET})
set(CMAKE_REQUIRED_QUIET TRUE)
Expand Down Expand Up @@ -60,6 +68,11 @@ if(USE_SANITIZER)
if(SANITIZER_ADDR_AVAILABLE)
message(STATUS " Building with Address sanitizer")
append("${SANITIZER_ADDR_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR
Expand All @@ -84,6 +97,11 @@ if(USE_SANITIZER)
message(STATUS " Building with Memory sanitizer")
endif()
append("${SANITIZER_MEM_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_MSAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR
Expand All @@ -102,6 +120,11 @@ if(USE_SANITIZER)
if(SANITIZER_UB_AVAILABLE)
message(STATUS " Building with Undefined Behaviour sanitizer")
append("${SANITIZER_UB_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_UBSAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR
Expand All @@ -117,6 +140,11 @@ if(USE_SANITIZER)
if(SANITIZER_THREAD_AVAILABLE)
message(STATUS " Building with Thread sanitizer")
append("${SANITIZER_THREAD_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_TSAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
Expand All @@ -131,6 +159,11 @@ if(USE_SANITIZER)
if(SANITIZER_LEAK_AVAILABLE)
message(STATUS " Building with Leak sanitizer")
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_LSAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR "Thread sanitizer not available for ${CMAKE_CXX_COMPILER}"
Expand All @@ -145,6 +178,11 @@ if(USE_SANITIZER)
if(SANITIZER_CFI_AVAILABLE)
message(STATUS " Building with Control Flow Integrity(CFI) sanitizer")
append("${SANITIZER_LEAK_FLAG}" SANITIZER_SELECTED_FLAGS)

if(AFL)
append_quoteless(AFL_USE_CFISAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR
Expand All @@ -167,6 +205,11 @@ if(USE_SANITIZER)
if(USE_SANITIZER MATCHES "([Aa]ddress)")
message(STATUS "Building with Address sanitizer")
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)

if(AFL)
append_quoteless(AFL_USE_ASAN=1 CMAKE_C_COMPILER_LAUNCHER
CMAKE_CXX_COMPILER_LAUNCHER)
endif()
else()
message(
FATAL_ERROR
Expand Down

0 comments on commit 8034d91

Please sign in to comment.