libsoliton/fuzz_overnight.sh
Kamal Tufekcic 1d99048c95
Some checks failed
CI / lint (push) Successful in 1m37s
CI / test-python (push) Successful in 1m49s
CI / test-zig (push) Successful in 1m39s
CI / test-wasm (push) Successful in 1m54s
CI / test (push) Successful in 14m44s
CI / miri (push) Successful in 14m18s
CI / build (push) Successful in 1m9s
CI / fuzz-regression (push) Successful in 9m9s
CI / publish (push) Failing after 1m10s
CI / publish-python (push) Failing after 1m46s
CI / publish-wasm (push) Has been cancelled
initial commit
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
2026-04-02 23:48:10 +03:00

108 lines
4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Overnight fuzz run: all soliton targets in parallel.
# Covers both core (soliton) and CAPI (soliton_capi) fuzz targets.
#
# Usage: ./fuzz_overnight.sh [hours] [workers]
# hours — how long to fuzz (default: 8)
# workers — libFuzzer workers per target (default: 1)
# 1 worker → 32 total threads (one per target)
# 2 workers → 64 total threads (two per target)
set -euo pipefail
if ! command -v parallel &>/dev/null; then
echo "ERROR: GNU parallel is required." >&2
exit 1
fi
HOURS="${1:-8}"
WORKERS="${2:-1}"
SECONDS_TOTAL=$((HOURS * 1))
CORE_DIR="soliton"
CAPI_DIR="soliton_capi"
LOG_BASE="fuzz_logs"
CORE_TARGETS=(
fuzz_ed25519_verify
fuzz_hybrid_verify
# fuzz_xwing_roundtrip # Excluded: 7 corpus entries after 90.5B execs, fully saturated (keygen→encap→decap, no adversarial input)
fuzz_ratchet_decrypt
fuzz_ratchet_decrypt_stateful
fuzz_ratchet_encrypt
fuzz_kex_receive_session
fuzz_kex_verify_bundle
fuzz_identity_sign_verify
# fuzz_auth_respond # Excluded: 4 corpus entries after 68B execs, fully saturated (single decap→HMAC)
fuzz_storage_decrypt_blob
# fuzz_identity_from_bytes # Excluded: 107 edges, 3 length checks only, saturates instantly
fuzz_decrypt_first_message
fuzz_storage_encrypt_blob
# fuzz_verification_phrase # Excluded: 88 edges, 29 corpus entries, trivial surface (SHA3→wordlist index)
fuzz_ratchet_roundtrip
fuzz_session_init_roundtrip
fuzz_call_derive
# fuzz_auth_verify # Excluded: 88 edges, saturated after ~15 corpus entries (single ct_eq call)
fuzz_ratchet_from_bytes_epoch
fuzz_kex_decode_receive
fuzz_dm_queue_roundtrip
fuzz_dm_queue_decrypt_blob
fuzz_argon2_params
fuzz_stream_decrypt
fuzz_stream_decrypt_at
fuzz_stream_encrypt_decrypt
fuzz_stream_encrypt_at
fuzz_ratchet_state_machine
)
CAPI_TARGETS=(
fuzz_capi_ratchet_from_bytes
fuzz_capi_storage_decrypt
fuzz_capi_decode_session_init
fuzz_capi_dm_queue_decrypt
fuzz_capi_stream_decrypt
fuzz_capi_stream_decrypt_at
fuzz_capi_stream_encrypt_at
)
ALL_TARGETS=("${CORE_TARGETS[@]}" "${CAPI_TARGETS[@]}")
# Create timestamped log directory + "latest" symlink for fuzz_stats.sh.
# Must be absolute — parallel commands cd into different dirs before tee.
LOG_DIR="$(pwd)/${LOG_BASE}/$(date +%Y-%m-%d_%H%M%S)"
mkdir -p "${LOG_DIR}"
ln -sfn "$(basename "${LOG_DIR}")" "${LOG_BASE}/latest"
THREADS=$(( ${#ALL_TARGETS[@]} * WORKERS ))
echo "Fuzzing for ${HOURS}h (${SECONDS_TOTAL}s), ${WORKERS} worker(s) per target"
echo " Core targets (${#CORE_TARGETS[@]}): ${CORE_TARGETS[*]}"
echo " CAPI targets (${#CAPI_TARGETS[@]}): ${CAPI_TARGETS[*]}"
echo " Total CPU threads: ${THREADS}"
echo " Logs: ${LOG_DIR}/"
echo "---"
# Ensure seed corpus exists for both core and CAPI targets.
# gen_corpus writes to both soliton/fuzz/corpus/ and soliton_capi/fuzz/corpus/.
# Cheap and idempotent — safe to re-run.
echo "Generating seed corpus (core + CAPI)..."
(cd "${CORE_DIR}/fuzz" && cargo +nightly run --bin gen_corpus --quiet)
echo "---"
# Build a list of "fuzz_dir target" pairs for GNU parallel.
# -max_len=65536: required for targets with large minimum input (hybrid_verify needs 6541 bytes;
# libFuzzer's default max_len is 4096, which would make those targets produce zero progress).
# -print_final_stats=1: emit machine-parseable stats at end (for fuzz_stats.sh).
# Output is tee'd to per-target log files and also shown live via parallel --lb.
PAIRS=()
for t in "${CORE_TARGETS[@]}"; do
PAIRS+=("${CORE_DIR} ${t}")
done
for t in "${CAPI_TARGETS[@]}"; do
PAIRS+=("${CAPI_DIR} ${t}")
done
printf '%s\n' "${PAIRS[@]}" | parallel --lb --colsep ' ' --tagstring '{= s/.*fuzz_// =}' \
"cd {1} && cargo +nightly fuzz run {2} -- -max_total_time=${SECONDS_TOTAL} -jobs=${WORKERS} -workers=${WORKERS} -max_len=65536 -print_final_stats=1 2>&1 | tee ${LOG_DIR}/{2}.log"
echo "---"
echo "Done. Logs saved to: ${LOG_DIR}/"
echo "Run ./fuzz_stats.sh for summary."