DF-0889 / run.sh
#!/bin/sh # DF-0889 trigger: leak one struct hpfsmount per failed hpfs mount. # # Strategy: a zero-filled image fails the SuperBlock magic check at # sys/vfs/hpfs/hpfs_vfsops.c:282 -> goto failed (line 285), which drops # through the `failed:` label at line 328 WITHOUT calling # kfree(hpmp, M_HPFSMNT). Each attempt leaks one hpfsmount. # # Run as root (or with vfs.usermount=1 + chowned vn device). set -u # How many failed mount attempts to perform. Keep small enough to finish # quickly but large enough that the leak is unambiguous in vmstat -m. N=${1:-200} # Pre-clean any prior state. umount /mnt/df0889 2>/dev/null # Detach any vn devices that point at our image (best-effort). for v in $(ls /dev/vn* 2>/dev/null); do vnconfig -u "$v" 2>/dev/null done # Make sure hpfs.ko is loaded so the filesystem type is registered. if ! kldstat -q -m hpfs; then kldload hpfs.ko || { echo "FAIL: cannot kldload hpfs.ko"; exit 2; } fi # Backing image: 4 MB of zeros. The SuperBlock (sector 16) and SpareBlock # (sector 17) reads succeed (return zero pages) but the magic check fails, # which is the simplest `goto failed` path after the hpmp kmalloc. IMG=/tmp/df0889.img dd if=/dev/zero of="$IMG" bs=1m count=4 2>/dev/null # Attach a vnode-backed memory disk (autoclone โ prints the resulting /dev/vnN). VNDEV=$(vnconfig -c vn "$IMG" 2>/dev/null) if [ -z "$VNDEV" ]; then echo "FAIL: vnconfig -c vn $IMG" exit 2 fi # vnconfig prints e.g. "vn4" โ normalize to /dev/vn4. case "$VNDEV" in /*) VNPATH="$VNDEV" ;; *) VNPATH="/dev/$VNDEV" ;; esac echo "Attached backing image at $VNPATH" mkdir -p /mnt/df0889 # Baseline allocation count. # NOTE: vmstat -m reports the M_HPFSMNT type under the human-readable name # "HPFS_mount". Only types with >=1 allocation are listed, so a baseline of # 0 means the line is absent โ treat that as 0. BEF=$(vmstat -m | awk '$1 == "HPFS_mount" {print $2}') [ -n "$BEF" ] || BEF=0 echo "BEFORE: HPFS_mount alloc count = $BEF" echo "Attempting $N failed hpfs mounts on $VNPATH ..." ok=0 fail=0 i=0 while [ "$i" -lt "$N" ]; do i=$((i + 1)) if mount -t hpfs -o ro "$VNPATH" /mnt/df0889 2>/dev/null; then # Should never happen on a zero image โ if it does, unmount and count. umount /mnt/df0889 2>/dev/null ok=$((ok + 1)) else fail=$((fail + 1)) fi done AFT=$(vmstat -m | awk '$1 == "HPFS_mount" {print $2}') [ -n "$AFT" ] || AFT=0 echo "AFTER : HPFS_mount alloc count = $AFT" echo "mount results: succeeded=$ok failed=$fail (out of $N)" DELTA=$((AFT - BEF)) echo "LEAK: HPFS_mount grew by $DELTA allocations over $N failed mounts" # Show the in-use vs free in the slab for context. vmstat -m | awk '$1 == "HPFS_mount" {print "vmstat -m HPFS_mount line:", $0}' # Cleanup (note: leaked hpmps are NOT reclaimed by this cleanup โ that is # the bug. Only a kldunload would free them, and even then only if the # module refcount allows it.) vnconfig -u "$VNPATH" 2>/dev/null rm -f "$IMG" exit 0 |