#!/bin/bash # # run.sh — coverage-guided fuzzing of the reader (libFuzzer through cargo-fuzz). # # run.sh [seconds-per-target] [target ...] # (default 600; envelope int_payload media containers) # # Targets: # envelope version detection, the WAI1 and WAI2 readers, the listing form # int_payload int_payload::decode_int against every committed parameter set # media the picture, audio, video and text decoders of the floor and the # recommended set # containers the extension containers: world, causal op, film, reel, score, # haptic, splat4d, audio scene # # Builds the seed corpora from the repository (`seeds`), then runs each target for # the time given, adding what it finds to the corpus. The corpus lives in # $WAI_FUZZ_CORPUS (default fuzz/corpus): point it at a directory that persists between # runs and each run starts where the last left off. A crash, a timeout (60 s) or an # input that takes more than 4 GiB stops that target; its input lands in # fuzz/artifacts//, the script carries on with the next target, and exits 1. # A target that fails without leaving an input (it did not build, or cargo-fuzz could # not run) is a tool failure, not a find: exit 2. # Turn a find into a regression test: `cargo +nightly fuzz tmin `, # then add the minimised input to tests/fuzz_smoke.rs. # # Needs a nightly toolchain and cargo-fuzz (`cargo install cargo-fuzz`). Heavy: run it # on the build host, under memguard, never on the dev Mac. set -uo pipefail cd "$(dirname "$0")" SECS=${1:-600} shift || true TARGETS=${*:-envelope int_payload media containers} CORPUS=${WAI_FUZZ_CORPUS:-corpus} TOOLCHAIN=${WAI_FUZZ_TOOLCHAIN:-nightly} cargo +"$TOOLCHAIN" run --quiet --release --bin seeds -- "$CORPUS" || exit 2 found=() broken=() for t in $TARGETS; do echo "== $t: ${SECS}s" mkdir -p "$CORPUS/$t" "artifacts/$t" before=$(ls "artifacts/$t" | wc -l) # --no-cfg-fuzzing: rav1e (the AV1 encoder wai links) depends on libfuzzer-sys under # cfg(fuzzing), which would leave wai's cdylib with an undefined libFuzzer symbol. The # targets use libfuzzer-sys directly and need no cfg. if ! cargo +"$TOOLCHAIN" fuzz run --no-cfg-fuzzing "$t" "$CORPUS/$t" -- \ -max_total_time="$SECS" -timeout=60 -rss_limit_mb=4096 -malloc_limit_mb=4096 \ -max_len=1048576 -print_final_stats=1; then if [ "$(ls "artifacts/$t" | wc -l)" -gt "$before" ]; then found+=("$t"); else broken+=("$t"); fi fi done if [ ${#broken[@]} -gt 0 ]; then echo "run.sh: did not run: ${broken[*]} (see the output above)" >&2 fi if [ ${#found[@]} -gt 0 ]; then echo "run.sh: found something in: ${found[*]}; inputs in fuzz/artifacts/" >&2 exit 1 fi [ ${#broken[@]} -eq 0 ] || exit 2 echo "run.sh: ${TARGETS} ran ${SECS}s each and found nothing"