Add segfault-focused fuzzing test without GNU parallel dependency
Replaces script.sh and script3.sh with new comprehensive fuzzing test: - Tests all system binaries with random flag combinations - Uses 22 diverse fuzz files (malformed JSON/XML, binary garbage, edge cases) - Reports only real crashes (SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS) - Bash background jobs for parallelization (max 10 jobs, no GNU parallel) - Skips GUI apps (GNOME, KDE, Qt, X11) and GNU parallel tools - Renamed sql.txt to sql_injection.txt to avoid socket conflicts - Removed parallel package dependency from main.fmf Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
dbf67e8bc7
commit
68f7483be4
6 changed files with 386 additions and 296 deletions
7
system-in-use/run-them-all/.testinfo.tmt
Normal file
7
system-in-use/run-them-all/.testinfo.tmt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Description: test
|
||||
Owner: Petr Sklenar <psklenar@redhat.com>
|
||||
RunFor:
|
||||
RunTest: ./runtest.sh
|
||||
Path: /mnt/tests/system-in-use/run-them-all
|
||||
Requires: parallel
|
||||
TestTime: 6h
|
||||
|
|
@ -5,8 +5,6 @@ test: ./runtest.sh
|
|||
framework: beakerlib
|
||||
duration: 6h
|
||||
enabled: false
|
||||
recommend:
|
||||
- parallel
|
||||
adjust:
|
||||
- when: "force == yes"
|
||||
enabled: true
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/bash
|
||||
# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
# Author: psklenar@redhat.com <psklenar@redhat.com>
|
||||
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
@ -11,12 +10,8 @@ rlJournalStart
|
|||
CORES_COUNT_OLD=$(coredumpctl list|wc -l)
|
||||
rlPhaseEnd
|
||||
|
||||
rlPhaseStartTest "run version 1"
|
||||
bash script.sh
|
||||
rlPhaseEnd
|
||||
|
||||
rlPhaseStartTest "run version 3"
|
||||
bash script3.sh
|
||||
rlPhaseStartTest "run"
|
||||
bash try-all-binaries-help-options.sh
|
||||
rlPhaseEnd
|
||||
|
||||
rlPhaseStartTest
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# see parallel , for athor note!
|
||||
mkdir -p ~/.parallel
|
||||
touch ~/.parallel/will-cite
|
||||
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
TARGET_DIRS="/usr/bin /usr/sbin"
|
||||
LOG_FILE="smoke_test_$(date +%Y%m%d_%H%M%S).log"
|
||||
SUMMARY_FILE="summary_report.txt"
|
||||
|
||||
# LIST OF BINARIES TO SKIP
|
||||
# Allready reported
|
||||
SKIP_LIST=(
|
||||
"/usr/bin/unoconv"
|
||||
"/usr/bin/ibus-setup"
|
||||
"/usr/bin/ffmpeg"
|
||||
"/usr/bin/ffprobe"
|
||||
"/usr/bin/ffplay"
|
||||
"/usr/bin/gnome-keyring-3"
|
||||
"/usr/bin/gnome-boxes"
|
||||
"/usr/bin/ibus-setup"
|
||||
"/usr/bin/unix_chkpwd"
|
||||
"/usr/bin/unix_update"
|
||||
"/usr/bin/cracklib-check"
|
||||
"/usr/bin/code2color"
|
||||
"/usr/bin/fsidd"
|
||||
"/usr/bin/stund"
|
||||
"/usr/bin/beakerlib"
|
||||
"/usr/bin/vimcolor"
|
||||
)
|
||||
|
||||
# Prepare skip pattern for grep
|
||||
SKIP_PATTERN=$(printf "|%s" "${SKIP_LIST[@]}")
|
||||
SKIP_PATTERN=${SKIP_PATTERN:1}
|
||||
|
||||
# Attempt to increase file descriptor limits
|
||||
ulimit -n 65535 2>/dev/null
|
||||
|
||||
echo "--- STARTING DESTRUCTION ENGINE ---"
|
||||
echo "Logging to: $LOG_FILE"
|
||||
echo "Skipping known issues: ${SKIP_LIST[*]}"
|
||||
echo "-----------------------------------"
|
||||
|
||||
# Initialize log file
|
||||
> "$LOG_FILE"
|
||||
|
||||
# THE CORE ENGINE
|
||||
# 1. Find executables
|
||||
# 2. Filter out skipped binaries
|
||||
# 3. Run in parallel (100 jobs at once, 5s timeout)
|
||||
find $TARGET_DIRS -maxdepth 1 -executable -type f | grep -vE "($SKIP_PATTERN)" | parallel --no-notice --jobs 100 --timeout 5 --tag \
|
||||
"tmp_err=\$(mktemp); \
|
||||
yes 'chaos_input' | {} --help >/dev/null 2>\"\$tmp_err\"; \
|
||||
EXIT_CODE=\$?; \
|
||||
if grep -Ei 'traceback|stack dump|segfault|exception|core dumped|assertion|invalid pointer' \"\$tmp_err\"; then \
|
||||
{ \
|
||||
echo '=================================================='; \
|
||||
echo 'COMMAND: {}'; \
|
||||
echo 'TIMESTAMP: \$(date +%H:%M:%S)'; \
|
||||
echo 'EXIT CODE: \$EXIT_CODE'; \
|
||||
echo 'ERROR LOG:'; \
|
||||
cat \"\$tmp_err\"; \
|
||||
echo '=================================================='; \
|
||||
echo ''; \
|
||||
} >> $LOG_FILE; \
|
||||
fi; \
|
||||
rm -f \"\$tmp_err\""
|
||||
|
||||
# --- POST-PROCESSING & STATISTICS ---
|
||||
echo "--- ANALYZING RESULTS ---"
|
||||
|
||||
TOTAL_CRASHES=$(grep -c "COMMAND:" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
SEGFAULTS=$(grep -ci "segfault" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
TRACEBACKS=$(grep -ci "traceback" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
|
||||
{
|
||||
echo "SMOKE TEST SUMMARY - $(date)"
|
||||
echo "------------------------------------------"
|
||||
echo "Total binaries tested (approx): $(find $TARGET_DIRS -maxdepth 1 -executable | wc -l)"
|
||||
echo "Skipped binaries: ${#SKIP_LIST[@]}"
|
||||
echo "Binaries with detected issues: $TOTAL_CRASHES"
|
||||
echo "Segmentation faults: $SEGFAULTS"
|
||||
echo "Python/Other Tracebacks: $TRACEBACKS"
|
||||
echo ""
|
||||
echo "TOP 10 DETECTED ISSUES:"
|
||||
grep "COMMAND:" "$LOG_FILE" | head -n 10
|
||||
} > "$SUMMARY_FILE"
|
||||
|
||||
echo "Done! Summary in $SUMMARY_FILE, full details in $LOG_FILE."
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Fuzzing audit of /usr/bin and /usr/sbin: runs each binary with random options
|
||||
# from --help, using input files or stdin. Logs crashes (segfault, traceback).
|
||||
# Dumps coredumps for failed binaries. Output: $HOME/fuzz_lab/fuzz_*.log, summary.txt, coredumps/
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# === CONFIGURATION ===
|
||||
BIN_DIRS="/usr/bin /usr/sbin"
|
||||
WORKSPACE="${HOME}/fuzz_lab"
|
||||
LOG_FILE="${WORKSPACE}/fuzz_$(date +%Y%m%d_%H%M%S).log"
|
||||
SUMMARY_FILE="${WORKSPACE}/summary.txt"
|
||||
RUNS_PER_BIN=15
|
||||
MAX_JOBS=1 # run this many binaries in parallel (background jobs)
|
||||
TIMEOUT_SEC=5 # seconds before SIGTERM - more time for crashes to manifest
|
||||
KILL_AFTER=15 # seconds before SIGKILL after SIGTERM
|
||||
|
||||
# Skip list: binary names only (use .re: for regex)
|
||||
SKIP_NAMES=(
|
||||
bash rm dd mkfs reboot shutdown poweroff dnf yum rpm vi nano vim login kill pkill
|
||||
sfdisk fdisk parted systemd-ask-password sulogin chronyc chronyd xfs_freeze
|
||||
unoconv ibus-setup ffmpeg ffprobe ffplay gnome-keyring-3 gnome-boxes
|
||||
unix_chkpwd unix_update cracklib-check code2color fsidd stund vimcolor
|
||||
ip nmcli nmtui ifconfig route arp iptables ip6tables nft firewall-cmd
|
||||
dhclient dhcpcd wpa_supplicant brctl bridge aws
|
||||
'.re:^beakerlib|gnome|gui|qt|wayland|vlc'
|
||||
'.re:^ip-|^nm-|^NetworkManager|^ovs-'
|
||||
# '.re:^[jJ]'
|
||||
'.re:^[iI]'
|
||||
'.re:^[hH]'
|
||||
# '.re:^[a-sA-S]'
|
||||
)
|
||||
|
||||
|
||||
# Debug: run only binaries whose name starts with this letter (e.g. "g"); empty = run all
|
||||
DEBUG_LETTER=""
|
||||
|
||||
should_skip() {
|
||||
local name=$(basename "$1") s
|
||||
for s in "${SKIP_NAMES[@]}"; do
|
||||
if [[ "$s" == .re:* ]]; then
|
||||
[[ "$name" =~ ${s#.re:} ]] && return 0
|
||||
else
|
||||
[[ "$name" == "$s" ]] && return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# === SETUP ===
|
||||
mkdir -p "$WORKSPACE"
|
||||
ulimit -n 65535 2>/dev/null || true
|
||||
|
||||
# Debug: if script stops unexpectedly, check these files:
|
||||
# current_run.txt = last BIN + ARGS being executed (which cmd caused the stop)
|
||||
# script_stopped.txt, progress_*.txt
|
||||
# Tip: run in tmux/screen to survive SSH disconnects (SIGHUP)
|
||||
STOP_LOG="$WORKSPACE/script_stopped.txt"
|
||||
PROGRESS_LOG="$WORKSPACE/progress_$$.txt"
|
||||
CURRENT_RUN_FILE="$WORKSPACE/current_run.txt"
|
||||
trap 'ec=$?; echo "$(date -Iseconds) EXIT code=$ec line=$LINENO" >> "$STOP_LOG"' EXIT
|
||||
trap 'echo "$(date -Iseconds) SIGNAL (HUP=disconnect?)" >> "$STOP_LOG"; exit 129' HUP INT TERM
|
||||
trap '' TSTP TTIN TTOU # ignore Ctrl+Z / job-control from fuzzed binaries
|
||||
|
||||
# Test data
|
||||
printf 'line1\nline2\n123\n' > "$WORKSPACE/input.txt"
|
||||
touch "$WORKSPACE/empty.txt"
|
||||
|
||||
# Build list of binaries to test
|
||||
ALL_BINS=()
|
||||
while IFS= read -r b; do
|
||||
should_skip "$b" && continue
|
||||
if [[ -n "$DEBUG_LETTER" ]]; then
|
||||
name=$(basename "$b")
|
||||
[[ "${name,,}" != "${DEBUG_LETTER,,}"* ]] && continue
|
||||
fi
|
||||
ALL_BINS+=("$b")
|
||||
done < <(find $BIN_DIRS -maxdepth 1 -executable -type f 2>/dev/null | sort -u)
|
||||
|
||||
TOTAL=${#ALL_BINS[@]}
|
||||
[[ -n "$DEBUG_LETTER" ]] && echo "DEBUG: only binaries starting with '$DEBUG_LETTER'"
|
||||
echo "=== FUZZING AUDIT (parallel, max $MAX_JOBS jobs) ==="
|
||||
echo "Binaries to test: $TOTAL"
|
||||
echo "Log: $LOG_FILE"
|
||||
echo "===================="
|
||||
|
||||
> "$LOG_FILE"
|
||||
RESULT_DIR="$WORKSPACE/result_$$"
|
||||
mkdir -p "$RESULT_DIR"
|
||||
|
||||
process_bin() {
|
||||
local bin="$1" name flags err ex pkg r n chosen args use_stdin
|
||||
name=$(basename "$bin")
|
||||
local out="$RESULT_DIR/$(echo "$bin" | tr '/' '_').log"
|
||||
flags=()
|
||||
flags_tmp=$(mktemp)
|
||||
timeout -k $KILL_AFTER ${TIMEOUT_SEC}s "$bin" --help 2>&1 | tr -d '\0' |
|
||||
grep -a -oE -e '--[a-zA-Z0-9][a-zA-Z0-9_-]*' -e '-[a-zA-Z0-9]' |
|
||||
grep -a -vE 'help|version|usage' | sort -u | head -n 20 > "$flags_tmp"
|
||||
while IFS= read -r f; do flags+=("$f"); done < "$flags_tmp"
|
||||
rm -f "$flags_tmp"
|
||||
[[ ${#flags[@]} -eq 0 ]] && flags=(-v -a -q -f)
|
||||
|
||||
for ((r=0; r<RUNS_PER_BIN; r++)); do
|
||||
n=$((1 + RANDOM % 3))
|
||||
chosen=$(printf '%s\n' "${flags[@]}" | shuf -n "$n" | tr '\n' ' ')
|
||||
args="$chosen"
|
||||
use_stdin=0
|
||||
case $((RANDOM % 4)) in
|
||||
0) args+=" $WORKSPACE/input.txt" ;;
|
||||
1) args+=" $WORKSPACE/empty.txt" ;;
|
||||
2) args+=" -"; use_stdin=1 ;;
|
||||
3) ;;
|
||||
esac
|
||||
|
||||
err=$(mktemp)
|
||||
echo "BIN: $bin | ARGS: $args" > "$CURRENT_RUN_FILE"
|
||||
(
|
||||
trap '[[ $? -gt 128 ]] && echo "BIN: $bin | ARGS: $args" >&2' EXIT
|
||||
ulimit -v 307200 2>/dev/null || true
|
||||
export MALLOC_CHECK_=3 LC_ALL=C
|
||||
unset DISPLAY WAYLAND_DISPLAY
|
||||
if [[ $use_stdin -eq 1 ]]; then
|
||||
timeout -k $KILL_AFTER --foreground ${TIMEOUT_SEC}s bash -c "cat $WORKSPACE/input.txt | $bin $args" >/dev/null 2>"$err"
|
||||
else
|
||||
timeout -k $KILL_AFTER --foreground ${TIMEOUT_SEC}s bash -c "$bin $args" >/dev/null 2>"$err"
|
||||
fi
|
||||
)
|
||||
ex=$?
|
||||
|
||||
if [[ $ex -gt 128 ]] || grep -qiE 'traceback|segfault|core dumped|assertion|invalid pointer' "$err" 2>/dev/null; then
|
||||
pkg=$(rpm -qf "$bin" --qf '%{NAME}' 2>/dev/null || echo "unknown")
|
||||
{
|
||||
echo "---"
|
||||
echo "CMD: $bin $args"
|
||||
echo "PKG: $pkg | EXIT: $ex"
|
||||
head -n 10 "$err"
|
||||
echo ""
|
||||
} >> "$out"
|
||||
fi
|
||||
rm -f "$err"
|
||||
done
|
||||
}
|
||||
|
||||
# === PARALLEL LOOP (background jobs, no GNU parallel) ===
|
||||
for ((i=0; i<TOTAL; i+=MAX_JOBS)); do
|
||||
for ((j=0; j<MAX_JOBS && i+j<TOTAL; j++)); do
|
||||
process_bin "${ALL_BINS[i+j]}" &
|
||||
done
|
||||
wait
|
||||
echo -n "."
|
||||
echo "$(date -Iseconds) batch $((i/MAX_JOBS + 1)) done, tested up to $((i + j))/$TOTAL" >> "$PROGRESS_LOG"
|
||||
done
|
||||
|
||||
# Merge result files into LOG_FILE
|
||||
for f in "$RESULT_DIR"/*.log; do
|
||||
[[ -f "$f" ]] && cat "$f" >> "$LOG_FILE"
|
||||
done
|
||||
rm -rf "$RESULT_DIR"
|
||||
|
||||
tested=$TOTAL
|
||||
issues=$( (grep -c "CMD:" "$LOG_FILE" 2>/dev/null || echo 0) | head -1 | tr -d '\n')
|
||||
issues=${issues:-0}
|
||||
echo ""
|
||||
|
||||
# === SUMMARY ===
|
||||
{
|
||||
echo "FUZZ AUDIT SUMMARY - $(date)"
|
||||
echo "=========================="
|
||||
echo "Binaries tested: $tested"
|
||||
echo "Issues found: $issues"
|
||||
echo ""
|
||||
if [[ $issues -gt 0 ]]; then
|
||||
echo "TOP PACKAGES:"
|
||||
grep "PKG:" "$LOG_FILE" | sed 's/.*PKG: //' | cut -d'|' -f1 | sort | uniq -c | sort -rn | head -10
|
||||
echo ""
|
||||
echo "SAMPLE COMMANDS:"
|
||||
grep "CMD:" "$LOG_FILE" | tail -5
|
||||
fi
|
||||
} > "$SUMMARY_FILE"
|
||||
|
||||
# === COREDUMP DUMP for each failed binary ===
|
||||
if [[ $issues -gt 0 ]]; then
|
||||
COREDUMP_DIR="$WORKSPACE/coredumps"
|
||||
mkdir -p "$COREDUMP_DIR"
|
||||
grep "CMD:" "$LOG_FILE" | sed 's/^CMD: //' | awk '{print $1}' | sort -u | while read -r bin; do
|
||||
[[ -z "$bin" ]] && continue
|
||||
name=$(basename "$bin")
|
||||
out="$COREDUMP_DIR/coredump_${name}.dump"
|
||||
if coredumpctl dump "$bin" -o "$out" 2>/dev/null; then
|
||||
echo "Dumped coredump for $bin -> $out"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Done. Issues: $issues | Summary: $SUMMARY_FILE"
|
||||
377
system-in-use/run-them-all/try-all-binaries-help-options.sh
Executable file
377
system-in-use/run-them-all/try-all-binaries-help-options.sh
Executable file
|
|
@ -0,0 +1,377 @@
|
|||
#!/bin/bash
|
||||
# Segfault-Focused Fuzz Test
|
||||
# Extracts flags from --help, tests with diverse fuzz files
|
||||
# Reports ONLY real crashes (segfault, abort, illegal instruction, etc.)
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# === CONFIGURATION ===
|
||||
BIN_DIRS="/usr/bin /usr/sbin"
|
||||
WORKSPACE="${HOME}/fuzz_lab"
|
||||
LOG_FILE="${WORKSPACE}/segfault_fuzz_$(date +%Y%m%d_%H%M%S).log"
|
||||
SUMMARY_FILE="${WORKSPACE}/segfault_summary.txt"
|
||||
RUNS_PER_BIN=20 # More runs per binary for better coverage
|
||||
MAX_PARALLEL=10 # Maximum parallel jobs (no rush)
|
||||
TIMEOUT_SEC=5 # Timeout before SIGTERM
|
||||
KILL_AFTER=10 # Timeout before SIGKILL
|
||||
|
||||
# === SKIP LIST ===
|
||||
SKIP_NAMES=(
|
||||
# Destructive/dangerous
|
||||
bash rm dd mkfs reboot shutdown poweroff halt init telinit
|
||||
sfdisk fdisk parted cfdisk gdisk sgdisk mkswap
|
||||
|
||||
# System critical
|
||||
login kill pkill killall systemd-ask-password sulogin chronyc chronyd
|
||||
xfs_freeze fsck e2fsck xfs_repair
|
||||
|
||||
# Network tools
|
||||
ip nmcli nmtui ifconfig route arp brctl bridge
|
||||
iptables ip6tables nft ebtables arptables firewall-cmd
|
||||
dhclient dhcpcd wpa_supplicant hostapd
|
||||
|
||||
# Package managers
|
||||
dnf yum rpm zypper apt apt-get dpkg pacman
|
||||
|
||||
# Editors
|
||||
vi vim nvim nano emacs ed
|
||||
|
||||
# Cloud tools
|
||||
aws gcloud kubectl docker podman
|
||||
|
||||
# GNU parallel tools (creates sockets, interferes with fuzz files)
|
||||
sql env_parallel parallel niceload parsort
|
||||
|
||||
# Already reported bugs
|
||||
unoconv ibus-setup ffmpeg ffprobe ffplay
|
||||
gnome-keyring-3 gnome-boxes unix_chkpwd unix_update
|
||||
cracklib-check code2color fsidd stund vimcolor
|
||||
|
||||
# GUI/Interactive (regex patterns)
|
||||
'.re:^gnome-|^gtk|^gdk|^gio-|^gsettings'
|
||||
'.re:^kde|^plasma|^kwin|^dolphin|^konsole'
|
||||
'.re:^xfce|^mate-|^cinnamon|^lxde|^lxqt'
|
||||
'.re:^qt|^Qt|^wayland|^weston'
|
||||
'.re:^X|^x11|^xorg|^xinit|^xterm'
|
||||
'.re:^vlc|^totem|^rhythmbox|^brasero'
|
||||
'.re:^firefox|^thunderbird|^chrome|^chromium'
|
||||
'.re:^gedit|^kate|^kwrite|^pluma'
|
||||
'.re:gui|^beakerlib'
|
||||
'.re:^ip-|^nm-|^NetworkManager|^ovs-'
|
||||
'.re:^[iI]'
|
||||
'.re:^[hH]'
|
||||
)
|
||||
|
||||
# === HELPER FUNCTIONS ===
|
||||
should_skip() {
|
||||
local name=$(basename "$1") s
|
||||
for s in "${SKIP_NAMES[@]}"; do
|
||||
if [[ "$s" == .re:* ]]; then
|
||||
[[ "$name" =~ ${s#.re:} ]] && return 0
|
||||
else
|
||||
[[ "$name" == "$s" ]] && return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# === SETUP ===
|
||||
mkdir -p "$WORKSPACE"
|
||||
ulimit -n 65535 2>/dev/null || true
|
||||
|
||||
# === DIVERSE FUZZ FILES ===
|
||||
echo "Creating fuzz test files..."
|
||||
|
||||
# 1. Empty file
|
||||
touch "$WORKSPACE/empty.dat"
|
||||
|
||||
# 2. Small text file
|
||||
printf 'line1\nline2\n123\ntest\n' > "$WORKSPACE/small.txt"
|
||||
|
||||
# 3. Malformed JSON
|
||||
cat > "$WORKSPACE/bad.json" <<'EOF'
|
||||
{"key": "value", "broken": [1, 2, 3,
|
||||
EOF
|
||||
|
||||
# 4. Malformed XML
|
||||
cat > "$WORKSPACE/bad.xml" <<'EOF'
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<unclosed>
|
||||
<tag>value
|
||||
EOF
|
||||
|
||||
# 5. Binary garbage
|
||||
dd if=/dev/urandom of="$WORKSPACE/random.bin" bs=1K count=10 2>/dev/null
|
||||
|
||||
# 6. Binary with null bytes
|
||||
printf '\x00\x00\xff\xff\xde\xad\xbe\xef\x00\x00' > "$WORKSPACE/nulls.bin"
|
||||
|
||||
# 7. Large file (triggers buffer issues)
|
||||
dd if=/dev/zero of="$WORKSPACE/large.dat" bs=1M count=50 2>/dev/null
|
||||
|
||||
# 8. UTF-8 edge cases
|
||||
printf '\xc3\x28\xe2\x82\x28\xf0\x28\x8c\x28' > "$WORKSPACE/bad_utf8.txt"
|
||||
|
||||
# 9. Format string attempts
|
||||
printf '%%s%%s%%s%%n%%x%%x' > "$WORKSPACE/format.txt"
|
||||
|
||||
# 10. Path traversal patterns
|
||||
printf '../../../etc/passwd\n..\\..\\..\\windows\\system32' > "$WORKSPACE/paths.txt"
|
||||
|
||||
# 11. SQL-like injection patterns
|
||||
printf "' OR 1=1 --\n\"; DROP TABLE users; --" > "$WORKSPACE/sql_injection.txt"
|
||||
|
||||
# 12. Command injection patterns
|
||||
printf '; ls -la\n| cat /etc/passwd\n`whoami`' > "$WORKSPACE/cmd.txt"
|
||||
|
||||
# 13. Very long line (buffer overflow test)
|
||||
python3 -c "print('A' * 100000)" > "$WORKSPACE/longline.txt"
|
||||
|
||||
# 14. Many short lines
|
||||
seq 1 100000 > "$WORKSPACE/manylines.txt"
|
||||
|
||||
# 15. Mixed binary/text
|
||||
cat "$WORKSPACE/small.txt" "$WORKSPACE/random.bin" > "$WORKSPACE/mixed.dat"
|
||||
|
||||
# 16. Compressed data patterns
|
||||
printf '\x1f\x8b\x08\x00\x00\x00\x00\x00' > "$WORKSPACE/gzip.dat"
|
||||
printf '\x50\x4b\x03\x04' > "$WORKSPACE/zip.dat"
|
||||
|
||||
# 17. Image-like headers (but corrupted)
|
||||
printf '\xff\xd8\xff\xe0\x00\x10JFIF' > "$WORKSPACE/fake.jpg"
|
||||
printf '\x89PNG\r\n\x1a\n' > "$WORKSPACE/fake.png"
|
||||
|
||||
# 18. ELF header (but truncated)
|
||||
printf '\x7fELF\x02\x01\x01\x00' > "$WORKSPACE/fake.elf"
|
||||
|
||||
# 19. Script with shebang
|
||||
printf '#!/bin/sh\necho test' > "$WORKSPACE/script.sh"
|
||||
|
||||
# 20. Just dashes (flag-like)
|
||||
printf -- '---\n-\n--help\n--version\n-v\n' > "$WORKSPACE/dashes.txt"
|
||||
|
||||
# List of fuzz files (as string for export)
|
||||
FUZZ_FILE_COUNT=22
|
||||
FUZZ_FILE_NAMES="empty.dat small.txt bad.json bad.xml random.bin nulls.bin large.dat bad_utf8.txt format.txt paths.txt sql_injection.txt cmd.txt longline.txt manylines.txt mixed.dat gzip.dat zip.dat fake.jpg fake.png fake.elf script.sh dashes.txt"
|
||||
|
||||
# Tracking files
|
||||
STOP_LOG="$WORKSPACE/script_stopped.txt"
|
||||
CURRENT_RUN_FILE="$WORKSPACE/current_run.txt"
|
||||
trap 'ec=$?; echo "$(date -Iseconds) EXIT code=$ec" >> "$STOP_LOG"' EXIT
|
||||
trap 'echo "$(date -Iseconds) SIGNAL RECEIVED" >> "$STOP_LOG"; exit 129' HUP INT TERM
|
||||
|
||||
# Build list of binaries to test
|
||||
echo "=== BUILDING BINARY LIST ==="
|
||||
ALL_BINS=()
|
||||
while IFS= read -r b; do
|
||||
should_skip "$b" && continue
|
||||
ALL_BINS+=("$b")
|
||||
done < <(find $BIN_DIRS -maxdepth 1 -executable -type f 2>/dev/null | sort -u)
|
||||
|
||||
TOTAL=${#ALL_BINS[@]}
|
||||
echo "Total binaries to test: $TOTAL"
|
||||
echo "Runs per binary: $RUNS_PER_BIN"
|
||||
echo "Max parallel jobs: $MAX_PARALLEL"
|
||||
echo "Fuzz files: $FUZZ_FILE_COUNT"
|
||||
echo "Log file: $LOG_FILE"
|
||||
echo "===================="
|
||||
|
||||
> "$LOG_FILE"
|
||||
|
||||
fuzz_binary() {
|
||||
local bin="$1"
|
||||
local name=$(basename "$bin")
|
||||
local pkg=$(rpm -qf "$bin" --qf '%{NAME}' 2>/dev/null || echo "unknown")
|
||||
|
||||
# Extract flags from --help
|
||||
local flags=()
|
||||
local flags_tmp=$(mktemp)
|
||||
timeout -k 5 3s "$bin" --help 2>&1 | tr -d '\0' |
|
||||
grep -aoE -e '--[a-zA-Z0-9][a-zA-Z0-9_-]*' -e '-[a-zA-Z0-9]' |
|
||||
grep -avE 'help|version|usage' | sort -u | head -n 50 > "$flags_tmp"
|
||||
|
||||
while IFS= read -r f; do flags+=("$f"); done < "$flags_tmp"
|
||||
rm -f "$flags_tmp"
|
||||
|
||||
# Fallback if no flags found
|
||||
[[ ${#flags[@]} -eq 0 ]] && flags=(-v -a -q -f -d -i -o)
|
||||
|
||||
# Run multiple fuzz iterations
|
||||
for ((r=0; r<RUNS_PER_BIN; r++)); do
|
||||
# Randomly select 1-4 flags
|
||||
local n=$((1 + RANDOM % 4))
|
||||
local chosen=$(printf '%s\n' "${flags[@]}" | shuf -n "$n" | tr '\n' ' ')
|
||||
local args="$chosen"
|
||||
local use_stdin=0
|
||||
|
||||
# Detect if flags suggest file input
|
||||
local needs_file=0
|
||||
if [[ "$chosen" =~ (--file|--input|--config|--from|-f|-i|-c|--load|--read) ]]; then
|
||||
needs_file=1
|
||||
fi
|
||||
|
||||
# Add fuzz file intelligently
|
||||
if [[ $needs_file -eq 1 ]] || [[ $((RANDOM % 3)) -eq 0 ]]; then
|
||||
# Pick random fuzz file from workspace
|
||||
local fuzz_files_arr=($FUZZ_FILE_NAMES)
|
||||
local fuzz_idx=$((RANDOM % ${#fuzz_files_arr[@]}))
|
||||
local fuzz_file="$WORKSPACE/${fuzz_files_arr[$fuzz_idx]}"
|
||||
|
||||
if [[ $((RANDOM % 5)) -eq 0 ]]; then
|
||||
# Sometimes stdin
|
||||
use_stdin=1
|
||||
args+=" -"
|
||||
else
|
||||
# File argument
|
||||
args+=" $fuzz_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
local err=$(mktemp)
|
||||
local exit_code=0
|
||||
|
||||
# Track current execution
|
||||
echo "BIN: $bin | ARGS: $args | PKG: $pkg" > "$CURRENT_RUN_FILE"
|
||||
|
||||
# Execute with safety limits
|
||||
(
|
||||
ulimit -v 512000 2>/dev/null || true # 500MB memory limit
|
||||
ulimit -f 102400 2>/dev/null || true # 100MB file size limit
|
||||
export MALLOC_CHECK_=3 LC_ALL=C
|
||||
unset DISPLAY WAYLAND_DISPLAY
|
||||
|
||||
if [[ $use_stdin -eq 1 ]]; then
|
||||
local first_fuzz="$WORKSPACE/$(echo $FUZZ_FILE_NAMES | awk '{print $1}')"
|
||||
timeout -k $KILL_AFTER --foreground ${TIMEOUT_SEC}s bash -c \
|
||||
"cat $first_fuzz | $bin $args" >/dev/null 2>"$err"
|
||||
else
|
||||
timeout -k $KILL_AFTER --foreground ${TIMEOUT_SEC}s \
|
||||
"$bin" $args >/dev/null 2>"$err"
|
||||
fi
|
||||
)
|
||||
exit_code=$?
|
||||
|
||||
# ONLY report real crashes (not usage errors)
|
||||
# Exit codes: 139=SIGSEGV, 134=SIGABRT, 136=SIGFPE, 132=SIGILL, 133=SIGTRAP, 135=SIGBUS
|
||||
if [[ $exit_code -eq 139 ]] || [[ $exit_code -eq 134 ]] || [[ $exit_code -eq 136 ]] || \
|
||||
[[ $exit_code -eq 132 ]] || [[ $exit_code -eq 133 ]] || [[ $exit_code -eq 135 ]] || \
|
||||
grep -qiE 'segmentation fault|segfault|core dumped|double free|heap corruption|buffer overflow|stack smashing|memory corruption|use after free|ASAN|UBSAN' "$err" 2>/dev/null; then
|
||||
|
||||
# Log the crash
|
||||
{
|
||||
echo "=================================================="
|
||||
echo "REAL CRASH DETECTED"
|
||||
echo "COMMAND: $bin $args"
|
||||
echo "PACKAGE: $pkg"
|
||||
echo "EXIT CODE: $exit_code"
|
||||
case $exit_code in
|
||||
139) echo "SIGNAL: SIGSEGV (Segmentation fault)" ;;
|
||||
134) echo "SIGNAL: SIGABRT (Abort)" ;;
|
||||
136) echo "SIGNAL: SIGFPE (Floating point exception)" ;;
|
||||
132) echo "SIGNAL: SIGILL (Illegal instruction)" ;;
|
||||
133) echo "SIGNAL: SIGTRAP (Trace trap)" ;;
|
||||
135) echo "SIGNAL: SIGBUS (Bus error)" ;;
|
||||
esac
|
||||
echo "TIMESTAMP: $(date -Iseconds)"
|
||||
echo "--------------------------------------------------"
|
||||
echo "ERROR OUTPUT:"
|
||||
head -n 30 "$err"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
}
|
||||
fi
|
||||
|
||||
rm -f "$err"
|
||||
done
|
||||
}
|
||||
|
||||
# === PARALLEL EXECUTION ===
|
||||
echo "Starting parallel fuzzing (segfaults only)..."
|
||||
|
||||
running_jobs=0
|
||||
for bin in "${ALL_BINS[@]}"; do
|
||||
# Wait if we hit max parallel jobs
|
||||
while [[ $running_jobs -ge $MAX_PARALLEL ]]; do
|
||||
wait -n 2>/dev/null || true
|
||||
((running_jobs--))
|
||||
done
|
||||
|
||||
# Start fuzzing in background
|
||||
{
|
||||
fuzz_binary "$bin" >> "$LOG_FILE" 2>&1
|
||||
} &
|
||||
|
||||
((running_jobs++))
|
||||
done
|
||||
|
||||
# Wait for all remaining jobs
|
||||
wait
|
||||
|
||||
echo ""
|
||||
echo "Fuzzing complete!"
|
||||
|
||||
# === STATISTICS & SUMMARY ===
|
||||
echo "Generating summary..."
|
||||
|
||||
total_crashes=$(grep -c "REAL CRASH DETECTED" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
segfaults=$(grep -c "SIGSEGV" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
aborts=$(grep -c "SIGABRT" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
sigfpe=$(grep -c "SIGFPE" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
sigill=$(grep -c "SIGILL" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
sigbus=$(grep -c "SIGBUS" "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
|
||||
{
|
||||
echo "SEGFAULT-FOCUSED FUZZ TEST SUMMARY - $(date)"
|
||||
echo "============================================"
|
||||
echo "Binaries tested: $TOTAL"
|
||||
echo "Runs per binary: $RUNS_PER_BIN"
|
||||
echo "Total test iterations: $((TOTAL * RUNS_PER_BIN))"
|
||||
echo "Fuzz files used: $FUZZ_FILE_COUNT"
|
||||
echo ""
|
||||
echo "REAL CRASHES FOUND:"
|
||||
echo " Total: $total_crashes"
|
||||
echo " Segmentation faults: $segfaults"
|
||||
echo " Aborts (SIGABRT): $aborts"
|
||||
echo " FP exceptions: $sigfpe"
|
||||
echo " Illegal instruction: $sigill"
|
||||
echo " Bus errors: $sigbus"
|
||||
echo ""
|
||||
|
||||
if [[ $total_crashes -gt 0 ]]; then
|
||||
echo "AFFECTED PACKAGES:"
|
||||
grep "PACKAGE:" "$LOG_FILE" | sed 's/.*PACKAGE: //' | sort | uniq -c | sort -rn
|
||||
echo ""
|
||||
echo "ALL CRASHES:"
|
||||
grep "COMMAND:" "$LOG_FILE"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Full log: $LOG_FILE"
|
||||
} > "$SUMMARY_FILE"
|
||||
|
||||
# === COREDUMP COLLECTION ===
|
||||
if [[ $total_crashes -gt 0 ]] && command -v coredumpctl &>/dev/null; then
|
||||
echo "Collecting coredumps..."
|
||||
COREDUMP_DIR="$WORKSPACE/coredumps_$(date +%Y%m%d_%H%M%S)"
|
||||
mkdir -p "$COREDUMP_DIR"
|
||||
|
||||
grep "COMMAND:" "$LOG_FILE" | sed 's/^.*COMMAND: //' | awk '{print $1}' | sort -u | while read -r bin; do
|
||||
[[ -z "$bin" ]] && continue
|
||||
name=$(basename "$bin")
|
||||
out="$COREDUMP_DIR/coredump_${name}.dump"
|
||||
if coredumpctl dump "$bin" -o "$out" 2>/dev/null; then
|
||||
echo " Dumped: $name"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Coredumps saved to: $COREDUMP_DIR"
|
||||
fi
|
||||
|
||||
# === FINAL OUTPUT ===
|
||||
echo ""
|
||||
echo "========================================"
|
||||
cat "$SUMMARY_FILE"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "Done! Check $SUMMARY_FILE for summary."
|
||||
Loading…
Add table
Add a link
Reference in a new issue