format_config() OOB heap read: vinum_conf.plex[sd->plexno] with plexno==-1 for detached subdisks persists heap bytes into the on-disk config
Summary
The subdisk branch unconditionally prints plex[sd->plexno].name; a detached subdisk keeps plexno==-1, so plex[-1].name reads one struct before the dynamically allocated array and the %s copies OOB heap bytes into the config text written to every vinum drive. Direct trigger needs root, but the same code runs when a crafted vinum disk's config is restored by scandisk (the DF-1732/1733 media surface). REPRODUCED on guest (crafted FS_VINUM partition + detached sd: hexdump shows OOB bytes in the persisted config; value tracks the plex[] allocation). Patched module validated (detached sds print no plex token). Guard-plexno>=0 fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4592 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| run.log | β | 4.1 KB | view raw | |
| run.patched.log | β | 4.2 KB | view raw | |
| leak_sample.txt | β | 967 B | view raw | |
| fix.diff | β | 1.1 KB | view raw | |
| fix.combined.diff | β | 1.8 KB | view raw | |
| label.bin | β | 512 B | β download | |
| run.sh | β | 158 B | view raw | |
| build.sh | β | 178 B | view raw | |
| env.txt | β | 291 B | view raw |
Fix verification
fixedPatched module (fix.diff applied to /usr/src, rebuilt vinum.ko, rebooted, identical run.sh): the plex-name field and its OOB byte are gone from the detached-sd line; baseline stock module shows the garbage byte in the same run.
run.log vs run.patched.log, 'DF-4592 evidence' sections; module md5 c25e05df61176fed080646a67ef6a41c (patched) vs a0152b6fbfd886fe8c0783d3b608aa97 (stock rebuild)
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log 'DF-4592 evidence' section (hexdump shows 31 20 70 6c 65 78 20 <OOB byte> 20 6c 65 6e = '1 plex <XX> len'); run.patched.log same section shows clean 'sd name det1 drive d1 len 2048s ... detached'; leak_sample.txt collects both observed bytes; fix.diff is the validated hunk
PoC changes
No seed PoC existed. Wrote the full harness: crafted disklabel32 (fstype 14) injected into the guest's md0 malloc disk to satisfy vinum's DIOCGPART fstype check, vinum(8) command files, sector-aligned dd dumps of the config area (bs=1 I/O is rejected by md), and hexdump extraction of the exact leaked byte.
Verified recommended fix
In format_config(), only print the 'plex %s' field when sd->plexno >= 0 (see fix.diff); detached sds keep the existing 'detached' suffix.
Verdict
Reproduced on the guest: creating a detached subdisk (sd name det1 drive d1 len 1m detached) makes format_config() print vinum_conf.plex[-1].name (vinumio.c:522, plexno==-1 per vinumconfig.c:1259); the leaked out-of-bounds heap byte (observed 0x01 and 0x20 in different runs, changing when the plex[] array was reallocated) is persisted into the on-disk vinum config area of every drive. Root-triggerable directly, and also reachable from a crafted vinum disk (detached sd config line parsed by vinum_scandisk). Fix validated: with fix.diff the detached-sd config line omits the plex token entirely and no OOB byte appears; round-trip parse preserved via the existing 'detached' keyword.
No comments yet.