jmphy_attach 'no media present' branch skips mii_phy_add_media, so miibus_mediainit calls ifmedia_set on an EMPTY media list β DragonFly panic("ifmedia_set") at attach (DF-4930/DF-4957 family)
Summary
The third member of the empty-media family (after atphy DF-4930 and ciphy DF-4957): the no-media branch skips the only population call while still triggering mediainit, and jme implements no mediainit method so nothing else fills the list - DFly's ifmedia_set panics on the empty list. Kernel sink PROVEN live on guest (jmsink KLD: 'no match for 0x0' -> panic, guest down; the IFM_NONE-fallback path survives). Hw-fault precondition (stuck-reset PHY or SMI timeout returning 0). Unconditional-add-media fix (family alternative: harden miibus_mediainit for all ~20 siblings).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4981 Β· 14 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.9 KB | β raw | |
| VERDICT.md | β | 4.8 KB | β raw | |
| jmsink.c | β | 4.2 KB | view raw | |
| Makefile | β | 52 B | β download | |
| build.sh | β | 194 B | view raw | |
| run.sh | β | 290 B | view raw | |
| build.log | β | 879 B | view raw | |
| run.log | β | 53 B | view raw | |
| run.2.log | β | 323 B | view raw | |
| panic.txt | β | 1.4 KB | view raw | |
| env.txt | β | 658 B | view raw | |
| fix.diff | β | 542 B | view raw | |
| manifest.json | β | 1.2 KB | view raw | |
| verdict.json | β | 3.6 KB | view raw |
DF-4981 β jmphy "no media present" branch β empty media list β panic("ifmedia_set") at attach
File: sys/dev/netif/mii_layer/jmphy.c:124-129 Family: DF-4930 (atphy), DF-4957 (ciphy) β same construct, same sink. Parent NIC: jme(4) (sys/dev/netif/jme/if_jme.c) β mii_phy_probe at :1028, NO miibus_mediainit method (:218-220), so nothing but the PHY populates the media list.
Chain
jmphy_attach reads BMSR (jmphy.c:119); if the PHY reports zero media bits
AND (BMSR_EXTSTAT clear, or EXTSR media bits zero), the branch at
jmphy.c:124-127 prints "no media present" and skips mii_phy_add_media(),
then jmphy.c:131 calls MIIBUS_MEDIAINIT β miibus_mediainit (mii.c:228-246)
walks an EMPTY ifm_list, media stays 0, and mii.c:244 calls
ifmedia_set(&mii->mii_media, 0) β sys/net/if_media.c:168-175:
ifmedia_match() on an empty list returns NULL β panic("ifmedia_set").
Realistic trigger: a JMicron JMP211/JMP202 PHY whose ID registers still match (miidevs: oui JMICRON 0x001b8c, models 0x21/0x22) while BMSR reads 0 β e.g. jme's SMI read timing out returns 0 (if_jme.c:303-308), or a stuck-reset / partially-powered-down PHY. Not emulatable on QEMU.
Build / run (on the guest)
mkdir -p /root/df4981 && cd /root/df4981 # jmsink.c + Makefile there
sh build.sh # -> jmsink.ko
sh run.sh # kldload; sysctl hw.jmsink_fire=1
# EXPECTED: panic("ifmedia_set"),
# ssh dies, guest down
Fix-mechanism check (after vm.sh reset with-src)
kldload /root/df4981/jmsink.ko && sysctl hw.jmsink_fixcheck=1 # EXPECTED: survives, ifm_cur non-NULL (the IFM_NONE fallback entry that # unconditional mii_phy_add_media() installs β mii_physubr.c:235-237)
Success criterion
Baseline: panic: ifmedia_set on the serial console, guest down.
Fixcheck: survives with non-NULL ifm_cur.
DF-4981 VERDICT β jmphy "no media present" β empty media list β panic("ifmedia_set") at attach
File: sys/dev/netif/mii_layer/jmphy.c:124-129 (+ :131) Family: DF-4930 (atphy), DF-4957 (ciphy) β identical construct, identical sink. This pack independently re-proves the sink on the current kernel.
Reproduced?
NOT reproduced end-to-end; the kernel-side sink is PROVEN on this exact kernel (verbatim method, same as the family precedent):
The full trigger requires a JMicron JMP211/JMP202 PHY, behind a jme(4) NIC,
whose ID registers still match miidevs (oui JMICRON 0x001b8c, models 0x21/0x22
β miidevs:227-228) while PHY_READ(sc, MII_BMSR) (jmphy.c:119) returns zero
media bits and MII_EXTSR (jmphy.c:120-121) contributes none β e.g. a
stuck-reset/powered-down PHY, or jme's SMI read timing out, which returns 0
(if_jme.c:303-308). No such PHY exists or is emulatable on the QEMU guest
(env.txt), so jmphy_attach itself cannot be driven into the branch here.
What WAS executed on the guest, using the real kernel ifmedia_* functions,
is the exact kernel-side tail of the chain β the state miibus_mediainit
is left in when jmphy's no-media branch skips mii_phy_add_media():
jmphy_attach(jmphy.c:119-121): capabilities/extcapabilities both have zero media bits β jmphy.c:124-127 prints "no media present" and SKIPSmii_phy_add_media(sc)β themii->mii_media.ifm_liststays EMPTY.- jmphy.c:131
MIIBUS_MEDIAINIT(sc->mii_dev)βmiibus_mediainit(mii.c:228-246): the parent pokeMIIBUS_MEDIAINIT(parent)(mii.c:235) is a no-op for jme β jme implements only miibus_{readreg,writereg,statchg} (if_jme.c:218-220) and attaches the bus viamii_phy_probe(if_jme.c:1028) β so nothing else populates the list. - The list walk (mii.c:236-240) finds nothing;
mediastays 0; mii.c:244 callsifmedia_set(&mii->mii_media, 0). ifmedia_set(sys/net/if_media.c:168-175):ifmedia_match()on an empty list returns NULL βpanic("ifmedia_set").
Observed (run.log + panic.txt, from the serial console):
jmsink: loaded; sysctl hw.jmsink_fire=1 to panic
jmsink: ifmedia_init (empty list)
jmsink: list walk done, media=0x0; calling ifmedia_set (mii.c:244)
ifmedia_set: no match for 0x0/0xffffffff
panic: ifmedia_set
cpuid = 1
Trace ... ifmedia_set() at ifmedia_set+0x53
jmsink_fire() at jmsink_fire+0x8e
sysctl_root ... userland_sysctl ... sys___sysctl
Debugger("panic")
The guest died mid-sysctl (ssh never returned; vm.sh status β down) β a
kernel-triggered fatal event at the exact sink the finding cites, on the
unpatched kernel. Note this is DragonFly-specific: FreeBSD's ifmedia_set
prints a warning and returns on no-match; DragonFly's panics
(sys/net/if_media.c:172-175).
Impact ceiling
Boot/attach-time kernel panic (DoS) on jme(4)+JMP211/JMP202 hardware whose
PHY misreports zero media capability. No unprivileged-user trigger; requires
a hardware fault state (BMSR=0 with matching ID regs). Memory-safety impact:
none β the panic is an intentional panic() guard, reached via a logic gap.
Severity Low, consistent with family precedent DF-1973/DF-4923/DF-4930/DF-4957.
Fix validation
fix.diff (authored after verification, never applied to the read-only
sys/ tree) makes jmphy_attach call mii_phy_add_media() unconditionally.
With zero capabilities that installs exactly the IFM_NONE fallback entry
(mii_physubr.c:235-237 β if ((sc->mii_flags & MIIF_NOISOLATE) == 0) ADD(
IFM_ETHER|IFM_NONE ...); jmphy never sets MIIF_NOISOLATE and jme passes no
such flag through mii_phy_probe), so miibus_mediainit's ifmedia_set()
finds a match and survives, and ifm_cur is non-NULL for later
jmphy_service() (jmphy.c:138 dereferences mii->mii_media.ifm_cur).
Fixcheck executed on the guest after vm.sh reset with-src (run.2.log):
jmsink-fix: ifmedia_init + IFM_NONE fallback entry (the fixed jmphy path) jmsink-fix: calling ifmedia_set(IFM_ETHER|IFM_NONE) -- must NOT panic jmsink-fix: survived; ifm_cur=0xfffff8008d481c80 (non-NULL keeps jmphy_service safe)
End-to-end kernel build with the patch was not performed: the bug is a one-line call-site change whose operative mechanism was validated with the real kernel functions on this kernel; a full jme+jmphy attach cannot exist on this guest. fix_status: not_testable (as persisted for the family), with the mechanism proven as above.
Guest was reset (vm.sh reset with-src) after both runs; left clean/up.
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 (jmphy.c: call mii_phy_add_media unconditionally; with zero capabilities it installs the IFM_NONE fallback entry per mii_physubr.c:235-237) could not be exercised end-to-end (no jme/JMicron hardware). Its operative mechanism WAS validated on the guest with the real kernel functions: with the fallback entry present, the identical ifmedia_set sequence survives and leaves ifm_cur non-NULL (run.2.log: 'jmsink-fix: survived; ifm_cur=0xfffff8008d481c80').
VERDICT.md 'Fix validation' section; fix.diff; run.2.log (fixcheck output)
Confirmed kernel references
Detail
Evidence (decisive lines)
panic.txt (sink panic: 'ifmedia_set: no match for 0x0/0xffffffff' -> panic, full trace), run.log (sysctl hw.jmsink_fire=1; ssh never returned; vm.sh status => down), run.2.log (fixcheck after reset: 'jmsink-fix: survived; ifm_cur=0xfffff8008d481c80'), VERDICT.md (jmphy.c:119-131 -> mii.c:228-246 -> sys/net/if_media.c:168-175, parent jme adds no media: if_jme.c:218-220, mii_phy_probe at :1028, SMI timeout returns 0: if_jme.c:303-308)
PoC changes
PoC authored fresh (no seed): jmsink KLD replaying the sink with jmphy-accurate citations; needed device_if.h/bus_if.h copied from the kernel objdir into the module dir for the kmod build.
Verified recommended fix
jmphy_attach: call mii_phy_add_media() unconditionally so the IFM_NONE fallback entry always exists (see fix.diff); or make miibus_mediainit tolerate an empty media list.
Verdict
NOT REPRODUCED end-to-end: the trigger requires JMicron JMP211/JMP202 PHY hardware (behind a jme(4) NIC) whose BMSR/EXTSR report zero media capability while its ID registers still match, and no such PHY exists on the QEMU guest (PHY register behavior is not emulatable). The kernel-side sink of the chain is nonetheless PROVEN on this exact kernel: replaying miibus_mediainit's terminal ifmedia_set() on an EMPTY media list (what jmphy_attach's no-media branch at jmphy.c:124-129 leads to via mii.c:228-246) yields panic("ifmedia_set") with trace ifmedia_set<-jmsink_fire<-sysctl_root<-userland_sysctl<-sys___sysctl and kills the guest (panic.txt). DragonFly's ifmedia_set panics on no-match where FreeBSD returns. The finding is therefore certain as a code path and likely as a field event (hardware-fault precondition), severity Low (boot/attach-time DoS on jme+JMicron hardware, no user-controlled trigger).
No comments yet.