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

sk_marv_miibus_writereg(): inverted YU_SMICR_BUSY check aborts the SMI write-completion wait the moment the write starts (vs correct msk_phy_writereg sibling)

Summary

The completion wait breaks as soon as BUSY is SET - i.e. when the write has just started - and otherwise burns the full 1000xDELAY(1) when idle; the wait never waits. Back-to-back SMI writes can hit the one-op-at-a-time SMI engine while the previous write is in flight and be silently dropped -> intermittent PHY misconfiguration/link flaps on Yukon hardware. Two-token inverted condition vs the in-tree correct msk sibling for the same PHY family. Hardware-gated; one-token fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3905 Β· 4 files
FileTypeDescriptionSize
README.md β€” 2.5 KB ↓ raw
fix.diff β€” 650 B view raw
manifest.json β€” 932 B view raw
verdict.json β€” 2.7 KB view raw

DF-3905 β€” sk_marv_miibus_writereg(): inverted BUSY check aborts the SMI

write-completion wait the moment the write starts

File: sys/dev/netif/sk/if_sk.c (pass 2, GLM 5.3) Hardware-gated: Yukon (SK_YUKON*) PHY writes only happen on real Marvell/SysKonnect hardware; the audit guest has none. Source-certain via comparison with the sibling driver and FreeBSD/OpenBSD lineage.

The bug (source)

sk_marv_miibus_writereg() (sys/dev/netif/sk/if_sk.c:507-529) issues an SMI (MII management) write and then tries to wait for completion:

SK_YU_WRITE_2(sc_if, YUKON_SMICR, ... | YU_SMICR_OP_WRITE);   /* :515-517 */

for (i = 0; i < SK_TIMEOUT; i++) {                            /* :519    */
        DELAY(1);
        if (SK_YU_READ_2(sc_if, YUKON_SMICR) & YU_SMICR_BUSY) /* :521-522 */
                break;                                        /* WRONG   */
}

The condition is inverted: it breaks the wait as soon as BUSY is set β€” i.e. exactly when the write has started β€” and otherwise burns the full 1000Γ—DELAY(1) loop when the PHY is idle. The correct protocol (wait while BUSY is set, proceed when it clears) is what the sibling driver implements for the same hardware family:

So under if_sk.c the "wait for write completion" never waits for the completion. Consequences on Yukon hardware: the caller (miibus layer, sk_init_yukon, mii_mediachg from the 1 Hz tick / media ioctls) can issue the next SMI operation while the previous PHY write is still in flight; Marvell SMI executes one operation at a time, so back-to-back writes can be silently dropped β€” PHY configuration (aneg restart, power state, media override) intermittently not taking effect. This is a functional-correctness bug (media/PHY state machine misconfiguration, link flaps), not memory corruption.

Lineage

The inverted form is a DFly-carried transcription bug (present since the driver import); FreeBSD if_sk.c historically waits with (SMICR & BUSY) == 0.

Why not runtime-verified

No Yukon silicon on the audit guest (YUKON_SMICR MMIO unreachable); the defect is a two-token logic inversion proven by source diff against the in-tree sibling driver handling the same PHY. status inconclusive per family convention for hardware-gated findings.

Fix

fix.diff: invert the break condition to (... & YU_SMICR_BUSY) == 0, matching msk_phy_writereg() exactly.

Fix verification

inconclusive
baseline no→ patch + rebuild →patched clean

Two-token condition inversion, byte-identical in shape to the proven-correct msk_phy_writereg sibling. Not runnable on this guest (no Yukon NIC).

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

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-3905/README.md (side-by-side with the msk sibling); findings/poc/DF-3905/fix.diff (condition inversion)

PoC changes

No seed PoC; no runnable trigger exists without Yukon silicon (YUKON_SMICR MMIO). The proof is the source diff against the in-tree sibling driver for the same PHY.

Verified recommended fix

Invert the break condition in sk_marv_miibus_writereg to (... & YU_SMICR_BUSY) == 0, mirroring msk_phy_writereg.

Verdict

Source-certain logic inversion, hardware-gated (no Yukon silicon on the audit guest) -> inconclusive per family convention. sk_marv_miibus_writereg (sys/dev/netif/sk/if_sk.c:519-523) breaks its SMI write-completion wait as soon as YU_SMICR_BUSY is SET - i.e. the moment the write starts - and otherwise spins the full SK_TIMEOUT when the PHY is idle: the wait-for-completion never waits. The sibling driver for the same hardware implements the correct protocol: msk_phy_writereg (sys/dev/netif/msk/if_msk.c:417-428) breaks on (GM_SMI_CT_BUSY) == 0. Consequence on Yukon hardware: back-to-back SMI writes (miibus config, sk_init_yukon, mii_mediachg from the 1 Hz tick/media ioctls) can be issued while the previous PHY write is still in flight and silently dropped by the one-op-at-a-time SMI engine - intermittent PHY misconfiguration/link flaps. Functional-correctness bug, not memory corruption; severity Low. fix.diff inverts the condition to match msk_phy_writereg.