# 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

1. `hptproc.c:614-617` registers `hw.hptmv.status` RW; writes require
   `SYSCAP_NOSYSCTL_WR` (`sys/kern/kern_sysctl.c:1446-1447`) → root-only
   surface, consistent with DF-1529/1530/1531's threat model.
2. `hptproc.c:309-311` calls `Kernel_DeviceIoControl` per write, with **no
   serialization between two concurrent writers**.
3. `ioctl.c:312-329`: the read-only family
   (GET_CHANNEL_INFO / GET_LOGICAL_DEVICES / GET_DEVICE_INFO[_V2] / …) is
   forwarded to `hpt_default_ioctl` **directly** — the comment at `:316` says
   "read-only ioctl functions can be called directly" — i.e. without the
   `lock_driver_idle()` that the mutating group gets at `:357-371`.
4. `ioctl.c:219-263` (HPT_IOCTL_DELETE_ARRAY) → `hpt_delete_array`
   (`:156-186`) → blob `fDeleteArray` — also **no lock held**.
5. `gui_lib.c:36-37` documents 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).
6. `fDeleteArray` (blob, `ioctl.c:183`) tears down array tables
   (`mArFreeArrayTable`, the free pattern visible at `gui_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.)
