urndis(4) attach-failure paths call urndis_detach() on a never-attached usb_ether β deterministic kernel panic (lockmgr of NULL, fault VA 0) from plugging a malicious RNDIS device
Summary
Fourth member of the DF-5334/5384/5395 uether class: every attach failure goto runs the full detach with ue_lock/ue_methods unassigned and uether_ifattach never run - uether_getifp returns the embedded never-NULL ifnet so UE_LOCK lockmgr(NULL)s: Fatal trap 12 VA 0. Reproduced 4x deterministically with the malformed-descriptor and rejected-MAC-query device variants (crash dump taken; boot-time variant bricks the boot); detach-only-what-was-set fix validated (attach returned 6, guest up, valid device still attaches).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5397 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.7 KB | β raw | |
| VERDICT.md | β | 2.7 KB | β raw | |
| fix.diff | β | 937 B | view raw | |
| panic.txt | β | 13.1 KB | view raw | |
| run.serial-baseline-panic-usbdebug.log | β | 17.4 KB | view raw | |
| run.serial-baseline-panic2.log | β | 20.8 KB | view raw | |
| run.serial-patched-clean.log | β | 29.5 KB | view raw |
DF-5397 β urndis(4) attach-failure paths call urndis_detach() on a
never-attached usb_ether -> deterministic kernel panic (lockmgr NULL)
What
sys/bus/u4b/net/if_urndis.c β urndis_attach() failure paths
(if_urndis.c:258-299: "No valid alternate setting found", "Unable to
get hardware address", "Invalid address length", "Unable to set data
filters") jump to:
detach:
urndis_detach(dev); /* if_urndis.c:309-311 */
return (ENXIO);
ue->ue_lock, ue->ue_methods etc. are assigned only at
if_urndis.c:290-294 β after every failure goto β and
uether_ifattach() never ran. urndis_detach() calls
uether_ifdetach(ue); on DragonFly every guard there is dead:
usb_proc_drain()early-returns (zeroedup_lock) β safe;uether_getifp(ue)returns the address of the embeddedue->ue_arpcom.ac_ifβ never NULL β soif (ifp != NULL)passes;UE_LOCK(ue)βlockmgr(ue->ue_lock == NULL)β page fault VA 0.
Identical class to DF-5334 (cdce). An attacker-supplied USB device
(evil RNDIS NIC / tethering dongle β precisely this driver's threat
model) triggers it by making the attach fail once: e.g. malformed
class-specific descriptors so usbd_transfer_setup() finds no usable
alternate setting on the data interface (the exact gadget used here),
or by failing/short-answering the RNDIS MAC query.
Reproduction (baseline, stock if_urndis.ko)
Malformed RNDIS gadget over usb-redir (RNDIS_MALFORMED=1
boot_rig_cold.sh, usbredir_rndis.py with malformed on):
urndis0: <vendor 0x0525 product 0xa4a2, class 2/0, rev 2.00/0.00, addr 2> on usbus0 urndis0: No valid alternate setting found Fatal trap 12: page fault while in kernel mode fault virtual address = 0x0 Stopped at lockmgr_exclusive+0x5d: orl (%r14),%esi lockmgr_exclusive() at lockmgr_exclusive+0x5d uether_ifdetach() at uether_ifdetach+0x2f urndis_detach() at urndis_detach+0x2a urndis_attach() at urndis_attach+0x11d device_doattach() at device_doattach+0x3af usb_probe_and_attach() at usb_probe_and_attach+0x176 uhub_explore() at uhub_explore+0x231 usb_bus_explore() at usb_bus_explore+0xd0 usb_process() at usb_process+0x76
(4 independent reproductions; crash dump taken via call dumpsys.
A second variant β "Unable to get hardware address" when the RNDIS
query response is rejected β panics at urndis_attach+0x13a with the
same teardown, captured in run.serial-baseline-panic-usbdebug.log.)
Fix validation (patched if_urndis.ko, fix.diff)
fix.diff replaces the error-path urndis_detach(dev) with a teardown
of only what was actually initialised (USB transfers + the softc lock).
Same malformed device, patched module:
urndis0: <vendor 0x0525 product 0xa4a2, class 2/0, rev 2.00/0.00, addr 2> on usbus0 urndis0: No valid alternate setting found device_probe_and_attach: urndis0 attach returned 6
Guest stays up (ssh alive, zero Fatal trap in dmesg.boot), attach
retried cleanly, and the unpatched flow of DF-5396 (valid device)
still attaches (ue0: MAC address: 02:00:de:ad:be:ef) β no regression.
Run it
- guest:
mv /boot/kernel/if_cdce.ko /root/(cdce's VPI match on 0525:a4a2 would win probe priority and panic via its own DF-5334 bug first),kldload if_urndis - host:
RNDIS_MALFORMED=1 sh boot_rig_cold.sh(device present at boot, malformed CS descriptors) β or togglemalformed onon the control port and replug. - baseline: panic (above); patched: clean ENXIO, guest survives.
Kernel references
- sys/bus/u4b/net/if_urndis.c:290-294 (ue fields assigned after all failure gotos), :309-311 (goto detach -> urndis_detach)
- sys/bus/u4b/net/usb_ethernet.c:268-314 (uether_ifdetach), :54-56 (URNDIS/UE lock macros), sys/bus/u4b/usb_process.c (drain guard)
- sibling finding DF-5334 (cdce, same class)
DF-5397 VERDICT
Status: reproduced (deterministic kernel panic / local-device DoS via attach-failure path). Fix: validated on the guest.
How reproduced
The malicious usbredir RNDIS device (usbredir_rndis.py from the DF-5396
pack, RNDIS_MALFORMED=1) presents CDC class-specific descriptors whose
walked lengths are one byte too long each, so DF's config parse never
finds the data interface and urndis_attach()\'s alternate-setting loop
fails on every iteration -> "No valid alternate setting found" ->
goto detach -> urndis_detach(dev) -> uether_ifdetach() over the
never-initialised usb_ether -> lockmgr(NULL) -> Fatal trap 12, VA 0.
Four independent baseline reproductions (two descriptor-failure variants:
alt-setting failure and MAC-query rejection), each with the DDB backtrace
naming uether_ifdetach+0x2f <- urndis_detach+0x2a <- urndis_attach, and a
crash dump via call dumpsys. Evidence: panic.txt,
run.serial-baseline-panic-usbdebug.log (USB_DEBUG kernel, annotated),
run.serial-baseline-panic2.log, run.serial-patched-clean.log.
Why not worse than a panic
The faulting pointer is NULL (ue_lock), so the primitive is a denial-of-service at attach time (device plug-in / boot with the evil gadget present). Because the panic happens with preemption state of the usb explore thread and a fully attacker-chosen timing window, it is also a reliability/UX kill: a boot-time evil device bricks the boot (serial DDB, ssh never starts). No memory-corruption primitive was identified in this path (the NULL is dereferenced, not written through).
Fix validation
fix.diff (tear down only usbd transfers + lock, never uether_ifdetach on the un-attached ue) applied on the guest, module rebuilt + installed:
- malformed device replug:
urndis0: No valid alternate setting found+device_probe_and_attach: urndis0 attach returned 6, guest alive, zero Fatal traps. - valid device (regression): full attach + DF-5396 differential ran on the same patched module build (ue0 up, RNDIS data path live).
Notes
- cdce (DF-5334) shares the bug and must be kept from probing first for this driver's PoC (VPI 0525:a4a2 beats urndis's class match).
- FreeBSD's urndis_attach has the same shape; whether FreeBSD's uether_ifdetach is equally unguarded was not verified in this run.
Kernel references
sys/bus/u4b/net/if_urndis.c:290-294, :309-311; sys/bus/u4b/net/usb_ethernet.c:268-314; DF-5334 (cdce sibling).
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
fixedfix.diff applied on guest, module rebuilt+installed: same malformed-device replug prints 'No valid alternate setting found' + 'device_probe_and_attach: urndis0 attach returned 6', guest stays up (ssh alive, zero Fatal traps); regression check with the valid device still attaches (ue0 up, DF-5396 differential ran on the same build).
run.serial-patched-clean.log tail (urndis0 lines + attach returned 6) and live ssh checks recorded in VERDICT.md
Confirmed kernel references
Detail
Exploit chain
DoS only: the faulting pointer is NULL (read-deref in lockmgr), no write primitive identified. A plugged evil gadget or an evil device present at boot kills the kernel/requires hard reset.
Evidence (decisive lines)
panic.txt (Fatal trap 12 VA=0x0 + full DDB trace), run.serial-baseline-panic-usbdebug.log (USB_DEBUG-annotated, urndis0 messages + trace), run.serial-baseline-panic2.log (second variant at urndis_attach+0x13a 'Unable to get hardware address'), run.serial-patched-clean.log ('attach returned 6', guest alive)
PoC changes
No seed; reused the DF-5396 usbredir rig with its malformed-descriptor mode (RNDIS_MALFORMED=1 / 'malformed on' control command) which reproduces the exact alt-setting-loop failure. cdce must be prevented from probing first (its VPI match on 0525:a4a2 wins priority and panics via its own DF-5334 bug).
Verified recommended fix
On urndis_attach error paths, tear down only usbd_transfer_unsetup + lockuninit; never call urndis_detach()/uether_ifdetach() before uether_ifattach() succeeded
Verdict
Reproduced deterministically (4 independent runs, 2 variants). urndis_attach() failure paths goto a label that calls urndis_detach(), which drives uether_ifdetach() over a never-initialised usb_ether: ue_lock is assigned only after the last failure goto and uether_ifattach never ran, while uether_getifp() on DragonFly returns the embedded (never-NULL) ac_if - so lockmgr(NULL) faults at VA 0. Triggered by a malicious RNDIS gadget whose descriptors fail the alternate-setting loop (or whose MAC query response is rejected); DDB backtrace: lockmgr_exclusive <- uether_ifdetach+0x2f <- urndis_detach+0x2a <- urndis_attach+0x11d <- usb_probe_and_attach <- uhub_explore. Boot-time variant bricks the boot. fix.diff (teardown only transfers+lock on the error path) validated: attach returns ENXIO cleanly, guest survives, valid-device attach unaffected.
No comments yet.