mxge_dma_test divides by the firmware-returned tick count with no zero check: kernel divide-by-zero panic at attach, at every open, and inside watchdog recovery
Summary
All three DMA-benchmark computations divide by (cmd.data0 & 0xffff) - the device-written 0.5us tick half of the MXGEFW_DMA_TEST result - with no zero guard. A device answering with repetitions<<16|0 executes an integer division by zero in kernel context -> #DE panic. Reachable from mxge_reset (attach and every mxge_open) and mxge_firmware_probe - including the watchdog-recovery path, so a flaky NIC panics the host precisely during recovery. Zero-guard fix git-apply-clean.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3721 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| VERDICT.md | β | 1.0 KB | β raw | |
| fix.diff | β | 918 B | view raw | |
| verdict.json | β | 1.9 KB | view raw | |
| manifest.json | β | 744 B | view raw | |
| env.txt | β | 583 B | view raw |
DF-3721 β mxge_dma_test divides by a firmware-returned counter with no zero check: kernel #DE panic at attach / watchdog recovery
Vulnerability
sys/dev/netif/mxge/if_mxge.c mxge_dma_test() (:430-488) computes DMA
benchmark numbers from the firmware command response:
sc->read_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); /* :459 */
sc->write_dma = ((cmd.data0>>16) * len * 2) / (cmd.data0 & 0xffff); /* :469 */
sc->read_write_dma= ((cmd.data0>>16) * len * 2 * 2) / (cmd.data0 & 0xffff); /* :479 */
cmd.data0 is the device-written result register
(MXGEFW_DMA_TEST/UNALIGNED_TEST: upper 16 bits repetitions, lower 16
bits 0.5 Β΅s ticks β mxge_mcp.h). The lower half is the divisor and is
never checked: a device that returns repetitions<<16 | 0 (glitched SRAM,
hung DMA engine, hostile firmware) makes the kernel execute an integer
division by zero β #DE β panic.
Reachability: mxge_dma_test runs from mxge_reset (:1225, i.e. every
attach :4363 and every mxge_open after reset :3341) and from
mxge_firmware_probe (:551). A device that passed the preceding
MXGEFW_CMD_RESET handshake but returns a zero tick count panics the host
during boot-time probe or during the watchdog-recovery path
(mxge_watchdog_reset :3658-3664) β turning a flaky NIC into a panicking
NIC precisely when the system is trying to recover it.
Threat model
Device-fault / hostile-device (same premise as DF-3716/3718/3720); the divisor is never host-derived.
Verification
Hardware-gated (no Myricom NIC on the guest); source-certain; the
division-by-zero fault behavior itself is architectural (x86 #DE in kernel
context = fatal trap). inconclusive per family convention.
Fix
fix.diff: check (cmd.data0 & 0xffff) == 0 after each successful test
command and bail out with EIO through the existing abort path
(git-apply clean).
DF-3721 VERDICT
Status: inconclusive (hardware-gated), confidence: certain source-level.
Source proof
- :459/:469/:479 divide by (cmd.data0 & 0xffff), the device-returned 0.5us tick counter of MXGEFW_DMA_TEST / MXGEFW_CMD_UNALIGNED_TEST.
- Zero divisor => x86 #DE in kernel context => fatal trap/panic.
- Call graph: mxge_reset :1225 (attach :4363, every open :3341), mxge_firmware_probe :551, and indirectly the watchdog recovery (mxge_watchdog_reset reloads fw + mxge_open :3658-3664).
Not reproduced
Requires the device to answer the DMA test with ticks==0; guest has no Myricom NIC (env.txt).
Fix
fix.diff guards all three divisions (git apply --check clean); fix_status=not_testable.
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 git apply --check clean; not buildable without mxge hardware.
findings/poc/DF-3721/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
findings/poc/DF-3721/VERDICT.md; fix.diff (zero-divisor guards on all three sites, git-apply clean); env.txt
PoC changes
No seed PoC; hardware-gated.
Verified recommended fix
Treat (cmd.data0 & 0xffff) == 0 as a failed benchmark: status=EIO via the existing abort path.
Verdict
Source-certain, hardware-gated: mxge_dma_test (if_mxge.c:430-488) divides by the device-returned tick count (cmd.data0 & 0xffff) at :459/:469/:479 with no zero check; a device answering the DMA benchmark with repetitions<<16|0 (fault/hang/hostile firmware) triggers an integer divide-by-zero -> kernel panic. Reachable at attach (mxge_reset :1225 via :4363), at every open (:3341) and inside watchdog recovery (mxge_watchdog_reset :3658-3664 reloads firmware and reopens), so a flaky NIC panics the host exactly when recovery is attempted. Guest has no Myricom device; not runtime-testable.
No comments yet.