mv family queue-pointer registers used unmasked: device-fed outbound_tail/inbound_head index inbound_q/outbound_q[512] MMIO β OOB bus-space read and 8-byte OOB MMIO write up to ~32GB past BAR2
Summary
The mv out/inbound helpers use the device registers unmasked as queue-array MMIO offsets; arrays are 512 entries; wrap checks occur only after use. A device value >=512 steers OOB MMIO access - machine-check/panic or neighbouring-BAR corruption. Distinct from DF-1312 (srb[] index); these are the queue-pointer registers themselves. Mask-at-read fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3963 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.3 KB | β raw | |
| VERDICT.md | β | 1.6 KB | β raw | |
| trigger.c | β | 2.0 KB | view raw | |
| build.sh | β | 67 B | view raw | |
| run.sh | β | 91 B | view raw | |
| run.log | β | 12 B | view raw | |
| env.txt | β | 1021 B | view raw | |
| fix.diff | β | 907 B | view raw | |
| build.log | β | 7.1 KB | view raw | |
| manifest.json | β | 370 B | view raw | |
| verdict.json | β | 3.1 KB | view raw |
DF-3963 β mv queue-pointer registers trusted raw: device-fed OOB MMIO read and write off the 512-entry queue arrays
File: sys/dev/raid/hptiop/hptiop.c (pass 2; knowns excluded β DF-1312 covers
the hba->srb[] index, not these queue-pointer registers)
What
hptiop_mv_outbound_read (229β250) reads the device register outbound_tail
and uses it unmasked as the index outbound_q[outbound_tail] β an MMIO read
at BAR2+0x1040+8tail. hptiop_mv_inbound_write (252β265) likewise writes 8
host-chosen bytes at BAR2+0x40+8inbound_head, unmasked. The arrays are 512
entries (MVIOP_QUEUE_LEN, hptiop.h:96β107). A device value β₯ 512 (or a
device-DMA attacker flipping the register) steers the access up to ~32 GB past
BAR2. Host RAM is not behind the BAR, so impact is machine-check/panic
(unmapped MMIO) or corruption of a neighbouring mapped BAR β a device-fed DoS
/MMIO-corruption primitive. Complements DF-1312 (which is the srb[] index fed
from the popped queue values); these are the queue pointer registers
themselves.
Build / Run
Hardware-gated (mv-family RR3020/3120 HBA required; guest has none β env.txt).
Expected
Fatal trap / machine check on the OOB MMIO access, or silent corruption of an adjacent device's register file.
DF-3963 verdict β certain source gap, device-fed, Low impact on host memory
Reproduced?
No: no mv-family HighPoint HBA on the guest (env.txt).
Analysis (path:line)
- hptiop.c:232 β
outbound_tail = BUS_SPACE_RD4_MV2(outbound_tail)device register; :236-239 uses it unmasked asoutbound_q[outbound_tail]offset (BAR2 + 0x1040 + 8*tail) forbus_space_read_region_4(..., 2). - hptiop.c:254 β
inbound_head = BUS_SPACE_RD4_MV2(inbound_head); :260-262 writes 8 bytes ofp(host phys addr | MVIOP flags) atinbound_q[inbound_head](BAR2 + 0x40 + 8*head), unmasked. - Wrap checks (:243, :257) happen only AFTER use and only for the +1 value β the device-provided base is never bounded by MVIOP_QUEUE_LEN (512, hptiop.h:96; arrays at hptiop.h:105-106).
- Both call sites run on the I/O path (
hptiop_drain_outbound_queue_mv:722-733,hptiop_post_*mv writes) β reachable from ordinary I/O once the register is bad.
Why Low
The corrupted window is PCI MMIO space, not host RAM: realistic outcomes are a bus error/panic (DoS) or clobbering another device's registers. Same device-trust threat model as DF-1312 (rated Low). Fix is a two-line mask.
Fix
fix.diff masks both device-fed pointers with & (MVIOP_QUEUE_LEN - 1).
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_testableTwo-line mask keeps all accesses inside the 512-entry arrays; git apply --check clean. Runtime validation impossible without the HBA fix.diff applied to the guest /usr/src copy and the hptiop.ko module rebuilt clean with -Werror (build.log; combined with the other four hptiop fix.diffs of this batch); runtime validation still impossible without the HBA.
fix.diff; fix.diff applied to the guest /usr/src copy and the hptiop.ko module rebuilt clean with -Werror (build.log; combined with the other four hptiop fix.diffs of this batch); runtime validation still impossible without the HBA.
Confirmed kernel references
Detail
Exploit chain
wedge/emulated mv HBA sets inbound_head=0x400 -> next hptiop_mv_inbound_write posts 8 bytes at BAR2+0x40+0x2000 (outside the 4KB queue window) -> unmapped-MMIO machine check (panic/DoS) or corruption of an adjacent mapped BAR; symmetric OOB read path via outbound_tail in the interrupt drain.
Evidence (decisive lines)
VERDICT.md (offset math + path:line), trigger.c, env.txt, fix.diff (mask both registers, git apply --check clean)
PoC changes
Informational trigger only; hardware-gated.
Verified recommended fix
Mask device-fed queue pointers: & (MVIOP_QUEUE_LEN - 1) in hptiop_mv_outbound_read/hptiop_mv_inbound_write (fix.diff).
Verdict
Source-certain device-fed OOB bus-space access: hptiop_mv_outbound_read (hptiop.c:232,236-239) and hptiop_mv_inbound_write (:254,260-262) use the device-maintained outbound_tail / inbound_head registers unmasked as indices into the 512-entry inbound_q/outbound_q arrays (hptiop.h:96-107); a value >=512 steers an MMIO read (and an 8-byte MMIO WRITE of a host phys|flags value) up to ~32GB past BAR2. Impact bounded to MMIO space (machine-check/panic or neighbouring-BAR corruption), not host RAM -> Low, same device-trust class as the known DF-1312 (which covers the srb[] index, not the queue-pointer registers). Not reproduced: no mv-family HBA on the guest (env.txt).
No comments yet.