Read-only GUI ioctls walk live array state with no driver lock while DELETE_ARRAY frees it - use-after-free race (panic or kernel-pointer copyout)
Summary
gui_lib.c is self-declared unsynchronized; its caller honors that only for the mutating ioctls - the whole read-only family is forwarded 'directly' with NO lock, and DELETE_ARRAY also runs unlocked. Two concurrent root sysctl writes race a GET_DEVICE_INFO walk (member derefs, VDEV_TO_ID copies) against array-table teardown -> UAF reads -> panic, or stale-slab bytes plus truncated kernel pointers copyout'd. Root-only race on HighPoint hardware. Serialize-the-read-family fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4332 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.6 KB | β raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| verdict.json | β | 2.3 KB | view raw | |
| manifest.json | β | 834 B | view raw | |
| env.txt | β | 363 B | view raw |
DF-4332 β hptmv read-only GUI ioctls walk array state with no driver lock (UAF race)
Files (walk sites under audit): sys/dev/raid/hptmv/gui_lib.c
* get_array_flag :163-197 (pMember[i] derefs)
* calc_rebuild_progress :208-224
* get_array_info/get_array_info_v2 :243-245, 265-267
* hpt_get_logical_devices :496 (while (pLogical->pParent) walk)
* dispatcher: hpt_default_ioctl :1134-1447
Race counterpart (out-of-file, root cause of the missing serialization):
sys/dev/raid/hptmv/ioctl.c:312-329 routes HPT_IOCTL_GET_ "directly" with
no lock_driver(), and HPT_IOCTL_DELETE_ARRAY
(ioctl.c:219-263 β hpt_delete_array β blob fDeleteArray) also never
takes the driver lock, while the mutating ioctls
(CREATE_ARRAY / SET_ / ADD_) do* run under lock_driver_idle (:357-371).
gui_lib.c's own header states the contract plainly
(gui_lib.c:36-37): "This implementation doesn't use any synchronization; the
caller must assure the proper context when calling these functions" β the
caller does not, for the whole read-only family and for DELETE_ARRAY.
Trigger (requires HighPoint RocketRAID 18xx hardware)
Two concurrent root sysctl writes to hw.hptmv.status
(hptproc.c:614-617, gated by SYSCAP_NOSYSCTL_WR, kern_sysctl.c:1446):
- thread A:
HPT_IOCTL_GET_DEVICE_INFO {id = array X}βget_array_infowalksX->u.array.pMember[0..bArnMember-1]and copiesVDEV_TO_ID(pMember)/ArrayName/ flags to userspace; - thread B:
HPT_IOCTL_DELETE_ARRAY {id = X}βfDeleteArrayfrees X's member array tables (mArFreeArrayTable, cf. the mirrored free ingui_lib.c:802-809) and stamps.
Thread A then dereferences freed PVDevices: UAF read β panic, or β if the
freed slab is untouched β copies kernel heap pointers
(VDEV_TO_ID = truncated PVDevice) and stale slab contents out via
hptproc.c:315.
Guest status β NOT REPRODUCIBLE HERE
The audit guest has no HighPoint/Marvell PCI device:
# pciconf -l | grep -icE "11ab|hpt" 0 # sysctl -n hw.hptmv.status sysctl: unknown oid 'hw.hptmv.status' # hpt_status OID registered from attach
With gIal_Adapter == NULL the ioctl path NULL-derefs before reaching
gui_lib.c (already known: DF-1853). Verdict: inconclusive β hardware
absent; the race is established by code inspection only.
Fix direction (not validated on this guest)
Serialize the read-only dispatch group and DELETE_ARRAY under the same
lock_driver()/lock_driver_idle(pAdapter) regime as the mutating ioctls
(one-line summary; a reviewed patch needs care: GET_* currently run lock-free
by design comment ioctl.c:316).
DF-4332 β VERDICT
Status: inconclusive (hardware absent). Confidence in the code defect: likely.
Why inconclusive
The race requires (a) a HighPoint RocketRAID 18xx controller attached
(gIal_Adapter != NULL), (b) at least one configured array, and (c) two
concurrent privileged sysctl writes. The audit guest (QEMU, stock X86_64_GENERIC)
has no such device β pciconf -l shows zero 11AB devices and the
hw.hptmv.status OID is not even registered (it is created from the attach
path via xhptregister_node, hptproc.c:612-619 + entry.c:98). Without an
adapter the ioctl entry NULL-derefs long before gui_lib.c is reached β that
crash is the already-known DF-1853 and is deliberately NOT reproduced here.
Code trace establishing the defect
hptproc.c:614-617registershw.hptmv.statusRW; writes requireSYSCAP_NOSYSCTL_WR(sys/kern/kern_sysctl.c:1446-1447) β root-only surface, consistent with DF-1529/1530/1531's threat model.hptproc.c:309-311callsKernel_DeviceIoControlper write, with no serialization between two concurrent writers.ioctl.c:312-329: the read-only family (GET_CHANNEL_INFO / GET_LOGICAL_DEVICES / GET_DEVICE_INFO[_V2] / β¦) is forwarded tohpt_default_ioctldirectly β the comment at:316says "read-only ioctl functions can be called directly" β i.e. without thelock_driver_idle()that the mutating group gets at:357-371.ioctl.c:219-263(HPT_IOCTL_DELETE_ARRAY) βhpt_delete_array(:156-186) β blobfDeleteArrayβ also no lock held.gui_lib.c:36-37documents that gui_lib itself has zero synchronization. Its read paths dereference live structures freely:hpt_get_device_info:512-534(mIsArrayβget_array_info:230-249),get_array_flag:163-197(pMember[i]derefs guarded only by NULL check),calc_rebuild_progress:208-224,hpt_get_logical_devices:496(while (pLogical->pParent)unbounded parent walk).fDeleteArray(blob,ioctl.c:183) tears down array tables (mArFreeArrayTable, the free pattern visible atgui_lib.c:802-809) β concurrent step 5 walks are then UAF reads.
Impact ceiling: kernel UAF read β panic (DoS), or limited kernel-heap info
leak β get_array_info copies VDEV_TO_ID(pMember) (kernel addresses) and
ArrayName bytes from freed/reused slab to the caller
(hptproc.c:315 copyout). Root-triggerable from both sides; race window is a
single ioctl. Severity Low.
What would falsify or confirm it
Confirm: two threads looping GET_DEVICE_INFO vs DELETE_ARRAY on a real 182x
with one mirror array; expect panic in get_array_flag/get_array_info or
pIds[] values leaking heap pointers after free. Falsify: if the blob's
fDeleteArray defers all frees via DPC-to-completion under the caller's lock
(it takes none, so unlikely), the race would be only against rebuild state,
not lifetime.
Fix direction
Hold the driver lock across the read-only dispatch group and DELETE_ARRAY
(mirroring ioctl.c:357-371), or refcount PVDevice lifetime for the GET_*
walks. Not validated on this guest (no hardware); no fix.diff shipped.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
(No fix.diff for this item: documented recommendation only - see Fix above.)
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md full path:line trace; env.txt: pciconf grep count 0 and 'sysctl: unknown oid hw.hptmv.status'
PoC changes
no runnable PoC possible without the HBA; evidence is the code trace plus guest hardware-absence capture
Verified recommended fix
Serialize the read-only ioctl group and DELETE_ARRAY under lock_driver()/lock_driver_idle like the mutating ioctls (ioctl.c:357-371)
Verdict
INCONCLUSIVE - hardware absent. The unlocked-walk defect is established by inspection: ioctl.c:316-329 dispatches the entire read-only GUI ioctl family to hpt_default_ioctl with no driver lock and ioctl.c:219-263 (DELETE_ARRAY) frees array/member tables equally unlocked, while gui_lib.c (self-declared unsynchronized, header lines 36-37) dereferences pMember[]/pParent chains in get_array_flag/calc_rebuild_progress/get_array_info/hpt_get_logical_devices. Concurrent root sysctl writes then race a GET_DEVICE_INFO walk against array teardown -> UAF read -> panic or kernel-pointer copyout. The guest has no HighPoint controller (pciconf: 0 devices; hw.hptmv.status OID absent - registered from attach), and without one the path NULL-derefs before gui_lib.c (known DF-1853). Root-only both sides, narrow window: Low.
No comments yet.