1#!/bin/bash 2set -e 3 4print_help() 5{ 6 cat <<EOFHELP 7# Simple wrapper around a libfuzzer test run, as much for 8# documentation as direct use. The idea here is really simple: build 9# for the Zephyr "native_posix" board (which is a just a x86 10# executable for the build host, not an emulated device) and run the 11# resulting zephyr.exe file. This specifies a "fuzz_corpus" directory 12# to save the seeds that produce useful coverage output for use in 13# repeated runs (these are not particularly large, we might consider 14# curating and commiting such a seed directory to the tree). 15# 16# The tool will run until it finds a failure condition. You will see 17# MANY errors on stdout from all the randomized input. Don't try to 18# capture this, either let it output to a terminal or arrange to keep 19# only the last XXX lines after the tool exits. 20# 21# The only prerequisite to install is a clang compiler on the host. 22# Versions 12+ have all been observed to work. 23# 24# You will need the kconfigs specified below for correct operation, 25# but can add more at the end of this script's command line to 26# duplicate configurations as needed. Alternatively you can pass 27# overlay files in kconfig syntax via: 28# fuzz.sh -t 300 -- -DOVERLAY_CONFIG=..., etc... 29EOFHELP 30} 31 32 33# To test this test, make the following change locally: 34: <<EOF_TEST_PATCH 35--- a/src/ipc/ipc3/handler.c 36+++ b/src/ipc/ipc3/handler.c 37@@ -1609,6 +1609,8 @@ void ipc_boot_complete_msg(struct ipc_cmd_hdr *header, uint32_t data) 38 39 void ipc_cmd(struct ipc_cmd_hdr *_hdr) 40 { 41+ __ASSERT(false, "test the fuzzer test"); 42+ 43 struct sof_ipc_cmd_hdr *hdr = ipc_from_hdr(_hdr); 44EOF_TEST_PATCH 45 46 47main() 48{ 49 setup 50 51 # Parse "$@". getopts stops after '--' 52 while getopts "ho:t:" opt; do 53 case "$opt" in 54 h) print_help; exit 0;; 55 o) FUZZER_STDOUT="$OPTARG";; 56 t) TEST_DURATION="$OPTARG";; 57 *) print_help; exit 1;; 58 esac 59 done 60 61 # Pass all "$@" arguments remaining after '--' to cmake. 62 # This also drops _leading_ '--'. 63 shift $((OPTIND-1)) 64 65 # Default values 66 : "${TEST_DURATION:=3}" 67 : "${FUZZER_STDOUT:=/dev/stdout}" # bashism 68 69 west build -d build-fuzz -b native_posix "$SOF_TOP"/app/ -- \ 70 -DCONFIG_ASSERT=y \ 71 -DCONFIG_SYS_HEAP_BIG_ONLY=y \ 72 -DCONFIG_ZEPHYR_NATIVE_DRIVERS=y \ 73 -DCONFIG_ARCH_POSIX_LIBFUZZER=y \ 74 -DCONFIG_ARCH_POSIX_FUZZ_TICKS=100 \ 75 -DCONFIG_ASAN=y "$@" 76 77 mkdir -p ./fuzz_corpus 78 79 timeoutret=0 80 date 81 timeout -k 10 "$TEST_DURATION" >"$FUZZER_STDOUT" build-fuzz/zephyr/zephyr.exe ./fuzz_corpus || 82 timeoutret=$? 83 if [ $timeoutret -eq 124 ]; then 84 # The current ASAN seems overly sensitive: it frequently (but not always) complains 85 # loudly that it has been aborted with a so-called DEADLYSIGNAL when the timeout 86 # command above actually delivers just a gentle TERM by default. Counteracts the 87 # wrong impression this unpredictable whining can give with a proud "successfully" 88 # message. 89 printf '\n\nSuccessfully aborted fuzzer after %d seconds test duration with DEADLYSIGNAL\n' \ 90 "$TEST_DURATION" 91 else 92 die 'zephyr.exe fuzzer stopped before timing out: %d\n' $timeoutret 93 fi 94 date 95} 96 97 98setup() 99{ 100 SOF_TOP=$(cd "$(dirname "$0")/.." && pwd) 101 export SOF_TOP 102 103 export ZEPHYR_TOOLCHAIN_VARIANT=llvm 104 105 # ZEPHYR_BASE. Does not seem required. 106 local WS_TOP 107 WS_TOP=$(cd "$SOF_TOP"; west topdir) 108 # The manifest itself is not a west project 109 ZEP_DIR=$(2>/dev/null west list -f '{path}' zephyr || echo 'zephyr') 110 export ZEPHYR_BASE="$WS_TOP/$ZEP_DIR" 111 112} 113 114die() 115{ 116 >&2 printf '%s ERROR: ' "$0" 117 # We want die() to be usable exactly like printf 118 # shellcheck disable=SC2059 119 >&2 printf "$@" 120 >&2 printf '\n' 121 exit 1 122} 123 124main "$@" 125