etc~ scripts and random things |
| git clone https://github.com/djnnvx/etc.git |
| log | files | refs | archive |
setup.sh (5389B)
1 #!/bin/bash 2 # setup.sh - bootstrap libnfs fuzzing environment. 3 # Same machine specs as the libksba/libusb harnesses: AFL++ (from source or 4 # system), CLASSIC+LAF instrumentation, a CmpLog sibling per harness, ASan+UBSan 5 # at -O0 -g. Signed-int-overflow and shift dropped from UBSan - they're noise 6 # in XDR codepaths that do `value = (value << 8) | next_byte`. 7 # Usage: bash setup.sh [--skip-deps] [--skip-afl] 8 set -euo pipefail 9 10 SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)" 11 cd "${SCRIPT_DIR}" 12 13 AFL_REPO="https://github.com/AFLplusplus/AFLplusplus.git" 14 AFL_BIN="${SCRIPT_DIR}/afl-build/usr/local/bin" 15 16 LIBNFS_REPO="${LIBNFS_REPO:-https://github.com/sahlberg/libnfs.git}" 17 LIBNFS_TAG="${LIBNFS_TAG:-master}" 18 19 # UBSan noise filters (lessons from libksba + smoke-testing libnfs): 20 # signed-integer-overflow / shift - XDR reads bytes into signed int and shifts 21 # function - table-dispatch decoders use (fn_t)cast 22 # alignment - zdr_u_int reads u32 at unaligned offset 23 # All four are benign on x86_64 in practice and would flood AFL with noise. 24 CFLAGS_FUZZ="-fsanitize=address,undefined -fno-sanitize=signed-integer-overflow,shift,function,alignment -g -O0 -fno-omit-frame-pointer" 25 CFLAGS_FUZZ+=" -Wno-implicit-function-declaration -Wno-unused-function -Wno-unused-variable" 26 27 HARNESSES="fuzz_nfs3 fuzz_nfs4 fuzz_mount fuzz_pdu" 28 29 SKIP_DEPS=0 30 SKIP_AFL=0 31 for arg in "$@"; do 32 [[ "$arg" == "--skip-deps" ]] && SKIP_DEPS=1 33 [[ "$arg" == "--skip-afl" ]] && SKIP_AFL=1 34 done 35 36 log() { echo "[*] $*"; } 37 ok() { echo "[+] $*"; } 38 die() { echo "[!] $*" >&2; exit 1; } 39 40 if [[ "${SKIP_DEPS}" -eq 0 ]]; then 41 log "Installing dependencies..." 42 sudo apt-get update -qq 43 sudo apt-get install -y \ 44 build-essential git tmux python3 \ 45 clang llvm lld pkg-config gdb cmake 46 ok "Dependencies installed." 47 fi 48 49 if [[ "${SKIP_AFL}" -eq 1 ]]; then 50 command -v afl-clang-fast > /dev/null 2>&1 || die "afl-clang-fast not found." 51 elif [[ -x "${AFL_BIN}/afl-clang-fast" ]]; then 52 ok "AFL++ already built." 53 export PATH="${AFL_BIN}:${PATH}" 54 else 55 log "Building AFL++..." 56 [[ -d "AFLplusplus" ]] || git clone --depth=1 "${AFL_REPO}" AFLplusplus 57 ( cd AFLplusplus && make source-only -j"$(nproc)" \ 58 && make install PREFIX="${SCRIPT_DIR}/afl-build/usr/local" ) 59 export PATH="${AFL_BIN}:${PATH}" 60 ok "AFL++ built." 61 fi 62 export PATH="${AFL_BIN}:${PATH}" 63 64 if [[ -d "libnfs-src/.git" ]]; then 65 ok "libnfs-src present ($(cd libnfs-src && git describe --tags --always))." 66 else 67 log "Cloning libnfs ${LIBNFS_TAG}..." 68 git clone "${LIBNFS_REPO}" libnfs-src 69 ( cd libnfs-src && git checkout -q "${LIBNFS_TAG}" ) 70 ok "libnfs-src cloned." 71 fi 72 73 # libnfs ships both autotools and CMake build systems. CMake is shorter to 74 # drive and produces a single libnfs.a (autotools fragments into one .la per 75 # protocol subdir + a libtoolize dance for shared-lib symbol export). We 76 # don't need shared libs, so CMake wins. 77 build_lib() { 78 local dir="$1" cc="$2"; shift 2 79 log " building ${dir} (CC=${cc})..." 80 rm -rf "${dir}" 81 mkdir -p "${dir}" 82 ( cd "${dir}" \ 83 && env "$@" CFLAGS="${CFLAGS_FUZZ}" \ 84 cmake -DCMAKE_C_COMPILER="${cc}" \ 85 -DBUILD_SHARED_LIBS=OFF \ 86 -DENABLE_UTILS=OFF \ 87 -DENABLE_EXAMPLES=OFF \ 88 -DENABLE_TESTS=OFF \ 89 "${SCRIPT_DIR}/libnfs-src" >/dev/null \ 90 && env "$@" make -j"$(nproc)" >/dev/null ) 91 [[ -f "${dir}/lib/libnfs.a" ]] || die "${dir}: libnfs.a not produced" 92 } 93 94 log "Building libnfs: instrumented (CLASSIC+LAF), CmpLog, and a plain-ASan copy for repro..." 95 build_lib build-cls afl-clang-fast AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_LAF_ALL=1 96 build_lib build-cmplog afl-clang-fast AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_LAF_ALL=1 AFL_LLVM_CMPLOG=1 97 build_lib build-plain clang 98 ok "libnfs built." 99 100 # CMake bundles everything into a single libnfs.a (protocol .o files are 101 # linked into the top-level static archive). -lpthread is the only runtime 102 # dep when krb5/gnutls are disabled. 103 COMMON_LDLIBS="-lpthread" 104 105 # Per-protocol headers live in their own subdirs (mount/, nfs/, nfs4/, ...). 106 # The harness #includes them by basename and we add each as -I. 107 HARNESS_INCS=( 108 -I "${SCRIPT_DIR}/libnfs-src/include" 109 -I "${SCRIPT_DIR}/libnfs-src/include/nfsc" 110 -I "${SCRIPT_DIR}/libnfs-src/mount" 111 -I "${SCRIPT_DIR}/libnfs-src/nfs" 112 -I "${SCRIPT_DIR}/libnfs-src/nfs4" 113 -I "${SCRIPT_DIR}/libnfs-src/portmap" 114 ) 115 116 log "Building harnesses..." 117 for h in ${HARNESSES}; do 118 log " ${h}..." 119 AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_LAF_ALL=1 \ 120 afl-clang-fast ${CFLAGS_FUZZ} "${HARNESS_INCS[@]}" \ 121 "${h}.c" "build-cls/lib/libnfs.a" ${COMMON_LDLIBS} -o "${h}" 122 AFL_LLVM_INSTRUMENT=CLASSIC AFL_LLVM_LAF_ALL=1 AFL_LLVM_CMPLOG=1 \ 123 afl-clang-fast ${CFLAGS_FUZZ} "${HARNESS_INCS[@]}" \ 124 "${h}.c" "build-cmplog/lib/libnfs.a" ${COMMON_LDLIBS} -o "${h}.cmplog" 125 clang ${CFLAGS_FUZZ} -DNFS_FUZZ_STANDALONE "${HARNESS_INCS[@]}" \ 126 "${h}.c" "build-plain/lib/libnfs.a" ${COMMON_LDLIBS} -o "${h}.repro" 127 done 128 ok "Harnesses built." 129 130 if [[ -d corpus/nfs3 && "$(ls corpus/nfs3 2>/dev/null | wc -l)" -gt 0 ]]; then 131 ok "Corpus present." 132 else 133 log "Generating corpus..." 134 bash gen_corpus.sh 135 fi 136 137 ok "Done. Run: bash start-fuzzers.sh"