os_map_pci_bar(): unchecked bus_alloc_resource_any() failure β rman_get_virtual(NULL) NULL-deref panic at hptrr device attach (DF-5039 twin)
Summary
The BAR alloc is never NULL-checked before rman_get_virtual ((r)->r_virtual macro) - an unassignable BAR (reads 0, no resource-list entry) faults at VA 0x40 in attach; hptrr is compiled into GENERIC so an affected RocketRAID card panics every boot. VERIFIED on guest at source+harness fidelity: verbatim (rename-only) copy called against a real PCI device through the real newbus/rman stack - Fatal trap 12 at 0x40 exactly as production; guard A/B-validated in the same boot. Hardware-gated DoS ceiling.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5082 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.1 KB | β raw | |
| VERDICT.md | β | 4.9 KB | β raw | |
| df5082_harness.c | β | 6.7 KB | view raw | |
| build.sh | β | 156 B | view raw | |
| run.sh | β | 178 B | view raw | |
| build.log | β | 840 B | view raw | |
| run.log | β | 204 B | view raw | |
| run.2.log | β | 694 B | view raw | |
| panic.txt | β | 2.4 KB | view raw | |
| env.txt | β | 259 B | view raw | |
| fix.diff | β | 909 B | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 4.4 KB | view raw |
DF-5082 β os_map_pci_bar() unchecked bus_alloc_resource_any() β rman_get_virtual(NULL) NULL-deref panic at attach
sys/dev/raid/hptrr/hptrr_os_bsd.c:101-104 β DF-5039 twin (hpt27xx).
Reproduce
- Guest up with kernel source:
dfbsd-qemu/vm.sh up - Push + build:
scp -F dfbsd-qemu/config df5082_harness.c build.sh dfbsd:/root/dfbsd-qemu/vm.sh run_root 'sh /root/build.sh' - Load module, run the FIXED variant first, then the VERBATIM copy:
dfbsd-qemu/vm.sh run_root 'kldload /root/df5082/df5082.ko; sysctl df5082.trigger=2; sysctl df5082.trigger=1'
Expected
trigger=2: console/dmesg printsDF5082-fixed: ... guarded, no panic; guest survives.trigger=1: console showsFatal trap 12: page fault while in kernel mode,fault virtual address = 0x40,Stopped at ... movq 0x40(%rax),%rsi; the ssh call times out (RC=124), guest wedged atdb>.
0x40 is offsetof(struct resource, r_virtual) (sys/sys/rman.h:106) β
the fault address proves the read is the inlined rman_get_virtual(NULL)
from hptrr_os_bsd.c:104.
Full story: VERDICT.md. Fix: fix.diff (validated A/B in-harness).
DF-5082 β os_map_pci_bar() unchecked bus_alloc_resource_any() failure β rman_get_virtual(NULL) NULL-deref panic at device attach
sys/dev/raid/hptrr/hptrr_os_bsd.c:85-106 β twin of DF-5039 (hpt27xx_os_bsd.c).
Verdict: REPRODUCED (source+harness, on-guest) β impact: panic (probe/attach-time DoS, hardware-gated)
The defect
os_map_pci_bar() (hptrr_os_bsd.c:85-106) allocates a PCI BAR and never
checks the allocation result:
hba->pcibar[index].res = bus_alloc_resource_any(hba->pcidev, /* :101 */
hba->pcibar[index].type, &hba->pcibar[index].rid, RF_ACTIVE);
hba->pcibar[index].base = (char *)rman_get_virtual(hba->pcibar[index].res) + offset; /* :104 */
rman_get_virtual(r) is the macro ((r)->r_virtual) (sys/sys/rman.h:149);
offsetof(struct resource, r_virtual) == 0x40 on amd64
(sys/sys/rman.h:100-114: r_link 16 + r_sharelink 8 + r_sharehead 8 +
r_start 8 + r_end 8 + r_flags 4 + pad 4). When the BAR cannot be
allocated (unassigned BAR, resource conflict with another driver), the
result is a read of physical address 0x40 β Fatal trap 12 with the
machine dead in the hptrr attach path. hptrr is compiled into
X86_64_GENERIC (sys/config/X86_64_GENERIC:120), so the panic happens
at boot when a RocketRAID 17xx/2xxx card is present with an
unallocatable BAR β a persistent fail-to-boot.
When bus_alloc_resource_any() fails on DragonFly, concretely:
- unimplemented/unassigned BAR (register reads 0): pci_add_map()
returns early without resource_list_add() (sys/bus/pci/pci.c:2525,
the ln2size < 4 early return), so resource_list_alloc() takes its
!rle β return 0 path (sys/kern/subr_bus.c:2673);
- BAR whose range is already reserved non-shareable: rman_reserve_resource()
fails inside the same call chain.
Both funnel NULL into hptrr_os_bsd.c:104.
Reproduction (DF-4764 fidelity class: verbatim copy + real kernel APIs)
No RocketRAID 2xxx hardware exists on the audit guest, so β per the
accepted DF-4764/DF-4765 precedent β the trigger executes a verbatim
copy of hptrr_os_bsd.c:85-106 (rename-only) inside a KLD, with the
real HBA/pcibar types from <dev/raid/hptrr/os_bsd.h> (layout
proven by CTASSERT), against a real PCI device on the real newbus /
pci / rman stack: the first PCI child whose BAR register reads 0
(hostb0, rid 0x10) β the same !rle β NULL failure shape production
hits for an unassignable BAR.
Console (full capture in panic.txt):
DF5082: victim hostb0 rid 0x10 (BAR reads 0 -> bus_alloc_resource_any will fail) DF5082: calling VERBATIM os_map_pci_bar ... Fatal user address access from kernel mode from sysctl at ffffffff8260030e Fatal trap 12: page fault while in kernel mode fault virtual address = 0x40 fault code = supervisor read data, page not present Stopped at df5082_trigger+0x2de: movq 0x40(%rax),%rsi db>
- fault VA 0x40 =
offsetof(struct resource, r_virtual)β the signature ofrman_get_virtual(NULL), exactly as predicted; Stopped at ... movq 0x40(%rax),%rsiβ the inlined macro deref;- ssh run returned RC=124 (timeout) and the guest was wedged at the DDB prompt β the panic table's "guest dies" class.
Fix validation (A/B, same boot, same victim/rid)
The same harness carries the fix.diff-guarded variant. Run order in
one boot: df5082.trigger=2 (fixed) twice, then df5082.trigger=1
(verbatim):
- fixed (run.log / run.2.log):
DF5082-fixed: bus_alloc_resource_any(rid 0x10) returned NULL; guarded, no panicβ guest survived both; - verbatim (panic.txt): Fatal trap 12 at VA 0x40.
The guarded variant survived the identical NULL allocation that
killed the verbatim copy β baseline reproduced (1), patched reproduced
(0) β fix_status: fixed (in-harness A/B; a full kernel rebuild was not
performed because the in-tree attach path cannot be exercised without
HighPoint hardware β the guard itself is exercised exactly at the NULL).
Impact ceiling
Probe/attach-time kernel panic β persistent boot failure on a machine
whose RocketRAID card has an unallocatable BAR (unassigned BAR or I/O
conflict). Not reachable by an unprivileged local user; the trigger is
hardware presence. Severity Low, bucket base:dev β consistent with
DF-5039. The write is a fixed near-NULL read (0x40); no exploitation
path beyond denial of service.
Not re-reported here (pass-2 duplicate discipline)
- Shutdown-window timer UAF for hptrr: already filed as DF-4394
(hptrr_osm_bsd.c
hpt_shutdown_vbus); the arming site in this file isos_request_timer(hptrr_os_bsd.c:218-226).
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
fixedfix.diff guard validated in-harness A/B: same boot, same victim (hostb0, rid 0x10), same NULL allocation - fixed variant printed 'guarded, no panic' twice and the guest survived (run.log, run.2.log); the verbatim copy then panicked at VA 0x40 (panic.txt). Full-kernel rebuild validation not performed: the in-tree attach path requires HighPoint hardware; the guard is exercised exactly at the NULL allocation.
run.2.log (fixed variant survives, dmesg capture), panic.txt (baseline panic), fix.diff (the exact guard applied to df5082_os_map_pci_bar_fixed)
Confirmed kernel references
Detail
Evidence (decisive lines)
panic.txt: 'fault virtual address = 0x40' + 'Stopped at df5082_trigger+0x2de: movq 0x40(%rax),%rsi' (verbatim-copy panic); run.log + run.2.log: 'DF5082-fixed: bus_alloc_resource_any(rid 0x10) returned NULL; guarded, no panic' (fix A/B, same victim hostb0/rid 0x10); VERDICT.md: full trace hptrr_os_bsd.c:101->104, rman.h:149 macro, 0x40 offset derivation; build.log: clean KLD build with CTASSERT layout proofs
PoC changes
no seed; harness authored for this finding: verbatim copy of os_map_pci_bar renamed df5082_os_map_pci_bar_copy/fixed (static, avoids clash with the kernel-resident hptrr_os_map_pci_bar), real-header HBA via os_bsd.h (needed SRCS+= device_if.h bus_if.h pci_if.h and an empty opt_cam.h in the kmod Makefile), victim = first PCI child with a BAR reading 0
Verified recommended fix
NULL-check bus_alloc_resource_any() in os_map_pci_bar() and return 0 on failure; guard os_unmap_pci_bar() against res==NULL/base==0 entries (fix.diff)
Verdict
REPRODUCED at source+harness on the audit guest (DF-4764 fidelity class): a KLD carrying a VERBATIM copy of hptrr_os_bsd.c:85-106 (rename-only) with the REAL HBA/pcibar layout from
No comments yet.