Skip to content
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

.github/workflows: Enable fuzz testing as a nightly CI task #631

Merged
merged 1 commit into from
Sep 27, 2023
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
161 changes: 161 additions & 0 deletions .github/workflows/nightly-fuzzing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
name: Fuzz Testing Nightly
on:
schedule:
# 3:00 AM PST monday-saturday
- cron: '00 11 * * 1-6'

jobs:
image_verify_seed_corpus:
name: Build Image Verifier seed corpus
runs-on: ubuntu-22.04

env:
# Change this to a new random value if you suspect the cache is corrupted
CACHE_BUSTER: 6542f37bb328

steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Restore seed corpus
uses: actions/cache/restore@v3
id: image_bundle_restore
with:
path: ./image/verify/fuzz/common_corpus/
key: image_verify-common_corpus-${{ env.CACHE_BUSTER }}

- name: Build seed corpus
if: steps.image_bundle_restore.outputs.cache-hit != 'true'
run: |
mkdir -p image/verify/fuzz/common_corpus
for x in $(seq 01 04); do
cargo run -j$(nproc) --manifest-path=builder/Cargo.toml --release --bin image -- --rom /dev/null --fw image/verify/fuzz/common_corpus/${x}; \
cargo clean; \
done

- name: Save seed corpus
uses: actions/cache/save@v3
if: steps.image_bundle_restore.outputs.cache-hit != 'true'
with:
path: ./image/verify/fuzz/common_corpus/
key: image_verify-common_corpus-${{ env.CACHE_BUSTER }}

dpe_libfuzzer:
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: dpe
fuzz_target_path: dpe/dpe/fuzz
fuzz_target_name: fuzz_target_1
fuzz_target_max_len: 512
fuzzer_features:
fuzzer_sanitiser: address

dpe_afl:
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: dpe
fuzz_target_path: dpe/dpe/fuzz
fuzz_target_name: fuzz_target_1
fuzz_target_max_len: 512
fuzzer_features:

image_verify_libfuzzer_unstructured:
needs: image_verify_seed_corpus
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: image_verify
fuzz_target_path: image/verify/fuzz
fuzz_target_name: fuzz_target_coldreset
fuzz_target_max_len: 131072
fuzzer_features:
fuzzer_sanitiser: address

image_verify_libfuzzer_structured:
needs: image_verify_seed_corpus
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: image_verify
fuzz_target_path: image/verify/fuzz
fuzz_target_name: fuzz_target_coldreset
fuzz_target_max_len: 131072
fuzzer_features: struct-aware
fuzzer_sanitiser: address

image_verify_afl_unstructured:
needs: image_verify_seed_corpus
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: image_verify
fuzz_target_path: image/verify/fuzz
fuzz_target_name: fuzz_target_coldreset
fuzz_target_max_len: 131072
fuzzer_features:

image_verify_afl_structured:
needs: image_verify_seed_corpus
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: image_verify
fuzz_target_path: image/verify/fuzz
fuzz_target_name: fuzz_target_coldreset
fuzz_target_max_len: 131072
fuzzer_features: struct-aware

lms_libfuzzer_unstructured:
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: lms
fuzz_target_path: drivers/fuzz
fuzz_target_name: fuzz_target_lms
fuzz_target_max_len: 16384
fuzzer_features:
fuzzer_sanitiser: address

lms_libfuzzer_structured:
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: lms
fuzz_target_path: drivers/fuzz
fuzz_target_name: fuzz_target_lms
fuzz_target_max_len: 16384
fuzzer_features: struct-aware
fuzzer_sanitiser: address

lms_afl_unstructured:
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: lms
fuzz_target_path: drivers/fuzz
fuzz_target_name: fuzz_target_lms
fuzz_target_max_len: 16384
fuzzer_features:

lms_afl_structured:
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: lms
fuzz_target_path: drivers/fuzz
fuzz_target_name: fuzz_target_lms
fuzz_target_max_len: 16384
fuzzer_features: struct-aware

x509_libfuzzer:
uses: ./.github/workflows/reusable-libfuzzer.yml
with:
name: x509
fuzz_target_path: x509/fuzz
fuzz_target_name: fuzz_target_1
fuzz_target_max_len: 8192
fuzzer_features:
fuzzer_sanitiser: address

x509_afl:
uses: ./.github/workflows/reusable-aflplusplus.yml
with:
name: x509
fuzz_target_path: x509/fuzz
fuzz_target_name: fuzz_target_1
fuzz_target_max_len: 8192
fuzzer_features:
164 changes: 164 additions & 0 deletions .github/workflows/reusable-aflplusplus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
name: Reusable AFL++
on:
workflow_call:
inputs:
name:
required: true
type: string
fuzz_target_path:
required: true
type: string
fuzz_target_name:
required: true
type: string
fuzz_target_max_len:
required: true
type: string
fuzzer_features:
required: true
type: string

jobs:
reusable_aflplus_plus:
# TODO: Set these as parameters?
runs-on: ubuntu-22.04
timeout-minutes: 90

env:
# Change this to a new random value if you suspect the cache is corrupted
CACHE_BUSTER: 6542f37bb328

steps:
- name: Checkout repo
uses: actions/checkout@v3
with:
submodules: 'true'

- name: Install dependencies
run: |
rustup toolchain install nightly-2023-04-15
cargo +nightly-2023-04-15 install cargo-afl
sudo apt-get install gnuplot
echo core | sudo tee /proc/sys/kernel/core_pattern

- name: Restore corpus dir
uses: actions/cache/restore@v3
with:
path: ${{ inputs.fuzz_target_path }}/corpus/
key: ${{ inputs.name }}-${{ env.CACHE_BUSTER }}

- name: Run fuzzing
run: |
cd ${{ inputs.fuzz_target_path }}
mkdir -p {corpus,artifacts}/${{ inputs.fuzz_target_name }}
cp common_corpus/* corpus/${{ inputs.fuzz_target_name }}/
# For parallelised workers
export AFL_IMPORT_FIRST=1
# For faster CI runs
#export AFL_CMPLOG_ONLY_NEW=1
export AFL_FAST_CAL=1
cargo +nightly-2023-04-15 afl build \
--features afl,${{ inputs.fuzzer_features }}
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p fast -L 1 -l 2ATR \
-M node01-cmplog_en \
target/debug/${{ inputs.fuzz_target_name }} &
for x in $(seq 3 4 $(nproc)); do \
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p fast -L 0 -c - \
-S node$(( $x ))-fast-mopt_en \
target/debug/${{ inputs.fuzz_target_name }} > /dev/null & ; \
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p fast -c - \
-S node$(( $x + 1 ))-fast-mopt_dis \
target/debug/${{ inputs.fuzz_target_name }} > /dev/null & ; \
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p explore -L 0 -c - \
-S node$(( $x + 2 ))-explore-mopt_en \
target/debug/${{ inputs.fuzz_target_name }} > /dev/null & ; \
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p explore -c - \
-S node$(( $x + 3))-explore-mopt_dis \
target/debug/${{ inputs.fuzz_target_name }} > /dev/null & ; \
done
# FIXME: Step detection for putting tasks in background
cargo +nightly-2023-04-15 afl fuzz \
-i corpus/${{ inputs.fuzz_target_name }} \
-o artifacts/${{ inputs.fuzz_target_name }} \
-G ${{ inputs.fuzz_target_max_len }} \
-V 3600 \
-p fast -L 1 -c - \
-S node02-cmplog_dis \
target/debug/${{ inputs.fuzz_target_name }} > /dev/null
cargo +nightly-2023-04-15 afl whatsup -s -d artifacts

- name: Export coverage
run: |
cd ${{ inputs.fuzz_target_path }}
cargo +nightly-2023-04-15 afl showmap \
-C -i artifacts/default -o /dev/null \
-- \
target/debug/${{inputs.fuzz_target_name }}
cargo +nightly-2023-04-15 afl plot artifacts/default plot

- name: Merge corpus between runs
run: |
cd ${{ inputs.fuzz_target_path }}
mkdir new_corpus
cargo +nightly-2023-04-15 afl cmin \
-i corpus \
-o new_corpus \
-T all \
-- \
target/debug/${{ inputs.fuzz_target_name }}
rm -rf corpus && mv new_corpus corpus

- name: Attempt to minimise each crash for test cases
run: |
cd ${{ inputs.fuzz_target_path }}
mkdir test_cases
for crashing_input in artifacts/${{ inputs.fuzz_target_name }}/*; do
cargo +nightly-2023-04-15 afl tmin \
-i $crashing_input \
-o test_cases/$(basename $crashing_input)
-- \
target/debug/${{ inputs.fuzz_target_name }} \
done

- name: Save corpus dir
uses: actions/cache/save@v3
with:
path: ${{ inputs.fuzz_target_path }}/corpus/
key: ${{ inputs.name }}-${{ env.CACHE_BUSTER }}

- name: Archive test cases dir
uses: actions/upload-artifact@v3
with:
name: test_cases
path: ${{ inputs.fuzz_target_path }}/test_cases/

- name: Archive fuzzing coverage
uses: actions/upload-artifact@v3
with:
name: plot
path: ${{ inputs.fuzz_target_path }}/plot/
Loading