blob: 4d23256fb617b5fdf1a6d7e5c84b20588f2d96a4 [file]
#!/usr/bin/env bash
# Swap-under--n test for T-01.
#
# Belt-and-suspenders check: even under the LD_PRELOAD fclose-swap attack,
# passing -n (which skips CopyStat entirely) must leave target.txt's mode
# unchanged. This test runs the swap repro with -n injected into the brotli
# command line — CopyStat never runs, so the symlink is irrelevant and the
# target's mode must stay 0600.
#
# This is a defense-in-depth test: if a future change were to wire
# CopyStat() up on a code path that ignored copy_stat, this test would
# catch it even if the primary fix is intact.
#
# We inline the attack setup here instead of reusing repro_copystat_swap.sh
# because that script hard-codes the brotli arg list. The same helper
# (libfclose_swap.so) is reused as-is.
#
# Usage: test_copystat_swap_with_no_copy_stat.sh /path/to/brotli /path/to/libfclose_swap.so
set -euo pipefail
if [[ $# -ne 2 ]]; then
echo "usage: $0 /path/to/brotli /path/to/libfclose_swap.so" >&2
exit 2
fi
brotli_bin=$(readlink -f -- "$1")
swap_so=$(readlink -f -- "$2")
script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
workdir=$(mktemp -d)
ld_preload="$swap_so"
cleanup() {
rm -rf -- "$workdir"
}
trap cleanup EXIT
cp -- "$script_dir/plain.bin" "$script_dir/plain.bin.br" \
"$script_dir/target.txt" "$workdir"/
chmod 0644 "$workdir/plain.bin"
chmod 0644 "$workdir/plain.bin.br"
chmod 0600 "$workdir/target.txt"
out_path="$workdir/out"
target_path="$workdir/target.txt"
if ldd "$brotli_bin" | grep -q 'libasan'; then
asan_runtime=$(cc -print-file-name=libasan.so)
if [[ -f "$asan_runtime" ]]; then
ld_preload="$asan_runtime:$ld_preload"
fi
fi
if [[ -n "${LD_PRELOAD:-}" ]]; then
ld_preload="$ld_preload:$LD_PRELOAD"
fi
env \
BROTLI_SWAP_OUTPUT_ABS="$out_path" \
BROTLI_SWAP_TARGET_ABS="$target_path" \
LD_PRELOAD="$ld_preload" \
"$brotli_bin" -d -n -o "$out_path" "$workdir/plain.bin.br" || true
# With -n, CopyStat never runs, so target.txt must remain 0600.
mode=$(stat -c '%a' "$target_path")
if [[ "$mode" != "600" ]]; then
echo "FAIL: target mode changed to $mode under -n; CopyStat was called" \
"despite copy_stat==BROTLI_FALSE" >&2
exit 1
fi
# Bonus: the content must also be unchanged.
if ! cmp -s -- "$workdir/target.txt" "$script_dir/target.txt"; then
echo "FAIL: target content changed under -n attack" >&2
exit 1
fi
echo "T-01 SWAP+NO-COPY-STAT: target unchanged under attack with -n"