#!/bin/bash #=============================================================================== # mkfs-guarded-harness — audit-D1 test harness for configs/felhom-mkfs-guarded.sh. # # Runs the REAL wrapper against throwaway loop devices with: # - a PATH-shimmed `lsblk` that fakes the member FSTYPE signal (FIXTURE_FSTYPE), # - a private mount namespace (unshare -m) that bind-mounts a RECORDER over # /usr/sbin/mkfs.ext4 — so a wrapper that decides to format provably "formats" # (the recorder logs the argv) while NO real mkfs can ever run, and # - /dev/null bind-mounted over pvs for the pvs-absent case. # # Nothing real is formatted; nothing leaks outside the namespace; the loop files # are throwaway temps. Run as root on a Linux host (losetup/unshare needed). # # Usage: mkfs-guarded-harness.sh # Exit 0 = all cases behave like the FIXED wrapper should. Running it against the # pre-fix wrapper is the red-proof: the member/RO cases will FAIL (recorder fired). #=============================================================================== set -euo pipefail WRAPPER="${1:?usage: mkfs-guarded-harness.sh }" WRAPPER="$(readlink -f "$WRAPPER")" [[ -r "$WRAPPER" ]] || { echo "no wrapper at $WRAPPER" >&2; exit 2; } [[ "$(id -u)" == 0 ]] || { echo "must run as root (losetup/unshare)" >&2; exit 2; } WORK="$(mktemp -d /tmp/mkfs-harness.XXXXXX)" LOOP=""; LOOP_RO="" cleanup() { [[ -n "$LOOP" ]] && losetup -d "$LOOP" 2>/dev/null || true [[ -n "$LOOP_RO" ]] && losetup -d "$LOOP_RO" 2>/dev/null || true rm -rf "$WORK" } trap cleanup EXIT # --- throwaway loop devices (a plain RW one + a kernel-read-only one) --- truncate -s 64M "$WORK/plain.img" truncate -s 64M "$WORK/ro.img" LOOP="$(losetup -f --show "$WORK/plain.img")" LOOP_RO="$(losetup -f --show -r "$WORK/ro.img")" echo "loop devices: rw=$LOOP ro=$LOOP_RO" # --- PATH shim: lsblk fakes only the `-nro FSTYPE` read when FIXTURE_FSTYPE is set --- mkdir -p "$WORK/shim" cat > "$WORK/shim/lsblk" <<'EOF' #!/bin/bash if [[ -n "${FIXTURE_FSTYPE:-}" && "${1:-}" == "-nro" && "${2:-}" == "FSTYPE" ]]; then echo "$FIXTURE_FSTYPE" exit 0 fi exec /usr/bin/lsblk "$@" EOF chmod 0755 "$WORK/shim/lsblk" # --- the mkfs recorder bound over /usr/sbin/mkfs.ext4 inside the namespace --- cat > "$WORK/fake-mkfs" <<'EOF' #!/bin/bash echo "mkfs.ext4 $*" >> "$MKFS_MARKER" exit 0 EOF chmod 0755 "$WORK/fake-mkfs" # run_case pass=0; fail=0 run_case() { local name="$1" dev="$2" fixture="$3" hidepvs="$4" want="$5" msg="$6" local marker="$WORK/marker.$RANDOM"; rm -f "$marker" local hide_cmds="" if [[ "$hidepvs" == 1 ]]; then for p in /usr/sbin/pvs /sbin/pvs; do [[ -e "$p" ]] && hide_cmds+="mount --bind /dev/null $p; " done fi set +e out="$(unshare -m bash -c " set -e mount --bind '$WORK/fake-mkfs' /usr/sbin/mkfs.ext4 $hide_cmds export PATH='$WORK/shim':\$PATH MKFS_MARKER='$marker' FIXTURE_FSTYPE='$fixture' exec bash '$WRAPPER' '$dev' ext4 " 2>&1)" rc=$? set -e local fired=no; [[ -s "$marker" ]] && fired=yes local verdict=FAIL if [[ "$want" == refuse ]]; then [[ $rc -ne 0 && "$fired" == no && "$out" == *"$msg"* ]] && verdict=PASS else [[ $rc -eq 0 && "$fired" == yes && "$(cat "$marker")" == *"$dev"* ]] && verdict=PASS fi if [[ "$verdict" == PASS ]]; then pass=$((pass+1)); else fail=$((fail+1)); fi printf '%-4s %-38s rc=%-3s mkfs-fired=%-3s want=%s\n' "$verdict" "$name" "$rc" "$fired" "$want" [[ "$verdict" == FAIL ]] && printf ' output: %s\n' "$out" return 0 } echo "--- wrapper under test: $WRAPPER ---" run_case "refuse zfs_member" "$LOOP" "zfs_member" 0 refuse "zfs_member" run_case "refuse linux_raid_member" "$LOOP" "linux_raid_member" 0 refuse "linux_raid_member" run_case "refuse crypto_LUKS" "$LOOP" "crypto_LUKS" 0 refuse "crypto_LUKS" run_case "refuse swap" "$LOOP" "swap" 0 refuse "swap" run_case "refuse LVM2_member" "$LOOP" "LVM2_member" 0 refuse "LVM" run_case "refuse read-only device" "$LOOP_RO" "" 0 refuse "read-only" run_case "pvs-hidden still catches LVM" "$LOOP" "LVM2_member" 1 refuse "LVM" run_case "plain blank disk formats" "$LOOP" "" 0 format "" echo "--- $pass passed, $fail failed ---" [[ $fail -eq 0 ]]