etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
run-fuzzers.sh (9119B)
1 #!/bin/bash 2 # run-fuzzers.sh — launch USB/IP fuzzing in tmux with a 2-fuzzer budget. 3 # 4 # Default profile (max-impact): 5 # Pane 1: in-process fuzz_urb (fast, high exec/sec, CmpLog-enabled) 6 # Pane 2: vhci kernel fuzzer (fuzz_vhci_server) against QEMU VM 7 # 8 # Optional profile: 9 # --inproc : protocol + urb only (no QEMU) 10 # --stub : fuzz_urb + stub kernel fuzzer (fuzz_stub_client) against QEMU VM 11 # 12 # This script intentionally keeps only two AFL++ instances active. 13 # For vhci mode it also launches a helper QEMU window in the same tmux session. 14 15 set -euo pipefail 16 17 SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)" 18 cd "${SCRIPT_DIR}" 19 20 AFL_BIN="${SCRIPT_DIR}/afl-build/usr/local/bin" 21 [[ -d "${AFL_BIN}" ]] && export PATH="${AFL_BIN}:${PATH}" 22 23 SESSION="usbip-fuzz" 24 OUTPUT_DIR="${SCRIPT_DIR}/output" 25 CORPUS_DIR="${SCRIPT_DIR}/corpus" 26 CORPUS_PROTOCOL="${CORPUS_DIR}/protocol" 27 CORPUS_URB="${CORPUS_DIR}/urb" 28 CORPUS_VHCI="${CORPUS_DIR}/vhci" 29 CORPUS_STUB="${CORPUS_DIR}/stub" 30 DICT="${SCRIPT_DIR}/dictionaries/usbip.dict" 31 TIMEOUT=1000 32 VHCI_TIMEOUT=5000 33 STUB_TIMEOUT=5000 34 NICE=10 35 PROFILE="max-impact" 36 VMLINUX="${SCRIPT_DIR}/bzImage" 37 VMLINUX_QEMU="${SCRIPT_DIR}/qemu/bzImage" 38 INITRD_VHCI="${SCRIPT_DIR}/initramfs-vhci.cpio.gz" 39 INITRD_VHCI_QEMU="${SCRIPT_DIR}/qemu/initramfs-vhci.cpio.gz" 40 INITRD_SERVER="${SCRIPT_DIR}/initramfs.cpio.gz" 41 INITRD_SERVER_QEMU="${SCRIPT_DIR}/qemu/initramfs.cpio.gz" 42 43 log() { echo "[*] $*"; } 44 ok() { echo "[+] $*"; } 45 die() { echo "[!] $*" >&2; exit 1; } 46 47 case "${1:-}" in 48 --status) 49 command -v afl-whatsup > /dev/null 2>&1 && \ 50 afl-whatsup "${OUTPUT_DIR}" 2>/dev/null || \ 51 echo "Output dir: ${OUTPUT_DIR}" 52 exit 0 ;; 53 --rerun) 54 tmux kill-session -t "${SESSION}" 2>/dev/null || true 55 ;; 56 --inproc) 57 PROFILE="inproc" 58 ;; 59 --stub) 60 PROFILE="stub" 61 ;; 62 --max-impact|"") 63 ;; 64 *) die "Unknown option: ${1}. Use --rerun, --status, --inproc, --stub, --max-impact." ;; 65 esac 66 67 command -v afl-fuzz > /dev/null 2>&1 || die "afl-fuzz not found." 68 [[ -f "fuzz_urb" ]] || die "fuzz_urb not found. Run build_fuzzers.sh first." 69 [[ -f "fuzz_urb.cmplog" ]] || die "fuzz_urb.cmplog not found." 70 [[ -d "${CORPUS_URB}" ]] || die "corpus/urb/ not found. Re-run gen_corpus.py first." 71 tmux list-sessions 2>/dev/null | grep -q "${SESSION}" && \ 72 die "Session '${SESSION}' already running. Use --rerun to restart." 73 74 sudo sysctl -w kernel.core_pattern=core > /dev/null 2>&1 || true 75 echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor > /dev/null 2>&1 || true 76 77 mkdir -p "${OUTPUT_DIR}" 78 79 if [[ "${PROFILE}" == "max-impact" || "${PROFILE}" == "stub" ]]; then 80 if [[ -f "${VMLINUX}" ]]; then 81 KERNEL_PATH="${VMLINUX}" 82 elif [[ -f "${VMLINUX_QEMU}" ]]; then 83 KERNEL_PATH="${VMLINUX_QEMU}" 84 else 85 die "Kernel image not found (expected bzImage or qemu/bzImage)." 86 fi 87 fi 88 89 if [[ "${PROFILE}" == "max-impact" ]]; then 90 [[ -f "fuzz_vhci_server" ]] || die "fuzz_vhci_server not found. Run build_fuzzers.sh first." 91 [[ -d "${CORPUS_VHCI}" ]] || die "corpus/vhci/ not found. Re-run gen_corpus.py first." 92 93 if [[ -f "${INITRD_VHCI}" ]]; then 94 INITRD_PATH="${INITRD_VHCI}" 95 elif [[ -f "${INITRD_VHCI_QEMU}" ]]; then 96 INITRD_PATH="${INITRD_VHCI_QEMU}" 97 else 98 die "initramfs-vhci.cpio.gz not found. Re-run setup.sh." 99 fi 100 fi 101 102 if [[ "${PROFILE}" == "stub" ]]; then 103 [[ -f "fuzz_stub_client" ]] || die "fuzz_stub_client not found. Run build_fuzzers.sh first." 104 [[ -d "${CORPUS_STUB}" ]] || die "corpus/stub/ not found. Re-run gen_corpus.py first." 105 106 if [[ -f "${INITRD_SERVER}" ]]; then 107 INITRD_PATH="${INITRD_SERVER}" 108 elif [[ -f "${INITRD_SERVER_QEMU}" ]]; then 109 INITRD_PATH="${INITRD_SERVER_QEMU}" 110 else 111 die "initramfs.cpio.gz not found. Re-run setup.sh." 112 fi 113 fi 114 115 log "Creating tmux session '${SESSION}'..." 116 tmux new-session -d -s "${SESSION}" -x 220 -y 50 117 tmux split-window -h -t "${SESSION}:0" 118 119 if [[ "${PROFILE}" == "inproc" ]]; then 120 [[ -f "fuzz_protocol" ]] || die "fuzz_protocol not found. Run build_fuzzers.sh first." 121 [[ -f "fuzz_protocol.cmplog" ]] || die "fuzz_protocol.cmplog not found." 122 [[ -d "${CORPUS_PROTOCOL}" ]] || die "corpus/protocol/ not found. Re-run gen_corpus.py first." 123 124 log "Launching AFL++ master (fuzz_protocol)..." 125 tmux send-keys -t "${SESSION}:0.0" \ 126 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 127 ASAN_OPTIONS=abort_on_error=1:symbolize=0:detect_leaks=0 \ 128 nice -n ${NICE} afl-fuzz \ 129 -M master \ 130 -i ${CORPUS_PROTOCOL} \ 131 -o ${OUTPUT_DIR} \ 132 -x ${DICT} \ 133 -c ./fuzz_protocol.cmplog \ 134 -t ${TIMEOUT} \ 135 -p fast \ 136 -m none \ 137 -- ./fuzz_protocol" \ 138 Enter 139 140 log "Launching AFL++ secondary (fuzz_urb)..." 141 tmux send-keys -t "${SESSION}:0.1" \ 142 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 143 ASAN_OPTIONS=abort_on_error=1:symbolize=0:detect_leaks=0 \ 144 nice -n ${NICE} afl-fuzz \ 145 -S urb \ 146 -i ${CORPUS_URB} \ 147 -o ${OUTPUT_DIR} \ 148 -x ${DICT} \ 149 -t ${TIMEOUT} \ 150 -p fast \ 151 -m none \ 152 -- ./fuzz_urb" \ 153 Enter 154 elif [[ "${PROFILE}" == "max-impact" ]]; then 155 log "Launching AFL++ master (fuzz_urb, in-process lane)..." 156 tmux send-keys -t "${SESSION}:0.0" \ 157 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 158 ASAN_OPTIONS=abort_on_error=1:symbolize=0:detect_leaks=0 \ 159 nice -n ${NICE} afl-fuzz \ 160 -M master \ 161 -i ${CORPUS_URB} \ 162 -o ${OUTPUT_DIR} \ 163 -x ${DICT} \ 164 -c ./fuzz_urb.cmplog \ 165 -t ${TIMEOUT} \ 166 -p fast \ 167 -m none \ 168 -- ./fuzz_urb" \ 169 Enter 170 171 log "Launching AFL++ secondary (fuzz_vhci_server, kernel lane)..." 172 tmux send-keys -t "${SESSION}:0.1" \ 173 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 174 nice -n ${NICE} afl-fuzz \ 175 -S vhci \ 176 -i ${CORPUS_VHCI} \ 177 -o ${OUTPUT_DIR} \ 178 -x ${DICT} \ 179 -t ${VHCI_TIMEOUT} \ 180 -m none \ 181 -- ./fuzz_vhci_server @@ 0.0.0.0 13241" \ 182 Enter 183 184 log "Starting vhci QEMU VM window..." 185 tmux new-window -t "${SESSION}" -n vm-vhci 186 tmux send-keys -t "${SESSION}:vm-vhci" \ 187 "qemu-system-x86_64 \ 188 -kernel ${KERNEL_PATH} \ 189 -initrd ${INITRD_PATH} \ 190 -nographic \ 191 -append 'console=ttyS0 quiet panic=-1 oops=panic kasan_multi_shot' \ 192 -m 512M \ 193 -net nic,model=e1000 -net user" \ 194 Enter 195 else 196 log "Launching AFL++ master (fuzz_urb, in-process lane)..." 197 tmux send-keys -t "${SESSION}:0.0" \ 198 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 199 ASAN_OPTIONS=abort_on_error=1:symbolize=0:detect_leaks=0 \ 200 nice -n ${NICE} afl-fuzz \ 201 -M master \ 202 -i ${CORPUS_URB} \ 203 -o ${OUTPUT_DIR} \ 204 -x ${DICT} \ 205 -c ./fuzz_urb.cmplog \ 206 -t ${TIMEOUT} \ 207 -p fast \ 208 -m none \ 209 -- ./fuzz_urb" \ 210 Enter 211 212 log "Launching AFL++ secondary (fuzz_stub_client, kernel lane)..." 213 tmux send-keys -t "${SESSION}:0.1" \ 214 "AFL_SKIP_CPUFREQ=1 AFL_AUTORESUME=1 AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ 215 nice -n ${NICE} afl-fuzz \ 216 -S stub \ 217 -i ${CORPUS_STUB} \ 218 -o ${OUTPUT_DIR} \ 219 -x ${DICT} \ 220 -t ${STUB_TIMEOUT} \ 221 -m none \ 222 -- ./fuzz_stub_client @@ 127.0.0.1 13240" \ 223 Enter 224 225 log "Starting stub QEMU VM window..." 226 tmux new-window -t "${SESSION}" -n vm-stub 227 tmux send-keys -t "${SESSION}:vm-stub" \ 228 "qemu-system-x86_64 \ 229 -kernel ${KERNEL_PATH} \ 230 -initrd ${INITRD_PATH} \ 231 -nographic \ 232 -append 'console=ttyS0 quiet panic=-1 oops=panic kasan_multi_shot' \ 233 -m 512M \ 234 -net nic,model=e1000 -net user,hostfwd=tcp:127.0.0.1:13240-:3240" \ 235 Enter 236 fi 237 238 log "Adding status window..." 239 tmux new-window -t "${SESSION}" -n status 240 tmux send-keys -t "${SESSION}:status" \ 241 "watch -n 10 '$(command -v afl-whatsup) ${OUTPUT_DIR} 2>/dev/null || echo \"output dir: ${OUTPUT_DIR}\"'" \ 242 Enter 243 244 tmux select-window -t "${SESSION}:0" 245 246 ok "Fuzzing session started." 247 echo "" 248 echo " Attach: tmux attach -t ${SESSION}" 249 echo " Status: ${0} --status" 250 echo " Profile: ${PROFILE}" 251 echo " Crashes: ${OUTPUT_DIR}/master/crashes/" 252 [[ "${PROFILE}" == "inproc" ]] && echo " ${OUTPUT_DIR}/urb/crashes/" 253 [[ "${PROFILE}" == "max-impact" ]] && echo " ${OUTPUT_DIR}/vhci/crashes/" 254 [[ "${PROFILE}" == "max-impact" ]] && echo " QEMU console: tmux window 'vm-vhci'" 255 [[ "${PROFILE}" == "stub" ]] && echo " ${OUTPUT_DIR}/stub/crashes/" 256 [[ "${PROFILE}" == "stub" ]] && echo " QEMU console: tmux window 'vm-stub'" 257 echo " Stop: bash cleanup.sh" 258 echo "" 259 260 tmux attach -t "${SESSION}"