DF-5062 / verdict.json
{ "finding_id": "DF-5062", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "made_vol() (sys/dev/raid/vinum/vinumconfig.c:763) creates /dev/vinum/vol/<name> with VINUMDEV(volno,0,0,VINUM_VOLUME_TYPE) and no range check, while get_empty_volume() grows VOL[] without limit; VINUM_VOL_WIDTH is 8 bits, so volume #256 gets minor 0x100 which Volno() (vinumutil.c:241) decodes as volno 0. Kernel minor() returns the raw si_uminor (kern_conf.c:70-75), so open/read/write/ioctl on /dev/vinum/vol/v256 are all served by VOL[0] -- a different volume. Reproduced deterministically on the stock-module guest: diskinfo(/dev/vinum/vol/v256) returned v0s exact 4.00 MB size for a zero-plex volume, and a BBBB marker written through v256 read back through /dev/vinum/vol/v0 (run.log, run.2.log). Deterministic cross-volume data corruption + wrong-object DIOCGPART sizing from ordinary root vinum configuration; every 256th volume aliases onto VOL[0]. Root-gated like the rest of the vinum family. Fix validated on a rebuilt vinum.ko: v256 gets no device node (log line + ENOENT), v0 I/O intact.", "exploit_chain": "root: vinum create -f (257 volumes) -> /dev/vinum/vol/v256 (minor 0x100) aliases VOL[0] -> all I/O through the v256 node silently reads/writes volume v0s storage: filesystem/swap corruption of the wrong volume (data-integrity attack, not kernel-memory corruption)", "evidence": "run.log: 257 volumes:, ls -l v256 rdev 255,0xffff00ff, diskinfo v256 size=0x400000 4.00 MB; run.2.log: od dump showing BBBB-v256-ALIAS written via v256 read back via v0; fix_run.log/fix_run2.log: patched module logs volume number 256 does not fit in the 8-bit device minor, v256 ENOENT, v0 positive control intact", "kernel_refs": [ "sys/dev/raid/vinum/vinumconfig.c:759-774", "sys/dev/raid/vinum/vinumconfig.c:875-899", "sys/dev/raid/vinum/vinumutil.c:238-242", "sys/dev/raid/vinum/vinumvar.h:83-86", "sys/dev/raid/vinum/vinumvar.h:113-116", "sys/kern/kern_conf.c:70-75", "sys/kern/kern_conf.c:154-160" ], "poc_changes": "wrote df5062_volalias.sh from scratch (no seed): vn0 vnode disk + vinum label (label.bin from the DF-4592 pack) since the guest has no mdconfig(8); first attempt used mdconfig (absent) so the drive failed and v0 stayed down (all EIO) -- switched to vnconfig(8), added vinum start v0 and conv=sync dd markers with od readback", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 190, "guest_dirty": 0, "build_cmd": "(none -- shell PoC; fix build: cd /usr/src/sys/dev/raid/vinum && make after applying fix.diff, rc=0)", "run_cmd": "kldload vinum; sh /tmp/df5062_volalias.sh; sh /tmp/alias2.sh", "code_hash": "3cd90fcb9808592b99f34f75a4ed6529ef60f2b6d3cea87bbf719289f9aad6b8", "notes": "makeudev() rejects minor 0x100 as NOUDEV, so stat() shows the bogus rdev 255,0xffff00ff -- cosmetic, the open path still executes with si_uminor=0x100. Volume #512 aliases VOL[0] again (0x200), etc. Guest reset clean after the run.", "recommended_fix": "made_vol(): refuse to make_dev a volume whose number does not fit in VINUM_VOL_WIDTH bits (log + return); see fix.diff", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "vinum.ko rebuilt from patched /usr/src in the guest (make rc=0), installed, rebooted, exact PoC re-run: kernel logs vinum: volume v256: volume number 256 does not fit in the 8-bit device minor; no device node created, /dev/vinum/vol/v256 is absent (write -> ENOENT, diskinfo -> No such file), and the positive control /dev/vinum/vol/v0 still reads/writes its own data. Aliasing gone; fix_build.log/fix_run.log/fix_run2.log.", "fix_evidence": "findings/poc/DF-5062/fix_run.log (patched log line + missing node + v0 4.00 MB control); fix_run2.log (AAAA survives, BBBB write via v256 -> ENOENT); fix_build.log (clean rebuild); fix.diff in the same pack" } |