ata_marvell_edma_allocate() dereferences ch->dma unconditionally (work_bus/work/work_tag): NULL-pointer panic when ata_dmaalloc() failed at channel attach β DF-4809 class, but in ->allocate (marvell is the only nata chipset whose allocate touches ch->dma)
Summary
ata_dmaalloc failure NULLs ch->dma (the framework supports PIO-only channels) but ata_pcichannel_attach calls ctlr->allocate unconditionally - marvell's EDMA allocate immediately reads ch->dma->work_bus. Attach-time NULL panic on 88SX EDMA under DMA allocation failure; live code (#included into natapci). No 88SX under QEMU - complete line-trace proof + fix compile-validated on guest (natapci.ko -Werror clean). Guard fix (DF-4809 methodology).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4813 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.4 KB | β raw | |
| VERDICT.md | β | 4.3 KB | β raw | |
| verdict.json | β | 3.2 KB | view raw | |
| fix.diff | β | 381 B | view raw | |
| fix_build.log | β | 9.9 KB | view raw |
DF-4813 β nata ata-marvell (EDMA): ata_marvell_edma_allocate() dereferences ch->dma unconditionally β NULL-pointer panic when ata_dmaalloc() failed at channel attach (DF-4809 class, in ->allocate instead of ->reset).
No runnable trigger exists on the audit guest (QEMU has no 88SX emulation and the PCI device cannot be faked the way an ACPI table can), so this pack holds the complete static proof plus a compile-validation of the fix, mirroring the accepted DF-4809 methodology.
Contents
VERDICT.md full path:line trace: ata-pci.c:795-798 (unconditional
ctlr->allocate after ch->dma may be NULL) -> ata-dma.c:149-153
(ata_dmaalloc failure NULLs ch->dma) -> ata-marvell.c:209
(work = ch->dma->work_bus;).
fix.diff 2-line guard (if (ch->dma == NULL) return ENXIO;)
fix_build.log natapci.ko rebuilt clean (-Werror) on the audit guest with
the guard applied: build_rc=0.
Build (fix compile-validation, on the guest)
cd /usr/src && patch -p1 < fix.diff cd /usr/src/sys/dev/disk/nata/natapci && make obj && make
Expected
Static: on any 88SX50xx/60xx/6042/7042 EDMA system whose channel attach hits an ata_dmaalloc() failure, the unpatched driver panics in ata_marvell_edma_allocate (ch->dma == NULL); with the guard the channel attach fails cleanly with ENXIO (handled at ata-pci.c:798-801).
DF-4813 β VERDICT
Status: NOT DYNAMICALLY TESTABLE on the audit guest (no Marvell 88SX PCI device exists under QEMU). Static proof is complete and unambiguous: same class as the accepted DF-4809 (ata-ahci).
Root cause β full path trace
ata_marvell_edma_allocate() dereferences ch->dma without a NULL check,
while its only caller invokes it after the DMA setup may have failed and
NULLed ch->dma:
ata_pcichannel_attach()β sys/dev/disk/nata/ata-pci.c:787-805:c 793 if (ctlr->dmainit) 794 ctlr->dmainit(dev); /* ata_marvell_edma_dmainit -> ata_dmainit: ch->dma = kmalloc(...M_INTWAIT) */ 795 if (ch->dma) 796 ch->dma->alloc(dev); /* ata_dmaalloc β CAN FAIL */ 797 798 if ((error = ctlr->allocate(dev))) { /* called UNCONDITIONALLY */ 799 if (ch->dma) 800 ch->dma->free(dev); 801 return error; 802 }ata_dmaalloc()β sys/dev/disk/nata/ata-dma.c:91-154: any of the fivebus_dma_tag_createcalls, eitherbus_dmamem_alloc(SG table page / 8 KB work area), eitherbus_dmamap_load, orbus_dmamap_createfailing prints "WARNING - DMA allocation failed, disabling DMA" and executesc 152 kfree(ch->dma, M_ATADMA); 153 ch->dma = NULL;The channel attach then continues (the framework explicitly supports PIO-only operation β that is why 795/799 guard withif (ch->dma)).ata_marvell_edma_allocate()β sys/dev/disk/nata/chipsets/ata-marvell.c:c 209 work = ch->dma->work_bus; <-- NULL deref (panic #1) 211 bzero(ch->dma->work, 1024+256); 212 bus_dmamap_sync(ch->dma->work_tag, ch->dma->work_map, ...);Every otherch->dmaconsumer in the framework guards withif (ch->dma)(ata-pci.c:795, 799, 816, 843);ata_marvell_pata_allocate(the 61xx PATA path) correctly goes throughata_pci_allocatewhich never touchesch->dma. Among ALL nata chipsets, marvell-edma is the only->allocateimplementation that dereferencesch->dma(ahci's allocate β ata-ahci.c: 159-182 β does not; its deref lived inreset, filed as DF-4809).
Reachability: the marvell EDMA glue is compiled into the live natapci
module / GENERIC kernel (ata-chipset.c:159-160, `#if !defined(ATA_NO_MARVELL)
include "chipsets/ata-marvell.c"`), for all 50xx/60xx/6042/7042 EDMA parts
(ata-marvell.c:75-82).
Trigger: attach of an 88SX EDMA channel (boot-time enumeration or later module load / hot-plug) at a moment when the DMA allocations of step 2 fail (DMA-coherent memory fragmentation, dma-window constraints). Result: NULL-pointer-write/panic in the device attach path -> boot or kldload DoS (CWE-476). No attacker-controlled data; not an unprivileged primitive β the precondition is an environmental allocation failure.
Why not reproduced on the guest
QEMU cannot present an 88SX PCI storage controller (no emulation exists, and
unlike the ACPI case of DF-4812 the PCI ID/behavior cannot be injected with
-acpitable), and forcing ata_dmaalloc() failure requires the real device
attach to run. Verification therefore mirrors the accepted DF-4809
methodology: line-precise static trace of the full call chain (above), plus a
compile-validation of the fix on the audit guest:
# cd /usr/src && patch -p1 < fix.diff # cd /usr/src/sys/dev/disk/nata/natapci && make obj && make [see fix_build.log]
Fix
Guard at the top of ata_marvell_edma_allocate (fix.diff, build-validated):
+ if (ch->dma == NULL)
+ return ENXIO;
+
work = ch->dma->work_bus;
The channel then fails attach cleanly; ata_pcichannel_attach already
handles the error (ata-pci.c:798-801).
Classification
- severity: Low (attach-time NULL-deref panic, environmental trigger; matches DF-4809)
- CWE-476 (NULL Pointer Dereference)
- bucket: base:dev
- kernel_refs: chipsets/ata-marvell.c:209, chipsets/ata-marvell.c:211-213, ata-pci.c:795-798, ata-dma.c:149-153
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_testablefix.diff adds the same 'if (ch->dma == NULL) return ENXIO;' guard the framework itself uses; compile-validated on the audit guest (natapci.ko rebuilt clean with -Werror). Behavioral validation impossible on QEMU: no 88SX device, and ata_dmaalloc failure cannot be produced without the real attach.
findings/poc/DF-4813/fix.diff; findings/poc/DF-4813/fix_build.log
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-4813/VERDICT.md (full path:line trace); findings/poc/DF-4813/fix.diff; findings/poc/DF-4813/fix_build.log (clean -Werror module build with the guard)
PoC changes
not applicable (no seed PoC; pass-2 static finding; dynamic trigger requires physical 88SX hardware)
Verified recommended fix
Guard ata_marvell_edma_allocate with 'if (ch->dma == NULL) return ENXIO;' before the first ch->dma dereference (ata-marvell.c:209)
Verdict
Static NULL-deref with complete path proof, not guest-runnable (no Marvell 88SX device exists under QEMU and a PCI storage controller cannot be injected like an ACPI table): ata_dmaalloc() failure leaves ch->dma == NULL (ata-dma.c:152-153) but channel attach continues (framework supports PIO-only, guarding every other ch->dma use at ata-pci.c:795/799/816/843); ata_pcichannel_attach then calls ctlr->allocate(dev) UNCONDITIONALLY (ata-pci.c:798) and ata_marvell_edma_allocate immediately dereferences ch->dma->work_bus (ata-marvell.c:209) and ch->dma->work/work_tag/work_map (211-213) -> attach/boot-time kernel panic (CWE-476) under DMA-coherent memory exhaustion on any 88SX50xx/60xx/6042/7042 EDMA system. Marvell is the only nata chipset whose ->allocate derefs ch->dma (ahci's allocate does not β its deref was in reset, DF-4809). Fix compile-validated on the audit guest: guard applied, natapci.ko rebuilt clean with -Werror (fix_build.log, build_rc=0).
No comments yet.