⬢ DragonFlyBSD Kernel Audit
DF-4900 / dm_minor_alias.sh
← back to finding ↓ download raw
#!/bin/sh
# DF-4900 PoC: dm minor-number unit aliasing + clone-bitmap wrong-bit free
# Part A (wrong-bit free / unit leak): create X, remove X, create Y ->
#   Y must get unit 0 again (minor 0x1E110007) if the bitmap round-trip were
#   correct; instead Y gets unit 1 (minor 0x1E11000F) because
#   dkunit(dkmakewholedisk(0)) = 0|0x200 = 512, so bit 0 is never freed.
# Part B (live duplicate minors): with unit-0 device alive, create 1024 more;
#   the device handed unit 1024 encodes to the SAME minor as unit 0.
echo "== Part A: bitmap round-trip leak =="
dmsetup create xa --notable
ls -l /dev/mapper/xa | awk '{print "xa rdev:", $5, $6}'
dmsetup remove xa
dmsetup create ya --notable
ls -l /dev/mapper/ya | awk '{print "ya rdev:", $5, $6}'
echo "(expected if buggy: ya != xa minor; correct behavior: same minor)"
dmsetup remove ya

echo "== Part B: 1025 live devices -> duplicate minor =="
i=0
while [ $i -lt 1025 ]; do
	dmsetup create $(printf d%04d $i) --notable || { echo "create failed at $i"; exit 1; }
	i=$((i+1))
done
echo "-- first (unit 0) and last (unit 1024):"
ls -l /dev/mapper/d0000 /dev/mapper/d1024 | awk '{print $9, $5, $6}'
echo "-- minor collision check:"
m0=$(stat -f %R /dev/mapper/d0000)
m1024=$(stat -f %R /dev/mapper/d1024)
echo "d0000 rdev=$m0  d1024 rdev=$m1024"
if [ "$m0" = "$m1024" ]; then
	echo "REPRODUCED: two live dm devices share the same device number"
else
	echo "not reproduced"
fi
echo "-- by-minor lookup confusion (info via major:minor of d1024):"
maj=$(stat -f %Hd /dev/mapper/d1024)
min=$(stat -f %Ld /dev/mapper/d1024)
echo "asking for minor $min (d1024's):"
dmsetup info -j $maj -m $min | grep -E "Name|UUID|Major|Minor" 
dmsetup remove_all