ioctls that can throw without lock_config() panic the kernel: VINUM_MOVE onto a full/hot-spare drive is a one-ioctl panic
Summary
throw_rude_remark's bug-catcher panics unless VF_LOCKED is held, but VINUM_MOVE/ATTACH/DETACH/SETSTATE never call lock_config(); moveobject -> give_sd_to_drive's 'No space'/'hot spare' throws turn recoverable config errors into panic(). LIVE-REPRODUCED: two crafted drives, one VINUM_MOVE ioctl -> 'panic: throw_rude_remark: called without config lock' with full backtrace. Note: the 'hotspare' config keyword is dead - the string was never added to the keyword table. Wrap-with-lock_config fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4136 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| vinum_movepanic.c | β | 2.5 KB | view raw | |
| panic.txt | β | 1016 B | view raw | |
| serial_full.txt | β | 3.7 KB | view raw | |
| README.md | β | 2.3 KB | β raw | |
| verdict.json | β | 2.9 KB | view raw | |
| env.txt | β | 388 B | view raw |
DF-4136 β ioctls that can reach throw_rude_remark() without holding
the config lock panic the kernel (VINUM_MOVE demonstrated)
Root cause
throw_rude_remark() (vinumconfig.c:105-106) starts with a bug-catcher:
if ((vinum_conf.flags & VF_LOCKED) == 0) /* bug catcher */
panic ("throw_rude_remark: called without config lock");
VF_LOCKED is set only by lock_config() (vinumlock.c:227-238), which is
called by VINUM_CREATE (vinumioctl.c:103) β but not by
VINUM_SETSTATE/VINUM_SETSTATE_FORCE, VINUM_ATTACH, VINUM_DETACH,
VINUM_MOVE, or VINUM_PARITYOP, even though those code paths reach
functions that throw:
attachobject()(sdβplex) βgive_sd_to_plex()β "Can't add %s to %s: plex full" (vinumconfig.c:250-254);moveobject()βgive_sd_to_drive()β "Can't place %s on hot spare drive %s" (vinumconfig.c:318-322) or "No space for %s on %s" (vinumconfig.c:324-328, 373-381).
Any of those turns a routine, recoverable configuration error into
panic().
Reproduced trigger (VINUM_MOVE)
- two crafted vinum drives on vn devices:
*
x0β normal drive with subdisks0*x1β up drive with thehotspareflag VINUM_MOVE(_IOWR('F', 98, struct _ioctl_reply)) with{type = sd_object, index = driveno(x1), otherobject = sdno(s0)}.moveobject()βgive_sd_to_drive()β hotspare rejection βthrow_rude_remark()β panic "throw_rude_remark: called without config lock".
Expected panic text captured in panic.txt / serial log.
Impact
Immediate kernel panic (local DoS) by anyone with /dev/vinum/control
access (root:wheel 0600) β a mis-typed vinum move/vinum attach on a
full or hotspare drive takes the whole machine down instead of returning
an error.
Fix
Either wrap the affected ioctls with lock_config()/unlock_config()
(best: VINUM_MOVE, VINUM_ATTACH, VINUM_DETACH,
VINUM_SETSTATE(_FORCE)), or downgrade the bug-catcher panic to a
log(LOG_ERR,...) + error return. The lock wrapper matches the
VINUM_CREATE pattern:
--- a/sys/dev/raid/vinum/vinumioctl.c
+++ b/sys/dev/raid/vinum/vinumioctl.c
@@ -316,7 +316,11 @@
case VINUM_MOVE:
+ error = lock_config();
+ if (error)
+ break;
moveobject((struct vinum_ioctl_msg *) data); /* move an object */
+ unlock_config();
break;
Fix verification
not_testableNo fix built for this finding in this run (the validated fix kernel addressed DF-4132/4133); the panic was reproduced on that build. Proposed lock_config wrapper in README is untested.
panic.txt baseline.
Confirmed kernel references
Detail
Exploit chain
craft two vinum drives (x0 with sd s0 1MB; x1 up with a 1500kB filler so free space < 1MB) -> VINUM_MOVE {_IOC style _IOWR('F',98,struct _ioctl_reply)} with {index=driveno(x1), otherobject=sdno(s0), type=sd_object} -> moveobject -> give_sd_to_drive -> freelist search fails -> throw_rude_remark(ENOSPC,...) -> panic('throw_rude_remark: called without config lock') at vinumconfig.c:105.
Evidence (decisive lines)
panic.txt (panic message + full backtrace), serial_full.txt, vinum_movepanic.c, README.md
PoC changes
Went through several trigger variants: the 'hotspare' config keyword is dead (kw_hotspare exists but the string was never added to the keyword table), so the 'No space' route was used; config text had to use the kernel's space-separated grammar (name=x forms are userland-only).
Verified recommended fix
Take lock_config()/unlock_config() around the ioctls that can throw (VINUM_MOVE/ATTACH/DETACH/SETSTATE), or make the bug-catcher non-fatal.
Verdict
VINUM_MOVE reaches give_sd_to_drive() without lock_config(); when the move target drive has insufficient space the 'No space' error path calls throw_rude_remark(), whose bug-catcher panics because VF_LOCKED is not held. One ioctl from root panics the machine with the exact predicted backtrace: throw_rude_remark <- give_sd_to_drive <- moveobject <- vinumioctl <- dev_dioctl. Verified on the kernel rebuilt with the DF-4132/DF-4133 fixes (independent defect). Any routine, recoverable config error on the MOVE/ATTACH/DETACH/SETSTATE ioctl paths is a kernel panic instead of an error return.
No comments yet.