# DF-5009 — rlphy_service() entry KASSERT panics stock GENERIC kernels on multi-PHY MII buses

## What

`rlphy_service()` opens with

```c
KASSERT(IFM_INST(ife->ifm_media) == sc->mii_inst,
    ("rlphy_service: can't isolate RealTek PHY"));   /* rlphy.c:200-201 */
```

before the `switch (cmd)`, i.e. for MII_MEDIACHG, MII_TICK **and**
MII_POLLSTAT alike.  The miibus dispatch routines call **every** PHY's
service routine with the one **shared** `mii->mii_media.ifm_cur`
(mii.c:309-318, 330-333, 346-348).  rlphy enforces instance 0 for
*itself* at attach (rlphy.c:145-148) but nothing stops a *different*
PHY driver from attaching afterwards as instance 1 (miibus_probe creates
a child for every address with media bits in BMSR, mii.c:138-162).
When the currently selected media belongs to that sibling instance, the
KASSERT fires — on any INVARIANTS kernel, which the default
X86_64_GENERIC config is (sys/config/X86_64_GENERIC:56).

Sibling selection is reachable in two ways:
* the operator selects a media word **unique to the sibling** (combo
  boards: fiber PHY with 1000SX, T4-capable PHY, …).  Note
  `ifmedia_match()` treats the instance field as don't-care
  (ifm_mask seeded with IFM_IMASK at miibus_attach, mii.c:180;
  if_media.c:393-413), so an instance-1 word is only selectable when no
  first-PHY entry shares its subtype — exactly the unique-subtype case.
* the default `ifmedia_set()` in `miibus_mediainit()` (mii.c:238-244)
  stays with instance 0, so plain autoselect does NOT trigger; the
  sibling must be selected explicitly.

After the selection the panic recurs automatically once per second
(MII_TICK from the MAC watchdog) and on every unprivileged
`SIOCGIFMEDIA` (ifconfig read → mii_pollstat → MII_POLLSTAT).

## Reproduced

Stock `X86_64_GENERIC` guest (DragonFly 6.5-DEVELOPMENT, built
2026-07-02).  A synthetic out-of-tree KLD ("fakemic") manufactures the
dual-PHY hardware precondition: canned MII register image with a
RealTek RTL8201L at address 0 (→ rlphy, instance 0) and an
unknown-vendor PHY at address 1 (→ ukphy, instance 1) that additionally
advertises 100baseT4 (a subtype rlphy never adds).  `sysctl -w
kern.fakemic_arm=1` emulates `ifconfig fakemic0 media 100baseT4` (the
sibling's unique word) and then invokes the watchdog `mii_tick()`:

```
panic: rlphy_service: can't isolate RealTek PHY
rlphy_service() at rlphy_service+0x29e
mii_tick() at mii_tick+0x3a
fakemic_arm_sysctl() at ...
sysctl_root ...
```

Full serial-console capture in `panic.txt`; procedure in `run.log` /
`run.sh`.  The KLD substitutes ~30 lines of register-canning for the
(rare, unemulatable) physical dual-PHY board; everything from
`mii_phy_probe()` down is the real in-kernel mii/rlphy/ukphy stack.

## Fix validated

`fix.diff` replaces the KASSERT with the standard foreign-instance guard
(the same shape as ukphy.c:200-202 and xmphy.c:171-184/225-227):
`if (IFM_INST(ife->ifm_media) != sc->mii_inst) return (0);`
Built as a kernel (`make nativekernel`), installed, rebooted, identical
trigger re-run: no panic, `mii_tick survived`, guest healthy
(`run.fixed.log`).

## Severity

Low — kernel DoS (panic), requires an rlphy-compatible PHY co-resident
with a second PHY on one MII bus (RTL8201L / ICPLUS IP101 combo boards,
8129 cards with dual PHYs) plus an operator selecting the sibling's
unique media.  Same family and mechanism class as DF-1973 (mlphy).
CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H (4.5).

## Contents

* `fakemic.c`, `Makefile` — synthetic dual-PHY MII MAC KLD (the PoC)
* `build.sh` / `run.sh` — exact commands
* `build.log` — module build output
* `run.log` — baseline (stock kernel) transcript → panic
* `run.fixed.log` — patched kernel transcript → survives
* `panic.txt` — serial console capture of the panic + backtrace
* `env.txt` — guest/kernel/compiler info
* `fix.diff` — the verified one-hunk fix

## 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.
