etc.git


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"