Fuzz replay
This commit is contained in:
parent
5c542ff9c8
commit
7a47e66651
|
|
@ -1,5 +1,5 @@
|
||||||
name: 'Cairn Zig Fuzz (AFL++)'
|
name: 'Cairn Zig Fuzz (AFL++)'
|
||||||
description: 'Build and run Zig AFL++ fuzz targets, reporting crashes and corpus to Cairn. Each target is built via `zig build fuzz -Dfuzz-target=<name>`.'
|
description: 'Build and run Zig AFL++ fuzz targets, reporting crashes and corpus to Cairn. Each target is built twice: `zig build fuzz -Dfuzz-target=<name>` (AFL-instrumented) and `zig build fuzz-replay -Dfuzz-target=<name>` (plain, for crash replay).'
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
cairn_server:
|
cairn_server:
|
||||||
|
|
@ -115,7 +115,30 @@ runs:
|
||||||
echo "Building ${TARGET_COUNT} target(s)"
|
echo "Building ${TARGET_COUNT} target(s)"
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
|
|
||||||
|
# Helper to find the single executable in a bin/ directory.
|
||||||
|
find_bin() {
|
||||||
|
local BIN_DIR="$1"
|
||||||
|
local LABEL="$2"
|
||||||
|
if [ -n "${FUZZ_BINARY}" ]; then
|
||||||
|
echo "${BIN_DIR}/${FUZZ_BINARY}"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
local BIN
|
||||||
|
BIN=$(find "${BIN_DIR}" -maxdepth 1 -type f -executable)
|
||||||
|
local COUNT
|
||||||
|
COUNT=$(echo "${BIN}" | wc -l)
|
||||||
|
if [ "${COUNT}" -eq 0 ] || [ -z "${BIN}" ]; then
|
||||||
|
echo "ERROR: No executable found in ${BIN_DIR} (${LABEL})" >&2
|
||||||
|
return 1
|
||||||
|
elif [ "${COUNT}" -gt 1 ]; then
|
||||||
|
echo "ERROR: Multiple executables in ${BIN_DIR} (${LABEL}), specify fuzz_binary input" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "${BIN}"
|
||||||
|
}
|
||||||
|
|
||||||
declare -A TARGET_BINS
|
declare -A TARGET_BINS
|
||||||
|
declare -A REPLAY_BINS
|
||||||
for i in "${!TARGET_NAMES[@]}"; do
|
for i in "${!TARGET_NAMES[@]}"; do
|
||||||
FUZZ_TARGET="${TARGET_NAMES[$i]}"
|
FUZZ_TARGET="${TARGET_NAMES[$i]}"
|
||||||
NUM=$((i + 1))
|
NUM=$((i + 1))
|
||||||
|
|
@ -124,33 +147,32 @@ runs:
|
||||||
|
|
||||||
echo "[${NUM}/${TARGET_COUNT}] Building ${FUZZ_TARGET}..."
|
echo "[${NUM}/${TARGET_COUNT}] Building ${FUZZ_TARGET}..."
|
||||||
|
|
||||||
# Each target gets its own zig-out to avoid binary name collisions.
|
# Each target gets its own output dir to avoid binary name collisions.
|
||||||
ZIG_OUT="${WORK}/zig-out"
|
# 1) AFL-instrumented binary for fuzzing.
|
||||||
rm -rf "${ZIG_OUT}"
|
AFL_OUT="${WORK}/afl-out"
|
||||||
zig build fuzz -Dfuzz-target="${FUZZ_TARGET}" --prefix "${ZIG_OUT}"
|
rm -rf "${AFL_OUT}"
|
||||||
|
zig build fuzz -Dfuzz-target="${FUZZ_TARGET}" --prefix "${AFL_OUT}"
|
||||||
# Locate fuzz binary.
|
|
||||||
if [ -n "${FUZZ_BINARY}" ]; then
|
|
||||||
FUZZ_BIN="${ZIG_OUT}/bin/${FUZZ_BINARY}"
|
|
||||||
else
|
|
||||||
FUZZ_BIN=$(find "${ZIG_OUT}/bin" -maxdepth 1 -type f -executable)
|
|
||||||
BIN_COUNT=$(echo "${FUZZ_BIN}" | wc -l)
|
|
||||||
if [ "${BIN_COUNT}" -eq 0 ] || [ -z "${FUZZ_BIN}" ]; then
|
|
||||||
echo "ERROR: No executable found in ${ZIG_OUT}/bin/"
|
|
||||||
exit 1
|
|
||||||
elif [ "${BIN_COUNT}" -gt 1 ]; then
|
|
||||||
echo "ERROR: Multiple executables in ${ZIG_OUT}/bin/, specify fuzz_binary input"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
FUZZ_BIN=$(find_bin "${AFL_OUT}/bin" "afl")
|
||||||
if [ ! -x "${FUZZ_BIN}" ]; then
|
if [ ! -x "${FUZZ_BIN}" ]; then
|
||||||
echo "ERROR: Fuzz binary not found or not executable: ${FUZZ_BIN}"
|
echo "ERROR: Fuzz binary not found or not executable: ${FUZZ_BIN}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TARGET_BINS["${FUZZ_TARGET}"]="${FUZZ_BIN}"
|
TARGET_BINS["${FUZZ_TARGET}"]="${FUZZ_BIN}"
|
||||||
echo " Built: ${FUZZ_BIN}"
|
echo " AFL binary: ${FUZZ_BIN}"
|
||||||
|
|
||||||
|
# 2) Plain binary for crash replay (no AFL instrumentation).
|
||||||
|
REPLAY_OUT="${WORK}/replay-out"
|
||||||
|
rm -rf "${REPLAY_OUT}"
|
||||||
|
zig build fuzz-replay -Dfuzz-target="${FUZZ_TARGET}" --prefix "${REPLAY_OUT}"
|
||||||
|
|
||||||
|
REPLAY_BIN=$(find_bin "${REPLAY_OUT}/bin" "replay")
|
||||||
|
if [ ! -x "${REPLAY_BIN}" ]; then
|
||||||
|
echo "ERROR: Replay binary not found or not executable: ${REPLAY_BIN}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
REPLAY_BINS["${FUZZ_TARGET}"]="${REPLAY_BIN}"
|
||||||
|
echo " Replay binary: ${REPLAY_BIN}"
|
||||||
done
|
done
|
||||||
|
|
||||||
# ── Phase 2: Prepare seeds and Cairn targets (sequential, network I/O) ──
|
# ── Phase 2: Prepare seeds and Cairn targets (sequential, network I/O) ──
|
||||||
|
|
@ -326,6 +348,7 @@ runs:
|
||||||
FUZZ_TARGET="${TARGET_NAMES[$i]}"
|
FUZZ_TARGET="${TARGET_NAMES[$i]}"
|
||||||
NUM=$((i + 1))
|
NUM=$((i + 1))
|
||||||
FUZZ_BIN="${TARGET_BINS[${FUZZ_TARGET}]}"
|
FUZZ_BIN="${TARGET_BINS[${FUZZ_TARGET}]}"
|
||||||
|
REPLAY_BIN="${REPLAY_BINS[${FUZZ_TARGET}]}"
|
||||||
RUN_ID="${RUN_IDS[${FUZZ_TARGET}]}"
|
RUN_ID="${RUN_IDS[${FUZZ_TARGET}]}"
|
||||||
CAIRN_TARGET_ID="${CAIRN_TARGET_IDS[${FUZZ_TARGET}]}"
|
CAIRN_TARGET_ID="${CAIRN_TARGET_IDS[${FUZZ_TARGET}]}"
|
||||||
FINDINGS="work/${FUZZ_TARGET}/findings"
|
FINDINGS="work/${FUZZ_TARGET}/findings"
|
||||||
|
|
@ -346,16 +369,20 @@ runs:
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Replay the crash input to capture the stack trace.
|
# Replay using the non-AFL binary to get a proper stack trace.
|
||||||
STACK_TRACE=""
|
STACK_TRACE=""
|
||||||
CRASH_MSG="AFL++ crash (${FUZZ_TARGET}): ${CRASH_NAME}"
|
CRASH_MSG="AFL++ crash (${FUZZ_TARGET}): ${CRASH_NAME}"
|
||||||
REPLAY_OUTPUT=$(timeout 10 "${FUZZ_BIN}" < "${crash_file}" 2>&1 || true)
|
REPLAY_OUTPUT=$(timeout 10 "${REPLAY_BIN}" < "${crash_file}" 2>&1 || true)
|
||||||
if [ -n "${REPLAY_OUTPUT}" ]; then
|
if [ -n "${REPLAY_OUTPUT}" ]; then
|
||||||
STACK_TRACE="${REPLAY_OUTPUT}"
|
STACK_TRACE="${REPLAY_OUTPUT}"
|
||||||
FIRST_LINE=$(echo "${REPLAY_OUTPUT}" | grep -m1 -iE 'panic|error|fault|abort|overflow|undefined|sanitizer|SUMMARY' || true)
|
FIRST_LINE=$(echo "${REPLAY_OUTPUT}" | grep -m1 -iE 'panic|error|fault|abort|overflow|undefined|sanitizer|SUMMARY' || true)
|
||||||
if [ -n "${FIRST_LINE}" ]; then
|
if [ -n "${FIRST_LINE}" ]; then
|
||||||
CRASH_MSG="${FIRST_LINE}"
|
CRASH_MSG="${FIRST_LINE}"
|
||||||
fi
|
fi
|
||||||
|
echo " Replay (${CRASH_NAME}):"
|
||||||
|
echo "${REPLAY_OUTPUT}" | head -10 | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo " Replay produced no output for ${CRASH_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " Uploading crash: ${CRASH_NAME}"
|
echo " Uploading crash: ${CRASH_NAME}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue