DF-5486 / cue_attach_poc.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | /* * DF-5486 PoC harness โ if_cue.c attach-failure DF-5334-class panic. * * Target: sys/bus/u4b/net/if_cue.c cue_attach() failure branches: * * 402: lockinit(&sc->sc_lock, device_get_nameunit(dev), 0, LK_CANRECURSE); * 404: iface_index = CUE_IFACE_IDX; * 405: error = usbd_transfer_setup(uaa->device, &iface_index, * 406: sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_lock); * 407: if (error) { * 408: device_printf(dev, "allocating USB transfers failed\n"); * 409: goto detach; * 410: } * ... * 418: error = uether_ifattach(ue); * 419: if (error) { * 420: device_printf(dev, "could not attach interface\n"); * 421: goto detach; * 422: } * 423: return (0); [success] * * 425: detach: * 426: cue_detach(dev); * 427: return (ENXIO); [failure] * * cue_detach() (if_cue.c:430-441) then runs, in order: * * 436: usbd_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); * 437: uether_ifdetach(ue); * * but at this point ue->ue_lock / ue_dev / ue_udev / ue_methods / ue_tq are * still ALL ZERO (they are assigned only at if_cue.c:412-416, AFTER the * failing usbd_transfer_setup()). uether_ifdetach() * (sys/bus/u4b/net/usb_ethernet.c:267-305): * * 273: usb_proc_drain(&ue->ue_tq); <- no-op, up_lock == NULL * 276: ifp = uether_getifp(ue); <- embedded arpcom ifnet, NEVER NULL * 278: if (ifp != NULL) { <- dead guard, always true * 281: UE_LOCK(ue); <- lockmgr(NULL, LK_EXCLUSIVE) * ==> Fatal trap 12, fault VA 0x0 * * The trigger is fully device-controlled: any USB device presenting one of * the 3 VID:PID pairs in cue_devs[] (CATC NETMATE 0x042e:0x5600, * NETMATE2 0x042e:0x5601, SmartBridges SMARTLINK 0x087d:0x5600) at config * index 0 / iface 0 but WITHOUT a bulk-in + bulk-out endpoint pair makes * usbd_transfer_setup() fail (USB_ERR_NO_ENDPOINT / USB_ERR_SETUP) -- an * evil-USB-adapter / evil-dock / VM-attach scenario. * * This KLD replays cue_detach() verbatim on that exact post-failure state * using the production usbd_transfer_unsetup() and uether_ifdetach() * (exported by uether.ko). The only non-production code is the static * cue_attach()/cue_detach() plumbing itself (they are static in if_cue.c, * unreachable without a physical CATC Netmate; the failure branch reaches * them through a plain goto). */ #include <sys/stdint.h> #include <sys/param.h> #include <sys/queue.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/socket.h> #include <sys/kernel.h> #include <sys/bus.h> #include <sys/module.h> #include <sys/lock.h> #include <sys/condvar.h> #include <sys/sysctl.h> #include <sys/unistd.h> #include <sys/callout.h> #include <sys/malloc.h> #include <sys/caps.h> #include <net/if.h> #include <net/if_var.h> #include <bus/u4b/usb.h> #include <bus/u4b/usbdi.h> #include <bus/u4b/usb_process.h> #include <bus/u4b/net/usb_ethernet.h> #include <bus/u4b/net/if_cuereg.h> static int cue_poc_modevent(module_t mod, int type, void *arg) { struct cue_softc *sc; switch (type) { case MOD_LOAD: kprintf("cue_poc: constructing post-'allocating USB transfers " "failed' state (if_cue.c:405-410)\n"); sc = kmalloc(sizeof(*sc), M_TEMP, M_WAITOK | M_ZERO); if (sc == NULL) return (ENOMEM); /* if_cue.c:402: the only softc field initialised before the * failing usbd_transfer_setup() at if_cue.c:405 */ lockinit(&sc->sc_lock, "cue_poc", 0, LK_CANRECURSE); kprintf("cue_poc: state check: ue_lock=%p ue_dev=%p " "ue_udev=%p ue_tq.up_lock=%p (all must be 0/NULL)\n", sc->sc_ue.ue_lock, (void *)sc->sc_ue.ue_dev, sc->sc_ue.ue_udev, sc->sc_ue.ue_tq.up_lock); kprintf("cue_poc: entering cue_detach() replay: " "usbd_transfer_unsetup() + uether_ifdetach() " "(if_cue.c:436-437)\n"); /* if_cue.c:436 โ production code, zeroed xfer array == branch-1 */ usbd_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); /* if_cue.c:437 -> uether_ifdetach() -> UE_LOCK(ue) -> * lockmgr(NULL, LK_EXCLUSIVE) -> Fatal trap 12, VA 0x0 */ uether_ifdetach(&sc->sc_ue); kprintf("cue_poc: SURVIVED uether_ifdetach() (UNEXPECTED โ " "guard present?)\n"); lockuninit(&sc->sc_lock); kfree(sc, M_TEMP); return (0); default: return (0); } } static moduledata_t cue_poc_mod = { "cue_poc", cue_poc_modevent, NULL }; DECLARE_MODULE(cue_poc, cue_poc_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_DEPEND(cue_poc, uether, 1, 1, 1); |