Skip to content

Commit

Permalink
CI runs fuzzers
Browse files Browse the repository at this point in the history
  • Loading branch information
ashtum committed Jun 22, 2024
1 parent 1b87492 commit ee9762e
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml → .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI
name: build

on: [push, pull_request]

Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: fuzz

on:
push:
pull_request:
workflow_dispatch:
schedule:
- cron: "25 00 * * *"

jobs:
fuzz:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v3

- name: Install packages
run: |
sudo apt-get update
sudo apt-get install -y clang
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python3 tools/boostdep/depinst/depinst.py $LIBRARY
./bootstrap.sh
./b2
- name: Fuzz corpus
uses: actions/[email protected]
id: cache-corpus
with:
path: ${{ github.workspace }}/corpus.tar
key: corpus-${{ github.run_id }}
enableCrossOsArchive: true
restore-keys: |
corpus-
- name: Run fuzzer
run: |
cd ../boost-root/libs/beast
mkdir build
cd build
cmake \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang \
-DBeast_BUILD_TESTS=ON \
-DBeast_BUILD_FUZZERS=ON \
-DBOOST_BEAST_FUZZER_CORPUS_PATH=${{ github.workspace }}/corpus.tar ..
make boost_beast_fuzz_all
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ project (Beast VERSION 354)
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
option (Beast_BUILD_EXAMPLES "Build examples" ON)
option (Beast_BUILD_TESTS "Build tests" ${BUILD_TESTING})
option (Beast_BUILD_FUZZERS "Build fuzzers" OFF)
option (Beast_ENABLE_HANDLER_TRACKING "Define BOOST_ASIO_ENABLE_HANDLER_TRACKING when building libraries" OFF)
option (Boost_USE_STATIC_LIBS "Use Static Boost libraries" ON)

Expand Down
3 changes: 3 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ add_subdirectory (beast)
add_subdirectory (bench)
add_subdirectory (doc)
add_subdirectory (example)
if (Beast_BUILD_FUZZERS AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_subdirectory(fuzz)
endif()
119 changes: 119 additions & 0 deletions test/fuzz/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#
# Copyright (c) 2023 Alan de Freitas ([email protected])
# Copyright (c) 2024 Mohammad Nejati
#
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
#

# Get number of cores
include(ProcessorCount)
ProcessorCount(PROCESSOR_COUNT)

# Determine total fuzz time per file
file(GLOB BOOST_BEAST_FUZZER_SOURCE_FILES *.cpp)
list(LENGTH BOOST_BEAST_FUZZER_SOURCE_FILES BOOST_BEAST_FUZZER_SOURCE_FILES_COUNT)
set(BOOST_BEAST_FUZZER_TOTAL_TIME_DEFAULT 300)
math(EXPR BOOST_BEAST_FUZZER_TOTAL_TIME_DEFAULT "${BOOST_BEAST_FUZZER_TOTAL_TIME_DEFAULT} / (${PROCESSOR_COUNT} * ${BOOST_BEAST_FUZZER_SOURCE_FILES_COUNT}) + 1")

# Fuzzing options
set(BOOST_BEAST_FUZZER_TOTAL_TIME ${BOOST_BEAST_FUZZER_TOTAL_TIME_DEFAULT} CACHE STRING "Total time for fuzzing")
set(BOOST_BEAST_FUZZER_RSS_LIMIT 8192 CACHE STRING "RSS limit for fuzzing")
set(BOOST_BEAST_FUZZER_TIMEOUT 30 CACHE STRING "Timeout for fuzzing")
set(BOOST_BEAST_FUZZER_MAX_LEN 4000 CACHE STRING "Maximum size of the input")
set(BOOST_BEAST_FUZZER_JOBS ${PROCESSOR_COUNT} CACHE STRING "Number of jobs for fuzzing")
option(BOOST_BEAST_FUZZER_ADD_TO_CTEST "Add fuzzing targets to ctest" OFF)
set(BOOST_BEAST_FUZZER_CORPUS_PATH ${CMAKE_CURRENT_BINARY_DIR}/corpus.tar CACHE STRING "Path to corpus.tar")

# Corpus
set(BOOST_BEAST_FUZZER_SEEDS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/seeds.tar)
set(BOOST_BEAST_FUZZER_SEEDS_DIR ${CMAKE_CURRENT_BINARY_DIR}/seeds)
get_filename_component(BOOST_BEAST_FUZZER_SEEDS_PARENT_DIR ${BOOST_BEAST_FUZZER_SEEDS_DIR} DIRECTORY)
add_custom_target(
untar_seeds
COMMAND ${CMAKE_COMMAND} -E echo "Untar fuzz seeds from ${BOOST_BEAST_FUZZER_SEEDS_PATH} to ${BOOST_BEAST_FUZZER_SEEDS_PARENT_DIR}/seeds"
COMMAND ${CMAKE_COMMAND} -E tar xf ${BOOST_BEAST_FUZZER_SEEDS_PATH}
WORKING_DIRECTORY ${BOOST_BEAST_FUZZER_SEEDS_PARENT_DIR}
COMMENT "Unzipping fuzz seeds"
VERBATIM)

set(BOOST_BEAST_FUZZER_CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/corpus)
set(BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/merged-corpus)
if(EXISTS ${BOOST_BEAST_FUZZER_CORPUS_PATH})
add_custom_target(
untar_corpus
COMMAND ${CMAKE_COMMAND} -E echo "Untar fuzz corpus archive from \"${BOOST_BEAST_FUZZER_CORPUS_PATH}\" to \"${CMAKE_CURRENT_BINARY_DIR}/corpus\""
COMMAND ${CMAKE_COMMAND} -E tar xf ${BOOST_BEAST_FUZZER_CORPUS_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Unzipping fuzz corpus"
VERBATIM)
else()
add_custom_target(untar_corpus
COMMAND ${CMAKE_COMMAND} -E echo "No fuzz corpus archive in ${BOOST_BEAST_FUZZER_CORPUS_PATH}. Create empty fuzz corpus dir \"${BOOST_BEAST_FUZZER_CORPUS_DIR}.\""
COMMAND ${CMAKE_COMMAND} -E make_directory ${BOOST_BEAST_FUZZER_CORPUS_DIR}
COMMENT "Creating fuzz corpus directory"
VERBATIM)
endif()
add_dependencies(untar_corpus untar_seeds)

# Target that runs all fuzz targets
get_filename_component(BOOST_BEAST_FUZZER_CORPUS_PARENT_DIR ${BOOST_BEAST_FUZZER_CORPUS_PATH} DIRECTORY)
add_custom_target(
boost_beast_fuzz_all
COMMAND ${CMAKE_COMMAND} -E echo "Archive corpus from \"${BOOST_BEAST_FUZZER_CORPUS_DIR}\" to \"${BOOST_BEAST_FUZZER_CORPUS_PATH}\""
COMMAND ${CMAKE_COMMAND} -E tar cf ${BOOST_BEAST_FUZZER_CORPUS_PATH} ${BOOST_BEAST_FUZZER_CORPUS_DIR}
WORKING_DIRECTORY ${BOOST_BEAST_FUZZER_CORPUS_PARENT_DIR}
VERBATIM)

# Register a single fuzzer and add as dependency to fuzz target
function(add_boost_beast_fuzzer NAME)
# Fuzzer executable
set(SOURCE_FILES ${ARGN})
add_executable(fuzzer_${NAME} ${SOURCE_FILES})
target_link_libraries(fuzzer_${NAME} PRIVATE lib-beast)
target_compile_options(fuzzer_${NAME} PRIVATE -g -O2 -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=undefined)
target_link_libraries(fuzzer_${NAME} PRIVATE -fsanitize=fuzzer,address,undefined)
set_property(TARGET fuzzer_${NAME} PROPERTY FOLDER "fuzzing")

# Custom target to run fuzzer executable
add_custom_target(
fuzz_${NAME}
ALL
COMMAND ${CMAKE_COMMAND} -E make_directory ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E echo "Running fuzzer ${NAME} with corpus from ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME} and seeds from ${BOOST_BEAST_FUZZER_SEEDS_DIR}/${NAME}"
COMMAND
fuzzer_${NAME}
-rss_limit_mb=${BOOST_BEAST_FUZZER_RSS_LIMIT}
-max_total_time=${BOOST_BEAST_FUZZER_TOTAL_TIME}
-timeout=${BOOST_BEAST_FUZZER_TIMEOUT}
-max_len=${BOOST_BEAST_FUZZER_MAX_LEN}
-jobs=${BOOST_BEAST_FUZZER_JOBS}
${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
${BOOST_BEAST_FUZZER_SEEDS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E make_directory ${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E echo "Merging corpus from ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME} to ${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME}"
COMMAND
fuzzer_${NAME}
-merge=1
${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME}
${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
${BOOST_BEAST_FUZZER_SEEDS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E echo "Replacing corpus in ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME} with merged corpus from ${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME}"
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E make_directory ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E copy_directory ${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME} ${BOOST_BEAST_FUZZER_CORPUS_DIR}/${NAME}
COMMAND ${CMAKE_COMMAND} -E remove_directory ${BOOST_BEAST_FUZZER_MERGED_CORPUS_DIR}/${NAME}
DEPENDS untar_corpus fuzzer_${NAME})
add_dependencies(fuzz_${NAME} fuzzer_${NAME})
add_dependencies(boost_beast_fuzz_all fuzz_${NAME})
set_property(TARGET fuzz_${NAME} PROPERTY ENVIRONMENT "UBSAN_OPTIONS=halt_on_error=false")
endfunction()

# Register all fuzzers
file(GLOB BOOST_BEAST_FUZZER_SOURCE_FILES *.cpp)
source_group("" FILES ${BOOST_BEAST_FUZZER_SOURCE_FILES})
foreach(BOOST_BEAST_FUZZER_SOURCE_FILE ${BOOST_BEAST_FUZZER_SOURCE_FILES})
file(RELATIVE_PATH BOOST_BEAST_FUZZER_SOURCE_FILE ${CMAKE_CURRENT_SOURCE_DIR} ${BOOST_BEAST_FUZZER_SOURCE_FILE})
string(REGEX REPLACE "(.*).cpp" "\\1" RULE_NAME ${BOOST_BEAST_FUZZER_SOURCE_FILE})
add_boost_beast_fuzzer(${RULE_NAME} ${BOOST_BEAST_FUZZER_SOURCE_FILE})
endforeach()

0 comments on commit ee9762e

Please sign in to comment.