hptmv_event_notify uses closed-blob param2 as MV_U8 channel index into sataEvents[8]/VDevices[8] with no bounds check (hardening)
Summary
The MV core callback truncates MV_U32 param2 to MV_U8 and indexes sataEvents[8] and VDevices[8] without a range check; the only caller is the precompiled raid.o blob, so the value's discipline is unverifiable - the guard belongs in the open-source glue. If the closed core ever emits param2 >= 8 or a truncation mismatch, a 4-byte enum write lands mid-struct and VDevices[] is read out of bounds. One-line guard fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3925 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.0 KB | β raw | |
| VERDICT.md | β | 1.3 KB | β raw | |
| fix.diff | β | 379 B | view raw | |
| env.txt | β | 1.2 KB | view raw | |
| manifest.json | β | 774 B | view raw | |
| verdict.json | β | 1.6 KB | view raw |
DF-3925 β hptmv_event_notify trusts the closed-source MV core's param2 as a channel index with no bounds check
What
sys/dev/raid/hptmv/entry.c:850-901:
static MV_BOOLEAN
hptmv_event_notify(MV_SATA_ADAPTER *pMvSataAdapter, MV_EVENT_TYPE eventType,
MV_U32 param1, MV_U32 param2)
{
...
case MV_EVENT_TYPE_SATA_CABLE:
{
MV_U8 channel = param2; /* :860 β 32->8 truncation, no range check */
if (param1 == EVENT_CONNECT) {
pAdapter->sataEvents[channel] = SATA_EVENT_CHANNEL_CONNECTED; /* :864 */
...
else if (param1 == EVENT_DISCONNECT) {
pAdapter->sataEvents[channel] = SATA_EVENT_CHANNEL_DISCONNECTED;/* :872 */
device_change(pAdapter, channel, FALSE); /* :875 -> VDevices[channel] */
IAL_ADAPTER_T.sataEvents[MV_SATA_CHANNELS_NUM=8] and
.VDevices[MV_SATA_CHANNELS_NUM=8] (osbsd.h:170,176; mvSata.h:83). A param2
= 8 (or a truncation mismatch) writes an enum 4 bytes past
sataEvents[]into the middle of the adapter struct, anddevice_changeindexesVDevices[channel]OOB β out-of-struct PVDevice pointer use β memory corruption.
Provenance (why this is only speculative)
hptmv_event_notify is called only by the precompiled MV core library
(x86_64-elf.raid.o.uu, linked via Makefile hptmvraid.bo) β there is no
source for the caller in-tree. The historical FreeBSD mvSata core generates
MV_EVENT_TYPE_SATA_CABLE with channelIdx from loops bounded by
MV_SATA_CHANNELS_NUM, so on well-behaved core code param2 β [0,7]. But the
check belongs in the open-source glue: this is defense-in-depth against a
closed blob whose bounds discipline cannot be audited (and whose input is
device-controlled MMIO state).
Fix
--- a/sys/dev/raid/hptmv/entry.c
+++ b/sys/dev/raid/hptmv/entry.c
@@ -857,6 +857,9 @@ hptmv_event_notify(...)
{
MV_U8 channel = param2;
+ if (channel >= MV_SATA_CHANNELS_NUM)
+ return MV_FALSE;
+
if (param1 == EVENT_CONNECT)
(see fix.diff)
DF-3925 VERDICT
status: not_reproduced (hardware-gated, caller unauditable) | impact observed: none | source certainty: speculative
Analysis
- Sink: entry.c:864/872 write
sataEvents[channel](8-entry array, osbsd.h:170) and entry.c:875device_change(...VDevices[channel]...)(8-entry array, osbsd.h:176), withchannel = (MV_U8)param2taken from the callback args with no range validation (entry.c:860). - Source: the only caller is inside the closed binary blob x86_64-elf.raid.o.uu (mvSata core). No in-tree call site can be checked; the historical open mvSata core bounded channelIdx by MV_SATA_CHANNELS_NUM.
- Therefore the OOB is reachable only if the blob ever emits param2 >= 8 or a truncation mismatch β unverifiable. Filed as a hardening finding (speculative), not a demonstrated bug. Runtime reproduction additionally requires the RR1820 card (absent, env.txt).
Fix validation
Hardware-gated; one-line guard, no behavior change for valid channels.
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.
Fix verification
not_testableone-line guard authored in fix.diff; cannot validate without hardware
fix.diff in this pack; never applied to sys/
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md provenance analysis; Makefile links hptmvraid.bo from x86_64-elf.raid.o.uu (closed)
PoC changes
n/a (fresh pack)
Verified recommended fix
Validate channel < MV_SATA_CHANNELS_NUM at the top of the MV_EVENT_TYPE_SATA_CABLE case
Verdict
entry.c:860 truncates the MV core callback's MV_U32 param2 to MV_U8 and uses it unvalidated to index sataEvents[8] (:864/:872) and VDevices[8] (:875). The only caller is the precompiled mvSata core blob (x86_64-elf.raid.o.uu) whose param2 discipline cannot be audited from source; the historical core bounded it to [0,7]. Filed as speculative hardening: add a range guard in the open glue. No runtime test possible (no RR1820 on guest).
No comments yet.