etc.git


etc

~ scripts and random things
git clone https://github.com/djnnvx/etc.git
log | files | refs | archive

run-fuzzers.sh (7459B)

      1 #!/bin/bash
      2 # run-fuzzers.sh — launch linux-usb-stack syzkaller fuzzing in tmux.
      3 #
      4 # Three fuzzing profiles targeting different USB attack surfaces:
      5 #
      6 #   --raw-gadget  malicious USB device via syz_usb_* + raw_gadget (DEFAULT)
      7 #                 Exercises: USB core descriptor parsing, host controller drivers,
      8 #                 class driver binding on enumeration.
      9 #
     10 #   --gadget-fw   USB gadget framework via configfs syscalls
     11 #                 Exercises: composite gadget, function drivers, gadget lifecycle.
     12 #
     13 #   --usbfs       userspace → kernel via /dev/bus/usb ioctls (usbfs/devio)
     14 #                 Exercises: URB submission/cancellation, control transfers,
     15 #                 concurrent access bugs, ioctl integer overflows.
     16 #
     17 #   --all         all three profiles simultaneously (uses 6 QEMU VMs total)
     18 #
     19 # Usage:
     20 #   bash run-fuzzers.sh [--raw-gadget|--gadget-fw|--usbfs|--all]
     21 #   bash run-fuzzers.sh --status   # show crash counts
     22 #   bash run-fuzzers.sh --rerun    # kill existing session and restart
     23 
     24 set -euo pipefail
     25 
     26 SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)"
     27 cd "${SCRIPT_DIR}"
     28 
     29 SESSION="usb-fuzz"
     30 PROFILE="raw-gadget"
     31 
     32 log()  { echo "[*] $*"; }
     33 ok()   { echo "[+] $*"; }
     34 die()  { echo "[!] $*" >&2; exit 1; }
     35 
     36 case "${1:-}" in
     37     --status)
     38         # Pull Prometheus metrics from each running syz-manager instance.
     39         # syzkaller exposes /metrics in Prometheus text format — machine-readable,
     40         # no HTML parsing needed. Falls back to disk-based crash count if the
     41         # manager isn't responding (e.g. still starting up, or not launched).
     42         _status_profile() {
     43             local name="${1}" port="${2}"
     44             local metrics crash_count corpus_size coverage exec_total uptime
     45 
     46             metrics="$(curl -sf --max-time 2 "http://127.0.0.1:${port}/metrics" 2>/dev/null || true)"
     47 
     48             if [[ -n "${metrics}" ]]; then
     49                 _metric() { echo "${metrics}" | grep "^${1} " | awk '{print $2}' | head -1; }
     50                 crash_count="$(_metric syz_crash_count 2>/dev/null || echo '?')"
     51                 corpus_size="$(_metric syz_corpus_size 2>/dev/null || echo '?')"
     52                 coverage="$(_metric syz_coverage      2>/dev/null || echo '?')"
     53                 exec_total="$(_metric syz_exec_total  2>/dev/null || echo '?')"
     54                 uptime="$(_metric syz_uptime_secs     2>/dev/null || echo '?')"
     55                 printf "  %-12s  UP    crashes=%-4s corpus=%-6s coverage=%-8s execs=%s\n" \
     56                     "${name}" "${crash_count:-?}" "${corpus_size:-?}" "${coverage:-?}" "${exec_total:-?}"
     57             else
     58                 # Manager not responding — count crash dirs on disk as fallback
     59                 local disk_crashes=0
     60                 [[ -d "workdir-${name}/crashes" ]] && \
     61                     disk_crashes=$(find "workdir-${name}/crashes" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
     62                 printf "  %-12s  DOWN  (crashes on disk: %d)\n" "${name}" "${disk_crashes}"
     63             fi
     64         }
     65 
     66         echo "=== syzkaller USB stack fuzzer status ==="
     67         echo ""
     68         _status_profile "raw-gadget" 56741
     69         _status_profile "gadget-fw"  56742
     70         _status_profile "usbfs"      56743
     71         echo ""
     72         echo "  Web UIs:  http://127.0.0.1:56741  (raw-gadget)"
     73         echo "            http://127.0.0.1:56742  (gadget-fw)"
     74         echo "            http://127.0.0.1:56743  (usbfs)"
     75         echo ""
     76         echo "  Tip: curl -s http://127.0.0.1:PORT/metrics | grep '^syz_'"
     77         exit 0 ;;
     78     --rerun)
     79         tmux kill-session -t "${SESSION}" 2>/dev/null || true
     80         ;;
     81     --raw-gadget|"")
     82         PROFILE="raw-gadget" ;;
     83     --gadget-fw)
     84         PROFILE="gadget-fw" ;;
     85     --usbfs)
     86         PROFILE="usbfs" ;;
     87     --all)
     88         PROFILE="all" ;;
     89     *) die "Unknown option: ${1}. Use --raw-gadget, --gadget-fw, --usbfs, --all, --status, --rerun." ;;
     90 esac
     91 
     92 # ── preflight checks ─────────────────────────────────────────────────────────
     93 SYZ_MANAGER="$(find "${SCRIPT_DIR}/syzkaller/bin" -name "syz-manager" -type f 2>/dev/null | head -1)"
     94 [[ -n "${SYZ_MANAGER}" && -x "${SYZ_MANAGER}" ]] || die "syz-manager not found under syzkaller/bin/. Run setup.sh first."
     95 [[ -f "bzImage" ]]              || die "bzImage not found. Run setup.sh first."
     96 [[ -f "qemu/initramfs.cpio.gz" ]] || die "qemu/initramfs.cpio.gz not found. Run setup.sh first."
     97 [[ -f "qemu/id_rsa" ]]          || die "qemu/id_rsa not found. Run setup.sh first."
     98 command -v qemu-system-x86_64 > /dev/null || die "qemu-system-x86_64 not found."
     99 
    100 tmux list-sessions 2>/dev/null | grep -q "^${SESSION}:" && \
    101     die "Session '${SESSION}' already running. Use --rerun to restart or --status to check."
    102 
    103 # ── generate config from template (substitute __DIR__ with actual path) ──────
    104 gen_config() {
    105     local profile="${1}"
    106     local tmpfile
    107     tmpfile="$(mktemp /tmp/syz-${profile}-XXXXXX.cfg)"
    108     sed "s|__DIR__|${SCRIPT_DIR}|g" "${SCRIPT_DIR}/syzkaller-${profile}.cfg" > "${tmpfile}"
    109     echo "${tmpfile}"
    110 }
    111 
    112 # ── launch a single syz-manager instance in a named tmux window ──────────────
    113 launch_profile() {
    114     local profile="${1}"
    115     local cfg
    116     cfg="$(gen_config "${profile}")"
    117 
    118     mkdir -p "workdir-${profile}"
    119 
    120     local port
    121     case "${profile}" in
    122         raw-gadget) port=56741 ;;
    123         gadget-fw)  port=56742 ;;
    124         usbfs)      port=56743 ;;
    125     esac
    126 
    127     log "Launching syz-manager for profile '${profile}' (http://127.0.0.1:${port})..."
    128     tmux new-window -t "${SESSION}" -n "${profile}"
    129     tmux send-keys -t "${SESSION}:${profile}" \
    130         "${SYZ_MANAGER} -config ${cfg}" \
    131         Enter
    132 }
    133 
    134 # ── create tmux session ───────────────────────────────────────────────────────
    135 log "Creating tmux session '${SESSION}'..."
    136 tmux new-session -d -s "${SESSION}" -x 220 -y 50
    137 
    138 # The first window is created automatically; rename it to match the first profile.
    139 # We'll use it for the status monitor.
    140 
    141 if [[ "${PROFILE}" == "all" ]]; then
    142     launch_profile "raw-gadget"
    143     launch_profile "gadget-fw"
    144     launch_profile "usbfs"
    145 else
    146     launch_profile "${PROFILE}"
    147 fi
    148 
    149 # ── status window ─────────────────────────────────────────────────────────────
    150 tmux rename-window -t "${SESSION}:0" "status"
    151 tmux send-keys -t "${SESSION}:status" \
    152     "watch -n 15 'bash ${SCRIPT_DIR}/run-fuzzers.sh --status'" \
    153     Enter
    154 
    155 tmux select-window -t "${SESSION}:status"
    156 
    157 ok "Fuzzing session started."
    158 echo ""
    159 echo "  Attach:    tmux attach -t ${SESSION}"
    160 echo "  Status:    ${0} --status"
    161 echo "  Profile:   ${PROFILE}"
    162 echo ""
    163 case "${PROFILE}" in
    164     raw-gadget) echo "  Web UI:    http://127.0.0.1:56741" ;;
    165     gadget-fw)  echo "  Web UI:    http://127.0.0.1:56742" ;;
    166     usbfs)      echo "  Web UI:    http://127.0.0.1:56743" ;;
    167     all)        echo "  Web UIs:   http://127.0.0.1:56741  (raw-gadget)"
    168                 echo "             http://127.0.0.1:56742  (gadget-fw)"
    169                 echo "             http://127.0.0.1:56743  (usbfs)" ;;
    170 esac
    171 echo "  Crashes:   workdir-*/crashes/"
    172 echo "  Stop:      bash cleanup.sh"
    173 echo ""
    174 
    175 tmux attach -t "${SESSION}"