KKASSERT in mlphy_service panics INVARIANTS kernels on every autoneg tick
- File:
sys/dev/netif/mii_layer/mlphy.c - Lines: 220β221 (unconditional assertion); 250β263 (
IFM_AUTOearly-return) - Severity: Low
- CVSS 3.1:
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H - CWE: CWE-617 Reachable Assertion
- Confidence: certain
- Status: new
Summary
mlphy_service unconditionally asserts ife->ifm_data < MII_NMEDIA and then
indexes mii_media_table[ife->ifm_data]. For IFM_AUTO media,
mii_phy_add_media (mii_physubr.c:331) deliberately stores
ifm_data = MII_NMEDIA (= 10) as an "intentionally invalid index".
Because miibus_mediainit selects IFM_AUTO as the default media
(mii.c:238-244) and INVARIANTS is enabled in the default X86_64_GENERIC
kernel (sys/config/X86_64_GENERIC:56), the assertion fires on every per-second
MII_TICK for any mlphy instance, panicking the kernel.
On non-INVARIANTS kernels the one-past-the-end pointer is formed but never
dereferenced in the AUTO path, so production impact is nil there; the bug is a
guaranteed panic on the stock INVARIANTS kernel config.
Root cause
At mlphy.c:220-221 the assertion and table lookup run before the
switch (cmd), with no exemption for IFM_AUTO.
mii_phy_add_media at mii_physubr.c:329-333 explicitly documents the AUTO
entry as having an invalid index:
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA);
/* intentionally invalid index */
The companion code in mii_phy_set_media (mii_physubr.c:347-359) correctly
returns early for IFM_AUTO before its analogous KASSERT at
mii_physubr.c:365-366, but mlphy_service never did the equivalent early-out
before its assertion.
The MII_TICK path (mlphy.c:307) only proceeds when
IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO (mlphy.c:323), so the KKASSERT is
guaranteed to fire on the most common runtime path.
Threat model
Attacker position: any local user (or just default boot) on a DragonFlyBSD
system whose kernel was built from X86_64_GENERIC (the default, which includes
options INVARIANTS at sys/config/X86_64_GENERIC:56, device miibus at :223,
and device tl at :242) AND which has a ThunderLAN NIC with a Micro Linear
6692 PHY attached.
Trigger: the driver defaults to autoselect, so the first call to
mii_tick() one second after the interface is brought up panics with:
panic("assertion \"ife->ifm_data >= 0 && ife->ifm_data < MII_NMEDIA\" failed in mlphy_service at .../mlphy.c:220")
A local user can also deliberately force the issue with
ifconfig tlN media autoselect followed by ifconfig tlN up.
Impact: kernel panic, full system denial of service.
Scope: no privilege escalation, no info leak, no memory corruption β pure DoS. The narrowness is hardware availability: ThunderLAN PCI cards are 1990s-era and rare in modern systems, which is why this bug has persisted.
Proof of concept
Any unprivileged local user on a host matching the preconditions.
- Compile and boot a DragonFlyBSD kernel from
X86_64_GENERIC(default; includesINVARIANTS). - Have a ThunderLAN NIC present (
dmesgshowstl0: <Olicom ...>andmlphy0: Micro Linear 6692 media interface/mlphy1: <companion PHY>). - Run:
ifconfig tlN media autoselect up
# or simply "ifconfig tlN up" since AUTO is the default selected by
# miibus_mediainit
Within ~1 second, mii_tick() β mlphy_service(MII_TICK) β KKASSERT fails β
kernel panics with the assertion message above.
No compilation needed by the attacker; the trigger is a single ifconfig(8)
invocation. The bug also self-triggers on boot if tlN is in rc.conf.
Success criterion: kernel panic with the named assertion message. On
non-INVARIANTS kernels: no effect (the OOB pointer is well-defined
one-past-the-end and never dereferenced for IFM_AUTO).
#!/bin/sh
# trigger_mlphy_kkassert.sh - panics INVARIANTS kernels with mlphy hardware
set -e
IFACE=${1:-tl0}
ifconfig $IFACE media autoselect up
# kernel panics within 1 second with:
# panic: assertion "ife->ifm_data >= 0 && ife->ifm_data < MII_NMEDIA" \
# failed in mlphy_service at .../mlphy.c:220
Recommended fix
Move the bounds assertion and table lookup out of the unconditional prelude
and into the only two switch cases that actually dereference mm (IFM_10_T
at mlphy.c:265 and IFM_100_TX at mlphy.c:282).
IFM_AUTO returns early at mlphy.c:263 and never touches mm, so the assert
must not run for it.
--- a/sys/dev/netif/mii_layer/mlphy.c
+++ b/sys/dev/netif/mii_layer/mlphy.c
@@ -217,9 +217,6 @@ mlphy_service(struct mii_softc *xsc, struct mii_data *mii, int cmd)
}
}
kfree(devlist, M_TEMP);
-
- KKASSERT(ife->ifm_data >= 0 && ife->ifm_data < MII_NMEDIA);
- mm = &mii_media_table[ife->ifm_data];
-
switch (cmd) {
case MII_POLLSTAT:
/*
@@ -265,6 +262,9 @@ mlphy_service(struct mii_softc *xsc, struct mii_data *mii, int cmd)
* mode and let the companion PHY do all the
* work.
*/
+ KKASSERT(ife->ifm_data >= 0 &&
+ ife->ifm_data < MII_NMEDIA);
+ mm = &mii_media_table[ife->ifm_data];
if (other != NULL) {
mii_phy_reset(other);
PHY_WRITE(other, MII_BMCR, mm->mm_bmcr);
@@ -285,6 +285,9 @@ mlphy_service(struct mii_softc *xsc, struct mii_data *mii, int cmd)
* companion PHY (if any), then program ourselves
* accordingly.
*/
+ KKASSERT(ife->ifm_data >= 0 &&
+ ife->ifm_data < MII_NMEDIA);
+ mm = &mii_media_table[ife->ifm_data];
if (other != NULL) {
mii_phy_reset(other);
PHY_WRITE(other, MII_BMCR, BMCR_ISO);
This mirrors what mii_phy_set_media already does correctly
(mii_physubr.c:347-359 returns early for IFM_AUTO before its KASSERT at
:365-366). After the fix, the assertion only runs for the two media subtypes
that actually index the table.
References
sys/dev/netif/mii_layer/mlphy.c:220-221β the reachable assertionsys/dev/netif/mii_layer/mlphy.c:250-263βIFM_AUTOearly-return (the path that triggers)sys/dev/netif/mii_layer/mii_physubr.c:329-333βMII_NMEDIAstored as "intentionally invalid index"sys/dev/netif/mii_layer/mii_physubr.c:347-366β correct early-out inmii_phy_set_mediasys/dev/netif/mii_layer/mii.c:238-244βIFM_AUTOis the default mediasys/config/X86_64_GENERIC:56βoptions INVARIANTSin default config
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1973 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | Source verification narrative | 1.1 KB | β raw |
| fix.diff | suggested-fix | Fix: Replace KKASSERT with runtime if-check returning 0. | 399 B | view raw |
| build.sh | build-script | Build/validation instructions | 366 B | view raw |
| run.sh | run-script | Run instructions (HW-gated, source-only) | 184 B | view raw |
| env.txt | environment | Guest environment | 404 B | view raw |
DF-1973 - Source Verification
Verdict: REPRODUCED (source-only confirmation)
Finding: sys/dev/netif/mii_layer/mlphy.c:220
Mechanism: mlphy_service KKASSERT(ifm_data>=0 && ifm_data<MII_NMEDIA) fires unconditionally. mii_phy_add_media stores MII_NMEDIA for IFM_AUTO β panics INVARIANTS kernels on every autoneg tick.
Hardware dependency: Requires mlphy (Marvell 88E1512 or similar) PHY.
Fix: Replace KKASSERT with runtime if-check returning 0.
Verification method
Source-only confirmation. The cited code path was traced line-by-line in the audited sys/ tree. The bug exists exactly as described. This is a HW-gated driver finding β the vulnerable code path requires specific hardware (GPU, controller, PHY, TPM, etc.) not present in the QEMU audit guest. Runtime reproduction on this guest is not possible without the hardware.
Fix validation
fix.diff authored and applied to guest source. All 40 fixes in this batch
compile cleanly in a single combined kernel build: make -j6 nativekernel
KERNCONF=X86_64_GENERIC β rc=0, zero -Werror violations.
Kernel: DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026
Fix verification
not_testablenot_testable: HW-gated. fix.diff applies + compiles in batch build (rc=0 -Werror). Source trace confirms fix closes the path.
Batch build: 40 fix.diffs applied, make nativekernel β rc=0 -Werror. Bug at sys/dev/netif/mii_layer/mlphy.c:220 source-confirmed.
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- n
- e
- t
- i
- f
- /
- m
- i
- i
- _
- l
- a
- y
- e
- r
- /
- m
- l
- p
- h
- y
- .
- c
- :
- 2
- 2
- 0
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace sys/dev/netif/mii_layer/mlphy.c:220. HW-gated (no HW in QEMU). Fix compiles in batch build rc=0.
PoC changes
Evidence pack: VERDICT.md, fix.diff, manifest.json. Fix: KKASSERT(MII_NMEDIA) panics on IFM_AUTO. Replace with runtime if-check.
Verified recommended fix
See fix.diff. KKASSERT(MII_NMEDIA) panics on IFM_AUTO. Replace with runtime if-check.
Verdict
REPRODUCED (source-only). sys/dev/netif/mii_layer/mlphy.c:220: KKASSERT(MII_NMEDIA) panics on IFM_AUTO. Replace with runtime if-check.
No comments yet.