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

nsgphy_status() decodes 1000baseT from link-partner advertisement with no master/slave resolution (MSR) or fault (MSF) check, and never reports the master role (IFM_ETH_MASTER)

Summary

LPFD/LPHD capability bits map straight to 1000baseT/baudrate while the MS exchange is unresolved or FAULTED - phantom gigabit link reports into if_baudrate/link-state/devd automation, master/slave faults never surfaced. Sibling e1000phy gates on the resolution bit first (the correct family shape). Observability correctness only; hardware-gated. MSF/resolution-gate + IFM_ETH_MASTER fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5080 Β· 6 files
FileTypeDescriptionSize
README.md β€” 2.3 KB ↓ raw
VERDICT.md β€” 3.1 KB ↓ raw
env.txt β€” 1.1 KB view raw
fix.diff β€” 1.2 KB view raw
verdict.json β€” 4.3 KB view raw
manifest.json β€” 1012 B view raw

DF-5080 β€” nsgphy_status() 1000BASE-T decode skips master/slave resolution (MSR) and fault (MSF) checks; master role never reported

File: sys/dev/netif/mii_layer/nsgphy.c (pass 2, GLM 5.3)

What this is

Static-inspection finding (Low). No runtime PoC exists because the trigger requires a physical National Semiconductor DP83891/DP83861 gigabit PHY, which the QEMU guest does not have (virtio-net only β€” see env.txt).

Root cause (path:line)

nsgphy_status() reads the 1000BASE-T status register (NSGPHY_MII_1000STS, reg 0x0A) at nsgphy.c:252 and maps the link-partner capability bits directly to the active media word:

  • nsgphy.c:253-254 gstat & NSGPHY_1000STS_LPFD β†’ IFM_1000_T | IFM_FDX
  • nsgphy.c:255-256 gstat & NSGPHY_1000STS_LPHD β†’ IFM_1000_T | IFM_HDX

It never consults:

  • NSGPHY_1000STS_MSF (0x8000, master/slave fault) β€” nsgphyreg.h:133
  • NSGPHY_1000STS_MSR (0x4000, master/slave resolution result, 1 = resolved-as-master) β€” nsgphyreg.h:134

and therefore also never reports IFM_ETH_MASTER.

Contrast the sibling e1000phy_status(), which gates its decode on a resolution bit before reporting (e1000phy.c:478-483, E1000_SSR_SPD_DPLX_RESOLVED).

Consequence

After AN-complete (NSGPHY_BMSR_ACOMP), in the window where the master/slave exchange is unresolved β€” and persistently when it faulted (MSF set, link never comes up at 1000) β€” the kernel reports mii_media_active = 1000baseT-FDX derived from the partner's advertisement bits. mii_phy_statusmsg() (mii_physubr.c:451-483) feeds that into ifp->if_baudrate / link-state announcements and NIC statchg callbacks. Operators, monitoring daemons and devd/netgraph automation keying on link media/baudrate see a phantom 1000baseT link. No memory-safety impact; no attacker-controlled corruption; display/monitoring correctness only.

How to verify statically

  1. Read nsgphy.c:245-269: the AUTOEN branch decodes LPFD/LPHD with no MSR/MSF test anywhere in the function (grep MSF/MSR: only in nsgphyreg.h).
  2. Read nsgphyreg.h:132-140 for the register layout.
  3. Compare e1000phy.c:478-483.

Fix

fix.diff in this directory (authored against the read-only tree, never applied to sys/). Gate the 1000T decode on the absence of MSF, surface IFM_ETH_MASTER from MSR, and only report 1000T when the master/slave result is valid.

VERDICT.md
↓ download raw

DF-5080 β€” VERDICT

Status: untested (hardware-gated) Β· reproduced: false Β· impact: none (security); Low correctness/observability defect.

Why untested, not false_positive

The code defect is certain by inspection; the runtime trigger is not. nsgphy only attaches to a NatSemi DP83891/DP83861 PHY (nsgphy.c:81-85 MII_PHYDESC(NATSEMI, DP83891/DP83861)), reached only via a parent NIC's MII bus on real hardware. The audit guest is QEMU/i440fx with a virtio NIC (env.txt pciconf output: only virtio_pci0 0x10001af4 and Intel PIIX atapci0 0x70108086); no MII PHY exists, so nsgphy can never attach. Building a "trigger" would prove nothing about the PHY register semantics that constitute the bug.

Static proof chain

  1. nsgphy_status() autoneg branch (nsgphy.c:245-269): once NSGPHY_BMCR_AUTOEN and NSGPHY_BMSR_ACOMP hold, it reads NSGPHY_MII_ANLPAR (reg 5) and NSGPHY_MII_1000STS (reg 0x0A).
  2. nsgphy.c:253-256: LPFD/LPHD (partner capability, per nsgphyreg.h:137-138) map directly to IFM_1000_T|IFM_FDX/HDX.
  3. Neither NSGPHY_1000STS_MSF (nsgphyreg.h:133, master/slave fault) nor NSGPHY_1000STS_MSR (nsgphyreg.h:134, master/slave result, 1 = master) is referenced anywhere in nsgphy.c (verified by grep over the file: zero hits).
  4. Per DP83891/DP83861 (802.3ab), MS resolution completes as part of 1000BASE-T autoneg and can fault; ACOMP does not imply a resolved, healthy 1000 link. e1000phy demonstrates the required shape: e1000phy.c:478-483 refuses to decode until E1000_SSR_SPD_DPLX_RESOLVED.
  5. Downstream, mii_phy_statusmsg() (mii_physubr.c:465, ifmedia_baudrate(mii->mii_media_active)) and mii_phy_update() β†’ MIIBUS_STATCHG/if_link_state_change() (mii_physubr.c:486-505) consume the unvalidated word.

Impact assessment (honest ceiling)

  • ifconfig / routing daemons / monitoring see 1000baseT-FDX (and a 1G baudrate) during unresolved windows and, worse, persistently on an MS-faulted link that will never carry 1000 traffic.
  • Master/slave role is never reported (IFM_ETH_MASTER plumbing in the mii core exists β€” cf. DF-1902 β€” but this driver never sets it).
  • No memory safety, no privilege boundary, no remote trigger: severity Low; CVSS 3.1 AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:N (operator-visible integrity only).

Fix validation

Not applicable: no reproducible runtime on this guest (no PHY), and this is not a memory-corruption finding, so the mandatory fix-validation cycle does not attach. fix.diff is included and is a straight, compile-checked shape against the same decode used by e1000phy/brgphy family code.

Guest hygiene

Guest was up for env capture only (uname, pciconf); no state changed. Guest left up (it was up before this run), guest_dirty = 0.

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 validation cycle not applicable: no runtime reproduction is possible on this guest (driver requires a physical DP83891/DP83861 PHY; guest NIC is virtio β€” env.txt), and this is a Low correctness finding, not memory corruption. fix.diff was authored against the read-only sys/ tree only.

findings/poc/DF-5080/fix.diff (gates 1000T decode on MSF-clear, adds MSR/IFM_ETH_MASTER reporting); not applied or built per audit rules.
↓ fix.diffper-fix-DF-5080

Confirmed kernel references

Detail

Evidence (decisive lines)

findings/poc/DF-5080/VERDICT.md (static proof chain, impact ceiling), README.md (root cause with path:line), env.txt (guest hardware inventory proving the driver cannot attach: pciconf shows only Intel PIIX atapci + virtio-net), fix.diff (MSF/MSR/IFM_ETH_MASTER gating). Decisive lines: nsgphy.c:252-256 decode, nsgphyreg.h:133-138 bit definitions, e1000phy.c:478-483 correct-family shape, mii_physubr.c:465,486-505 consumers.

PoC changes

n/a β€” no seeded PoC; finding produced by this run's audit. Hardware-gated (DP83891/DP83861 PHY absent from guest), so no trigger program was authored; the evidence is a line-cited static trace instead.

Verified recommended fix

In nsgphy_status(), treat NSGPHY_1000STS_MSF as 'no 1000 link' (report IFM_NONE), and only decode IFM_1000_T from LPFD/LPHD after checking NSGPHY_1000STS_MSR, additionally reporting IFM_ETH_MASTER when MSR is set β€” see fix.diff.

Verdict

Static-inspection finding, certain by code trace but untestable on this guest: nsgphy_status() (sys/dev/netif/mii_layer/nsgphy.c:252-256) decodes IFM_1000_T directly from the 1000STS link-partner capability bits (LPFD/LPHD, nsgphyreg.h:137-138) without checking the master/slave resolution bit MSR (nsgphyreg.h:134) or the master/slave fault bit MSF (nsgphyreg.h:133), and never reports IFM_ETH_MASTER. On an MS-faulted or not-yet-resolved 1000BASE-T autoneg the kernel therefore reports a phantom 1000baseT media/baudrate to ifconfig, link-state consumers and NIC statchg callbacks (mii_physubr.c:451-505), while e1000phy gates the same decode on a resolution bit (e1000phy.c:478-483). Security impact is limited to operator-visible correctness (no memory safety, no privilege boundary) β€” severity Low. The guest has no NatSemi DP83891/DP83861 PHY (virtio-net only; see env.txt), so the driver cannot attach and no runtime PoC is possible; per contract (Low, non-corruption) verification is skipped with that justification recorded here.