miibus_mediainit calls ifmedia_set() on an EMPTY media list β panic("ifmedia_set") at NIC attach β the hub owning the DF-4930/DF-4957/DF-4981 empty-media family panic (family fix belongs here)
Summary
The walk finds no media when every PHY took its no-media branch and the parent added nothing - ifmedia_set panics on the no-match. REPRODUCED live on guest (verbatim walk replay -> panic, guest down; the fixed walk survives with ifm_cur non-NULL). PASS-2 INSIGHT: the family leaf-fix pattern is a NO-OP for the MIIF_NOISOLATE drivers (ciphy/truephy - the mii_phy_add_media IFM_NONE fallback is gated) - this hub guard is the only fix covering them. Guard+autoselect-default fix (compiles -Werror).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5001 Β· 15 files| File | Type | Description | Size | |
|---|---|---|---|---|
| miihub.c | β | 5.0 KB | view raw | |
| Makefile | β | 73 B | β download | |
| build.sh | β | 111 B | view raw | |
| run.sh | β | 187 B | view raw | |
| run_fix.sh | β | 426 B | view raw | |
| build.log | β | 2.6 KB | view raw | |
| run.log | β | 683 B | view raw | |
| run.2.log | β | 1.4 KB | view raw | |
| panic.txt | β | 2.3 KB | view raw | |
| env.txt | β | 563 B | view raw | |
| fixcheck-build.log | β | 899 B | view raw | |
| fix.diff | β | 894 B | view raw | |
| verdict.json | β | 5.0 KB | view raw | |
| VERDICT.md | β | 4.8 KB | β raw | |
| README.md | β | 2.3 KB | β raw |
DF-5001 β miibus_mediainit panics on an empty media list (the hub of the
DF-4930 / DF-4957 / DF-4981 "no media present" family)
What
miibus_mediainit() (sys/dev/netif/mii_layer/mii.c:227-245) pokes the
parent NIC for its own media, then walks mii->mii_media.ifm_list looking
for IFM_ETHER|IFM_AUTO, and unconditionally calls
ifmedia_set(&mii->mii_media, media) (mii.c:244). If the list is EMPTY
(every probed PHY took its "no media present" branch and the parent added
nothing), the walk body never runs, media stays 0 (mii.c:232), and
ifmedia_set(ifm, 0) finds no match and executes
panic("ifmedia_set") (sys/net/if_media.c:174). DragonFly panics where a
graceful attach failure is warranted.
Reproduce (on the QEMU guest)
# build (guest): sh build.sh # or: see build.log # baseline run: sh run.sh # expect panic + guest down # after vm.sh reset: sh run_fix.sh # fixed walk must survive
The KLD miihub.ko replays the hub walk verbatim (mii.c:238-244) against a
real struct ifmedia with an empty list:
sysctl hw.miihub_fire=1β baseline:ifmedia_set: no match for 0x0/...thenpanic: ifmedia_set(see panic.txt).sysctl hw.miihub_fixcheck=1β the fixed walk (fix.diff): survives,ifm_curnon-NULL (see run.2.log).
Expected output
Baseline (serial console, panic.txt):
miihub: ifmedia_init (EMPTY ifm_list -- ...) miihub: running miibus_mediainit walk verbatim (mii.c:238-244) ifmedia_set: no match for 0x0/0xfffffff panic: ifmedia_set Trace: ifmedia_set() <- miihub_fire() <- sysctl_root <- userland_sysctl <- sys___sysctl
Fixcheck (run.2.log):
miihub-fix: survived; ifm_cur=0xfffff8008d481d60 media=0x20 miihub-fix: ifm_cur->ifm_media=0x20 (service deref safe)
Trigger precondition (why this is Low, not High)
The empty list requires real PHY hardware whose BMSR/EXTSR report zero
media capability while still answering the probe (the DF-4930 atphy,
DF-4957 ciphy, DF-4981 jmphy, DF-5003 truephy attach branches β plus the
~20 ukphy_attach-shaped siblings), behind a parent NIC whose mediainit
method adds no media of its own. No unprivileged userland path can drive
the bus into this state; it is an attach/boot-time DoS on faulty or
malicious hardware-in-the-loop. The sink itself (the hub walk + terminal
ifmedia_set) is proven on this kernel by the replay above.
DF-5001 VERDICT β REPRODUCED (panic, replay of the hub statements)
Bottom line: miibus_mediainit() (mii.c:227-245) unconditionally ends
in ifmedia_set(&mii->mii_media, media) (mii.c:244). On an empty media
list media is still 0 (mii.c:232) and DragonFly's ifmedia_set()
executes panic("ifmedia_set") (sys/net/if_media.c:166-174, panic at :174)
β taking the whole system down at NIC attach time. The walk was executed
verbatim on the running guest kernel (KLD replay via sysctl) and panicked
exactly as predicted, killing the guest; the fixed walk (fix.diff) survives
the identical scenario and leaves ifm_cur non-NULL.
How it was reproduced
miihub.c contains a verbatim copy of the hub walk (mii.c:238-244)
operating on a real struct ifmedia initialized with ifmedia_init() β
the exact state of mii->mii_media after miibus_attach() (mii.c:180-181)
when every probed PHY has taken its "no media present" branch (family:
atphy.c DF-4930, ciphy.c DF-4957, jmphy.c DF-4981, truephy.c DF-5003, plus
the ukphy_attach-shaped siblings β ukphy.c:166-170, amphy, brgphy, ...)
and the parent NIC's MIIBUS_MEDIAINIT method added nothing (mii.c:235).
sh build.shβ buildsmiihub.koon the guest with the kernel's full-Werrorwarning set (build.log). NeededSRCS+= device_if.h bus_if.h(the generated-interface headers are absent from the guest's /sys aftervm.sh reset with-src; DF-4930's run had them pre-generated).sh run.shβsysctl hw.miihub_fire=1β panic:ifmedia_set: no match for 0x0/0xfffffffβpanic: ifmedia_set, traceifmedia_set() <- miihub_fire() <- sysctl_root <- userland_sysctl <- sys___sysctl, guest down (panic.txt, full serial-console capture; vm.sh status = down immediately after).vm.sh reset with-src;sh run_fix.shβsysctl hw.miihub_fixcheck=1β the FIXED walk (fix.diff shape: empty list βifmedia_add(IFM_ETHER|IFM_AUTO)βifmedia_set) survives:miihub-fix: survived; ifm_cur=0xfffff8008d481d60 media=0x20andifm_cur->ifm_media=0x20β 0x20 = IFM_ETHER|IFM_AUTO β proving theife = mii->mii_media.ifm_cur; IFM_INST(ife->ifm_media)dereference every*_service()performs on the next tick (e.g. truephy.c:185) stays safe (run.2.log).- The patched
mii.citself (fix.diff applied) compiles clean under-Werroras a KLD source on the guest (fixcheck-build.log) βLIST_EMPTY/ifmedia_addare already in mii.c's include set.
Why the end-to-end path is hardware-preconditioned (severity Low)
mii_probe() (mii.c:258-282) only creates the miibus when at least one
PHY address passes miibus_no_phy() (mii.c:105-116) β which requires a
BMSR with some media/EXTSTAT bits β and ukphy always attaches
(ukphy.c:126-131). The empty-list state therefore requires a PHY that
PASSES the probe (BMSR_MEDIAMASK|BMSR_EXTSTAT != 0 at mii.c:113-115) but
then reports zero media capabilities when its driver re-reads BMSR/EXTSR
at attach (e.g. truephy.c:163-172). That is faulty or
malicious-hardware-in-the-loop behavior, not an unprivileged userland
input. Consequence: attach/boot-time kernel panic (full DoS of the node),
same class and severity as the family findings (DF-4930/4957/4981, all
Low). No escalation angle exists: the primitive is a deterministic
panic() on a failed list match β no memory unsafety, no controllable
write.
Why the hub fix is the right family fix
- One guard in
miibus_mediainitcovers every current and future PHY driver that can add zero media (atphy, ciphy, jmphy, truephy, ukphy shape, and the ~20 siblings). - It is the ONLY fix that covers the
MIIF_NOISOLATEdrivers: themii_phy_add_media()IFM_NONE fallback is gated on MIIF_NOISOLATE being CLEAR (mii_physubr.c:230-232), but ciphy (ciphy.c:132) and truephy (truephy.c:157) always set MIIF_NOISOLATE β for them, "just call mii_phy_add_media unconditionally" adds nothing and the panic remains. (DF-4957's pack already works around this with an explicitifmedia_add; DF-4930's atphy leaf fix works only because atphy does not set MIIF_NOISOLATE.) - Non-empty-but-no-AUTO lists keep the existing behavior (set the last entry's media), which always self-matches.
Fix
fix.diff β in miibus_mediainit(), after the walk: if no entry was
found and the list is empty, ifmedia_add(IFM_ETHER|IFM_AUTO) and set
media accordingly, then ifmedia_set() as before. The bus then attaches
(degraded, autoselect-only) instead of panicking the system.
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 (miibus_mediainit: empty list -> ifmedia_add(IFM_ETHER|IFM_AUTO) before ifmedia_set) could not be exercised through the real in-kernel miibus_mediainit on this guest (no miibus-attached NIC exists in QEMU, so the real code path cannot be driven end-to-end). Its operative mechanism WAS validated on the running kernel: the identical empty-list scenario replayed through the FIXED walk survives with ifm_cur non-NULL and ifm_cur->ifm_media=0x20 (run.2.log), and the patched mii.c itself compiles clean under -Werror as a KLD source (fixcheck-build.log).
run.2.log ('miihub-fix: survived; ifm_cur=0xfffff8008d481d60 media=0x20'), fixcheck-build.log (miifix.ko linked from patched mii.c), fix.diff (applies cleanly: git apply --check OK)
Confirmed kernel references
Detail
Evidence (decisive lines)
panic.txt (serial console: 'ifmedia_set: no match for 0x0/0xfffffff' -> 'panic: ifmedia_set' -> trace ifmedia_set<-miihub_fire<-sysctl_root<-userland_sysctl<-sys___sysctl; vm.sh status=down right after), run.log (baseline, ssh died at panic), run.2.log (fixcheck: 'miihub-fix: survived; ifm_cur=0xfffff8008d481d60 media=0x20' + 'ifm_cur->ifm_media=0x20 (service deref safe)', guest up), build.log (clean -Werror KLD build), fixcheck-build.log (patched mii.c compiles as KLD source), fix.diff (git-apply-able, verified), VERDICT.md (full narrative)
PoC changes
PoC authored fresh (no seed). Two build iterations: the generated-interface headers (device_if.h/bus_if.h) are absent from the guest /sys after 'vm.sh reset with-src', so the Makefile needed SRCS+= device_if.h bus_if.h (kmod.mk's makeobjops.awk rules generate them). Baseline run killed the guest before ssh could flush; decisive output captured from the serial console (vm.sh log).
Verified recommended fix
miibus_mediainit: if the media list is empty after the parent poke, ifmedia_add(IFM_ETHER|IFM_AUTO) before ifmedia_set() (fix.diff) -- fixes the whole family in one place, including the MIIF_NOISOLATE drivers.
Verdict
REPRODUCED: miibus_mediainit (mii.c:227-245) ends in an unconditional ifmedia_set(&mii->mii_media, media) (mii.c:244); on an EMPTY media list the walk (mii.c:238-243) never runs, media stays 0 (mii.c:232), and DragonFly's ifmedia_set() executes panic("ifmedia_set") (sys/net/if_media.c:174). A KLD replaying the hub walk verbatim against a real struct ifmedia (state = every probed PHY took its 'no media present' branch: atphy DF-4930 / ciphy DF-4957 / jmphy DF-4981 / truephy DF-5003, parent NIC added nothing) panicked the running guest exactly as predicted ('ifmedia_set: no match for 0x0/0xfffffff' -> panic, trace ifmedia_set<-miihub_fire<-sysctl) and the guest went down (panic.txt); the fixed walk (fix.diff: empty list -> ifmedia_add(IFM_ETHER|IFM_AUTO) -> ifmedia_set) survived the identical scenario with ifm_cur non-NULL (run.2.log), and the patched mii.c compiles clean under -Werror (fixcheck-build.log). End-to-end trigger is hardware-preconditioned (a PHY that passes the BMSR probe at mii.c:113-115 but reports zero media capabilities at driver attach), i.e. attach/boot-time DoS on faulty or malicious hardware-in-the-loop -- same class as the family leaves (all Low); no memory unsafety, no escalation angle. This hub guard is the family-wide fix and the ONLY one covering the MIIF_NOISOLATE drivers ciphy and truephy, for whom the mii_phy_add_media IFM_NONE fallback is gated off (mii_physubr.c:230-232).
No comments yet.