ci(fuzz): Switch to alf for faster fuzzing (#245)

* test(fuzz): Migrate to afl++ for fuzzing

* build: Exclude new fuzz binaries

* chore: Fix new warning

* ci: Use cargo action for format check

* deps: Update constant_time_eq and flate2

* ci: Bug fix for file paths

* ci: Bug fix: working directory is parent of repository root

* ci: Bug fix: remove stray `cd` commands

* ci: Bug fix? Make paths explicitly descend from workspace root

* ci: Bug fix? Assume github.workspace is the repo root

* test(fuzz): Commit files that were previously missing

* ci(fuzz): Bug fix for fuzz_write_with_no_features

* ci(fuzz): Bug fix: no -V arg for cmin

* ci(fuzz): Bug fix: no -a arg for cmin

* Bug fix: replace colons with dashes in filenames

* style: Fix 2 clippy warnings

* style: Fix another clippy warning in some configs

* ci(fuzz): Enable renaming in all fuzz jobs

* ci(fuzz): Fix: need to rename files in multiple dirs

Signed-off-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com>

* ci(fuzz): Install `rename` tool

* ci(fuzz): Fix redundant steps and too-late install of `rename`

* ci(fuzz): fix? replace multiple colons

---------

Signed-off-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com>
This commit is contained in:
Chris Hennick 2024-11-19 06:25:55 -08:00 committed by GitHub
parent 1f2957db1f
commit 8abbf0e931
Signed by: DevComp
GPG key ID: B5690EEEBB952194
7681 changed files with 533 additions and 1318 deletions

View file

@ -65,7 +65,10 @@ jobs:
override: true
components: rustfmt
- name: fmt
run: cargo fmt --all -- --check
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
style_and_docs:
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
@ -105,38 +108,61 @@ jobs:
profile: minimal
toolchain: nightly
override: true
- uses: actions-rs/cargo@v1
- name: Install afl
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-fuzz
args: cargo-afl
- name: cargo afl system-config
uses: actions-rs/cargo@v1
with:
command: afl
args: system-config
- name: compile fuzz
uses: actions-rs/cargo@v1
with:
command: fuzz
args: build --all-features fuzz_read
command: afl
args: build --all-features --manifest-path ${{ github.workspace }}/fuzz_read/Cargo.toml
- name: run fuzz
timeout-minutes: 350
timeout-minutes: 70
uses: actions-rs/cargo@v1
with:
command: fuzz
args: run --all-features fuzz_read -- fuzz/corpus/fuzz_read -timeout=10s -rss_limit_mb=8192 -fork=2 -runs=25000000 -max_len=1000 -max_total_time=20700 -dict=fuzz/fuzz.dict
command: afl
args: fuzz -i ${{ github.workspace }}/fuzz_read/in -o out -V 3600 -a binary -- ${{ github.workspace }}/fuzz_read/target/debug/fuzz_read
- name: Minimize corpus
uses: actions-rs/cargo@v1
with:
command: afl
args: cmin -i out/default/queue -o out_cmin -- ${{ github.workspace }}/fuzz_read/target/debug/fuzz_read
- name: Report coverage
uses: actions-rs/cargo@v1
with:
command: afl
args: showmap -C -i out -o map -- ${{ github.workspace }}/fuzz_read/target/debug/fuzz_read
- run: sudo apt install rename
- name: Rename files
run: |
rename 's/:/-/g' map/*
rename 's/:/-/g' out_cmin/*
rename 's/:/-/g' out/default/crashes/*
- name: Upload updated corpus
uses: actions/upload-artifact@v4
with:
name: fuzz_read_corpus
path: out_cmin/*
- name: Upload any failure inputs
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_read_bad_inputs
path: fuzz/artifacts/fuzz_read/crash-*
path: out/default/crashes/*
if-no-files-found: ignore
- name: Minimize seed corpus
if: always()
run: ./recursive-fuzz-cmin.sh read 70000
shell: bash
- name: Upload updated seed corpus
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_read_corpus
path: fuzz/corpus/fuzz_read/*
name: fuzz_read_coverage
path: map
fuzz_read_with_no_features:
runs-on: ubuntu-latest
@ -151,28 +177,50 @@ jobs:
profile: minimal
toolchain: nightly
override: true
- uses: actions-rs/cargo@v1
- name: Install afl
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-fuzz
args: cargo-afl
- name: cargo afl system-config
uses: actions-rs/cargo@v1
with:
command: afl
args: system-config
- name: compile fuzz
uses: actions-rs/cargo@v1
with:
command: fuzz
args: build --no-default-features fuzz_read
command: afl
args: build --manifest-path ${{ github.workspace }}/fuzz_read/Cargo.toml
- name: run fuzz
timeout-minutes: 350
timeout-minutes: 70
uses: actions-rs/cargo@v1
with:
command: fuzz
args: run --no-default-features fuzz_read fuzz/corpus/fuzz_read -- -rss_limit_mb=8192 -timeout=10s -fork=2 -runs=40000000 -max_total_time=20700 -max_len=70000 -dict=fuzz/fuzz.dict
command: afl
args: fuzz -i ${{ github.workspace }}/fuzz_read/in -o out -V 3600 -a binary -- ${{ github.workspace }}/fuzz_read/target/debug/fuzz_read
- name: Report coverage
uses: actions-rs/cargo@v1
with:
command: afl
args: showmap -C -i out -o map -- ${{ github.workspace }}/fuzz_read/target/debug/fuzz_read
- run: sudo apt install rename
- name: Rename files
run: |
rename 's/:/-/g' map/*
rename 's/:/-/g' out/default/crashes/*
- name: Upload any failure inputs
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_read_no_features_bad_inputs
path: fuzz/artifacts/fuzz_read/crash-*
name: fuzz_read_bad_inputs_no_features
path: out/default/crashes/*
if-no-files-found: ignore
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_read_coverage_no_features
path: map
fuzz_write:
runs-on: ubuntu-latest
@ -187,41 +235,61 @@ jobs:
profile: minimal
toolchain: nightly
override: true
- uses: actions-rs/cargo@v1
- name: Install afl
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-fuzz
args: cargo-afl
- name: cargo afl system-config
uses: actions-rs/cargo@v1
with:
command: afl
args: system-config
- name: compile fuzz
uses: actions-rs/cargo@v1
with:
command: fuzz
args: build --all-features fuzz_write
command: afl
args: build --all-features --manifest-path ${{ github.workspace }}/fuzz_write/Cargo.toml
- name: run fuzz
timeout-minutes: 350
timeout-minutes: 70
uses: actions-rs/cargo@v1
with:
command: fuzz
args: run --all-features fuzz_write fuzz/corpus/fuzz_write -- -rss_limit_mb=8192 -timeout=2s -fork=2 -runs=5000000 -max_len=160 -max_total_time=20700 -dict=fuzz/fuzz.dict
command: afl
args: fuzz -i ${{ github.workspace }}/fuzz_write/in -o out -V 3600 -a binary -x ${{ github.workspace }}/fuzz_write/fuzz.dict -- ${{ github.workspace }}/fuzz_write/target/debug/fuzz_write
- name: Minimize corpus
uses: actions-rs/cargo@v1
with:
command: afl
args: cmin -i out/default/queue -o out_cmin -- ${{ github.workspace }}/fuzz_write/target/debug/fuzz_write
- name: Report coverage
uses: actions-rs/cargo@v1
with:
command: afl
args: showmap -C -i out -o map -- ${{ github.workspace }}/fuzz_write/target/debug/fuzz_write
- run: sudo apt install rename
- name: Rename files
run: |
rename 's/:/-/g' map/*
rename 's/:/-/g' out_cmin/*
rename 's/:/-/g' out/default/crashes/*
- name: Upload updated corpus
uses: actions/upload-artifact@v4
with:
name: fuzz_write_corpus
path: out_cmin/*
- name: Upload any failure inputs
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_write_bad_inputs
path: |
fuzz/artifacts/fuzz_write/crash-*
fuzz/artifacts/fuzz_write/leak-*
fuzz/artifacts/fuzz_write/timeout-*
path: out/default/crashes/*
if-no-files-found: ignore
- name: Minimize seed corpus
if: always()
run: ./recursive-fuzz-cmin.sh write 500
shell: bash
- name: Upload updated seed corpus
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_write_corpus
path: fuzz/corpus/fuzz_write/*
name: fuzz_write_coverage
path: map
fuzz_write_with_no_features:
runs-on: ubuntu-latest
@ -236,25 +304,47 @@ jobs:
profile: minimal
toolchain: nightly
override: true
- uses: actions-rs/cargo@v1
- name: Install afl
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-fuzz
args: cargo-afl
- name: cargo afl system-config
uses: actions-rs/cargo@v1
with:
command: afl
args: system-config
- name: compile fuzz
uses: actions-rs/cargo@v1
with:
command: fuzz
args: build --no-default-features fuzz_write
command: afl
args: build --all-features --manifest-path ${{ github.workspace }}/fuzz_write/Cargo.toml
- name: run fuzz
timeout-minutes: 350
timeout-minutes: 70
uses: actions-rs/cargo@v1
with:
command: fuzz
args: run --no-default-features fuzz_write fuzz/corpus/fuzz_write -- -rss_limit_mb=8192 -timeout=10s -fork=2 -runs=40000000 -max_len=256 -max_total_time=20700 -dict=fuzz/fuzz.dict
command: afl
args: fuzz -i ${{ github.workspace }}/fuzz_write/in -o out -V 3600 -a binary -x ${{ github.workspace }}/fuzz_write/fuzz.dict -- ${{ github.workspace }}/fuzz_write/target/debug/fuzz_write
- name: Report coverage
uses: actions-rs/cargo@v1
with:
command: afl
args: showmap -C -i out -o map -- ${{ github.workspace }}/fuzz_write/target/debug/fuzz_write
- run: sudo apt install rename
- name: Rename files
run: |
rename 's/:/-/g' map/*
rename 's/:/-/g' out/default/crashes/*
- name: Upload any failure inputs
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_write_no_features_bad_inputs
path: fuzz/artifacts/fuzz_write/crash-*
name: fuzz_write_bad_inputs_no_features
path: out/default/crashes/*
if-no-files-found: ignore
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: fuzz_write_coverage_no_features
path: map

2
.gitignore vendored
View file

@ -2,3 +2,5 @@ Cargo.lock
target
.DS_Store
\.idea/
/fuzz_read/out/
/fuzz_write/out/

View file

@ -15,7 +15,7 @@ description = """
Library to support the reading and writing of zip files.
"""
edition = "2021"
exclude = ["tests/**", "examples/**", ".github/**", "fuzz/**"]
exclude = ["tests/**", "examples/**", ".github/**", "fuzz_read/**", "fuzz_write/**"]
build = "src/build.rs"
[package.metadata.docs.rs]
@ -29,10 +29,10 @@ time = { version = "0.3.36", default-features = false }
aes = { version = "0.8.4", optional = true }
bzip2 = { version = "0.4.4", optional = true }
chrono = { version = "0.4.38", optional = true }
constant_time_eq = { version = "0.3.0", optional = true }
constant_time_eq = { version = "0.3.1", optional = true }
crc32fast = "1.4.2"
displaydoc = { version = "0.2.5", default-features = false }
flate2 = { version = "1.0.30", default-features = false, optional = true }
flate2 = { version = "1.0.33", default-features = false, optional = true }
indexmap = "2"
hmac = { version = "0.12.1", optional = true, features = ["reset"] }
memchr = "2.7.4"
@ -70,7 +70,7 @@ chrono = ["chrono/default"]
_deflate-any = []
_all-features = [] # Detect when --all-features is used
deflate = ["flate2/rust_backend", "deflate-zopfli", "deflate-flate2"]
deflate-flate2 = ["flate2/any_impl", "_deflate-any"]
deflate-flate2 = ["_deflate-any"]
# DEPRECATED: previously enabled `flate2/miniz_oxide` which is equivalent to `flate2/rust_backend`
deflate-miniz = ["deflate", "deflate-flate2"]
deflate-zlib = ["flate2/zlib", "deflate-flate2"]

View file

@ -1,60 +0,0 @@
#!/bin/bash
set -euxo pipefail
ncpus=$(nproc || getconf NPROCESSORS_ONLN)
ncpus=$(( ncpus / ( 1 + $(cat /sys/devices/system/cpu/smt/active))))
NORMAL_RESTARTS=5
rm -rf "fuzz/corpus/fuzz_$1_pre_fresh_blood" || true
mkdir "fuzz/corpus/fuzz_$1_pre_fresh_blood"
find "fuzz/corpus/fuzz_$1" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_pre_fresh_blood" ';' || true
for i in $(seq 1 $NORMAL_RESTARTS); do
find "fuzz/corpus/fuzz_$1_restart_${i}" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_pre_fresh_blood" ';' || true
rm -rf "fuzz/corpus/fuzz_$1_restart_${i}" || true
echo "$(date): RESTART ${i}"
mkdir "fuzz/corpus/fuzz_$1" || true
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-dict=fuzz/fuzz.dict -max_len="$2" -fork="$ncpus" \
-max_total_time=5100 -runs=100000000
mv "fuzz/corpus/fuzz_$1" "fuzz/corpus/fuzz_$1_restart_${i}"
mkdir "fuzz/corpus/fuzz_$1"
done
find "fuzz/corpus/fuzz_$1_restart_dictionaryless" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_pre_fresh_blood" ';' || true
rm -rf "fuzz/corpus/fuzz_$1_restart_dictionaryless" || true
echo "$(date): DICTIONARY-LESS RESTART"
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-max_len="$2" -fork="$ncpus" -max_total_time=5100 -runs=100000000
mv "fuzz/corpus/fuzz_$1" "fuzz/corpus/fuzz_$1_restart_dictionaryless"
mkdir "fuzz/corpus/fuzz_$1"
find "fuzz/corpus/fuzz_$1_restart_dictionaryless_012byte" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_pre_fresh_blood" ';' || true
rm -rf "fuzz/corpus/fuzz_$1_restart_dictionaryless_012byte" || true
echo "$(date): DICTIONARY-LESS RESTART WITH 0-2 BYTE CORPUS"
tar -xvzf "fuzz/012byte.tar.gz" -C "fuzz/corpus/fuzz_$1"
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-max_len="$2" -fork="$ncpus" -max_total_time=5100 -runs=100000000
mv "fuzz/corpus/fuzz_$1" "fuzz/corpus/fuzz_$1_restart_dictionaryless_012byte"
mkdir "fuzz/corpus/fuzz_$1"
find "fuzz/corpus/fuzz_$1_restart_012byte" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_pre_fresh_blood" ';' || true
rm -rf "fuzz/corpus/fuzz_$1_restart_012byte" || true
echo "$(date): RESTART WITH DICTIONARY AND 0-2 BYTE CORPUS"
tar -xvzf "fuzz/012byte.tar.gz" -C "fuzz/corpus/fuzz_$1"
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-dict=fuzz/fuzz.dict -max_len="$2" -fork="$ncpus" -max_total_time=5100 -runs=100000000
echo "$(date): MERGING CORPORA"
for i in $(seq 1 $NORMAL_RESTARTS); do
find "fuzz/corpus/fuzz_$1_restart_${i}" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1" ';'
rm -rf "fuzz/corpus/fuzz_$1_restart_${i}"
done
SPECIAL_RESTARTS=("dictionaryless_012byte" "dictionaryless")
for i in "${SPECIAL_RESTARTS[@]}"; do
find "fuzz/corpus/fuzz_$1_restart_${i}" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1" ';'
rm -rf "fuzz/corpus/fuzz_$1_restart_${i}"
done
echo "$(date): RUNNING WITH MERGED CORPUS"
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-dict=fuzz/fuzz.dict -max_len="$2" -fork="$ncpus" \
-max_total_time=1800 -runs=25000000 -rss_limit_mb=8192 -timeout=30
./recursive-fuzz-cmin.sh "$1" "$2"
echo "$(date): DONE BUILDING FUZZ CORPUS AT SIZE $2"

View file

@ -1,16 +0,0 @@
#!/bin/bash
set -euxo pipefail
mkdir "fuzz/corpus/fuzz_$1_recombination_sources" || true
# Ensure the 0-byte, 1-byte and 2-byte strings won't gain duplicates during recombination
find "fuzz/corpus/fuzz_$1_recombination_sources" -type f -size -3c -delete
for size in "${@:2}"; do
echo "$(date): STARTING ON SIZE $size"
rm -rf "fuzz/corpus/fuzz_$1_pre_fresh_blood" || true
find "fuzz/corpus/fuzz_$1" -type f -exec mv '{}' "fuzz/corpus/fuzz_$1_recombination_sources" ';' || true
./build-fuzz-corpus-multiple-restarts.sh "$1" "$size"
find "fuzz/corpus/fuzz_$1_recombination_sources" -type f -size "-$((size + 1))c" -exec mv '{}' "fuzz/corpus/fuzz_$1" ';'
./fuzz-until-converged.sh "$1" "$size"
done
echo "$(date): FINISHED"

View file

@ -1,21 +0,0 @@
#!/bin/bash
set -euxo pipefail
rm -r "fuzz/corpus/fuzz_$1_old" || true
ncpus=$(nproc || getconf NPROCESSORS_ONLN)
ncpus=$(( ncpus / ( 1 + $(cat /sys/devices/system/cpu/smt/active))))
MAX_ITERS_WITHOUT_IMPROVEMENT=3
iters_without_improvement=0
while [[ $iters_without_improvement -lt $MAX_ITERS_WITHOUT_IMPROVEMENT ]]; do
cp -r "fuzz/corpus/fuzz_$1" "fuzz/corpus/fuzz_$1_old"
cargo fuzz run --all-features "fuzz_$1" "fuzz/corpus/fuzz_$1" -- \
-dict=fuzz/fuzz.dict -max_len="$2" -fork="$ncpus" \
-max_total_time=1800 -runs=25000000 -rss_limit_mb=8192 -timeout=30
./recursive-fuzz-cmin.sh "$1" "$2"
if diff "fuzz/corpus/fuzz_$1" "fuzz/corpus/fuzz_$1_old"; then
iters_without_improvement=$(( iters_without_improvement + 1 ))
echo "$iters_without_improvement iterations without improvement"
else
iters_without_improvement=0
fi
rm -r "fuzz/corpus/fuzz_$1_old"
done

5
fuzz/.gitignore vendored
View file

@ -1,5 +0,0 @@
target
artifacts
corpus/*
!corpus/fuzz_read/
!corpus/fuzz_write/

Binary file not shown.

View file

@ -1,39 +0,0 @@
[package]
name = "zip-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2018"
[package.metadata]
cargo-fuzz = true
[dependencies]
libfuzzer-sys = "0.4"
arbitrary = { version = "1.3.2", features = ["derive"] }
replace_with = "0.1.7"
tikv-jemallocator = "0.6.0"
[dependencies.zip]
path = ".."
default-features = false
[features]
zip_defaults = ["zip/default"]
default = ["zip_defaults"]
# Prevent this from interfering with workspaces
[workspace]
members = ["."]
[[bin]]
name = "fuzz_read"
path = "fuzz_targets/fuzz_read.rs"
test = false
doc = false
[[bin]]
name = "fuzz_write"
path = "fuzz_targets/fuzz_write.rs"
test = false
doc = false

View file

@ -1 +0,0 @@
IPPPPPPPPPPPPPPPPPPPPPPPPPPPPPTPPPPPPPPpPPPPPPPPPPPPPPPP=PPPPPPPPPPPPPP=PPPPPPPPPPPPPPPPP=PPPPPPPPPP<50>

View file

@ -1 +0,0 @@
`K<>PKPK儕KPKキ儕K4儕KPK儕KPKPKPK儕KPKPK儕KPKPキ儕KK儕KPK

Some files were not shown because too many files have changed in this diff Show more