Skip to content

CI runs fuzzers #2891

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Loading