β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-3721

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3721 Β· 6 files
FileTypeDescriptionSize
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).

VERDICT.md
↓ download raw

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_testable
baseline no→ patch + rebuild →patched clean

fix.diff git apply --check clean; not buildable without mxge hardware.

findings/poc/DF-3721/fix.diff
↓ fix.diffper-fix-DF-3721

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.