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
Signed-off-by: Kamal Tufekcic <kamal@lo.sh>
108 lines
4 KiB
Bash
Executable file
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."
|