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

Unbounded PHY-reset busy-wait in my_autoneg_xmit β€” the driver's only hardware-wait loop without MY_TIMEOUT (spins forever in ioctl, boot, and ISR contexts holding ifp->if_serializer)

Summary

The reset-bit poll has no counter - contrast my_setcfg and my_reset, both bounded at MY_TIMEOUT with failure kprintf. A PHY whose BMCR sticks at 0xFFFF parks the caller forever: via ifconfig media (root), via boot FORCEDELAY, and worst via my_txeoc's deferred autoneg running inside my_intr holding the serializer - the whole ifnet including its watchdog is wedged. The my(4) instance of the unbounded idle/reset-loop family (DF-4217 sibling). Bounded-loop fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4258 Β· 6 files
FileTypeDescriptionSize
trigger.sh β€” 532 B view raw
env.txt β€” 1007 B view raw
VERDICT.md β€” 2.1 KB ↓ raw
fix.diff β€” 704 B view raw
manifest.json β€” 790 B view raw
verdict.json β€” 2.3 KB view raw
VERDICT.md
↓ download raw

DF-4258 VERDICT β€” unbounded while (BMCR & RESET) spin in my_autoneg_xmit

Status: inconclusive on the audit guest (hardware-gated). Missing bound certain at source level.

Reproduction attempt

No Myson PCI device on the guest (env.txt) β€” my0 cannot exist, the MII bit-bang (my_send_cmd_to_phy, if_my.c:161-209) cannot run. This matches the treatment of the sibling unbounded-loop family findings (DF-4217 ae i-- and the DF-3604/3761/3715 NIC-checklist set, all hardware-gated).

Analysis

if_my.c:379 is the only hardware-wait loop in the driver without the MY_TIMEOUT guard β€” contrast if_my.c:708-714 (my_setcfg) and if_my.c:738-743 (my_reset), both for (i = 0; i < MY_TIMEOUT; i++) with a failure kprintf. The reset poll executes:

  • at boot for every attach (FORCEDELAY, if_my.c:946 β†’ 422),
  • from my_ifmedia_upd on SIOCSIFMEDIA (root via ifconfig, if_my.c:1508-1511),
  • from my_txeoc in the interrupt service routine when a deferred autoneg fires (if_my.c:1203-1204 β†’ 436).

A PHY whose BMCR read sticks at 0xFFFF (hung part, unplugged card, PCI error) or that never completes self-reset parks the caller forever. In the ISR case ifp->if_serializer is held by my_intr (established via bus_setup_intr(..., ifp->if_serializer), if_my.c:955-957), so the whole ifnet β€” watchdog included β€” is wedged: system-level denial of service on affected hardware. Root ioctl or hardware fault required to trigger at runtime; boot variant needs no privileges but requires a broken PHY on the installed card.

Severity Low (hardware/root-gated DoS), CWE-835, confidence certain for the missing bound.

Fix

Bound the loop like my_reset does (fix.diff): poll MY_TIMEOUT iterations with DELAY(10) and warn if the reset never completes.

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 adds the bounded poll + warning, mirroring my_reset; hardware-gated, not validated here

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

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (all three trigger contexts + bounded-loop contrast); env.txt

PoC changes

trigger.sh wraps the ifconfig in timeout(1) to make the wedge observable

Verified recommended fix

Bound the BMCR reset poll with the same MY_TIMEOUT loop used in my_reset

Verdict

my_autoneg_xmit polls the PHY reset bit with 'while (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET);' (sys/dev/netif/my/if_my.c:379) β€” the only hardware-wait loop in the driver without a MY_TIMEOUT bound (contrast my_setcfg 708-714 and my_reset 738-743). A PHY whose BMCR reads stick at 0xFFFF (hung part, card unplugged, PCI error β€” bit 15 always set) parks the caller forever, each iteration being a ~ms-scale bit-banged MII transaction. Reachable from SIOCSIFMEDIA (ifconfig media autoselect, if_my.c:1508-1511), at boot from my_attach's FORCEDELAY autoneg (if_my.c:946), and β€” worst β€” from my_txeoc inside the ISR with ifp->if_serializer held (if_my.c:1203-1204, bus_setup_intr established against the serializer at 955-957), which wedges the whole ifnet including its watchdog. Not executable on the audit guest (no Myson NIC, env.txt); missing bound is certain at source level. This is the my(4) instance of the unbounded idle/reset-loop family (cf. DF-4217).