DF-5493 / ue_guard_b.c
/* * DF-5493 PoC harness — BRANCH B (see ue_guard_a.c for branch A). * * Target: sys/bus/u4b/net/usb_ethernet.c uether_ifdetach() (:267-305). * * BRANCH B state = what uether_ifattach() itself leaves on its only * failure, usb_proc_create() ENOMEM (usb_ethernet.c:173-178): * * ue->ue_dev/ue_udev/ue_lock/ue_methods are already set by the * driver (they are checked non-NULL at :167-171 BEFORE anything * happens), but usb_proc_create() failed and fully unwound ue_tq * back to all-zero on its error path (usb_process.c:208-219: on * USB_THREAD_CREATE failure it calls usb_proc_free() which * cv_destroy()s and resets up->up_lock = NULL at :244), and * ue_attach_post_task was never queued (it is queued only at * :181-185 AFTER a successful usb_proc_create), so the embedded * ifnet was never published via ether_ifattach(). * * Every uether driver then does: * * error = uether_ifattach(ue); * if (error) { goto detach; } -> driver_detach() -> * uether_ifdetach(ue) * * (e.g. if_cue.c:418-426) and uether_ifdetach() walks straight into: * * usb_proc_drain(&ue->ue_tq); :273 no-op (up_lock == NULL) * ifp = uether_getifp(ue); :276 embedded, NOT NULL * UE_LOCK(ue); :281 ue_lock IS valid -- passes * ifp->if_flags &= ~IFF_RUNNING; :282 * usb_callout_drain(&ue->ue_watchdog); :286 zeroed callout, passes * ether_ifdetach(ifp); :294 NEVER if_attach()ed -> * if_down()/if_detach() on a * zeroed ifnet -> Fatal trap * sysctl_ctx_free(&ue->ue_sysctl_ctx); :297 never sysctl_ctx_init'ed * devfs_clone_bitmap_put(..., ue->ue_unit); :300 ue_unit==0 never * allocated (would corrupt the * unit bitmap for a live ue0) * * This KLD replays the exact state + the single production call * uether_ifdetach() from the stock uether.ko. */ #include <sys/stdint.h> #include <sys/param.h> #include <sys/queue.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/condvar.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/sysctl.h> #include <bus/u4b/usb.h> #include <bus/u4b/usbdi.h> #include <bus/u4b/usb_process.h> #include <bus/u4b/net/usb_ethernet.h> static struct lock poc_lk; static struct usb_ether *poc_ue; static int ue_guard_b_modevent(module_t mod, int type, void *arg) { switch (type) { case MOD_LOAD: poc_ue = kmalloc(sizeof(*poc_ue), M_TEMP, M_WAITOK | M_ZERO); if (poc_ue == NULL) return (ENOMEM); /* Driver set ue_lock before uether_ifattach() * (usb_ethernet.c:169 requires it non-NULL); * usb_proc_create() then failed and unwound ue_tq * to all-zero (usb_process.c:217-219,244). */ lockinit(&poc_lk, "uegb", 0, 0); poc_ue->ue_lock = &poc_lk; kprintf("ue_guard_b: branch B state: ue_lock valid, ue_tq " "zeroed (uether_ifattach ENOMEM at " "usb_ethernet.c:173-178)\n"); kprintf("ue_guard_b: ue=%p ue_lock=%p ue_tq.up_lock=%p " "(up_lock must be NULL)\n", poc_ue, poc_ue->ue_lock, poc_ue->ue_tq.up_lock); kprintf("ue_guard_b: calling production uether_ifdetach() " "-> ether_ifdetach() on never-if_attach()ed ifnet\n"); uether_ifdetach(poc_ue); kprintf("ue_guard_b: SURVIVED uether_ifdetach() (UNEXPECTED " "-- guard present?)\n"); lockuninit(&poc_lk); kfree(poc_ue, M_TEMP); return (0); default: return (0); } } static moduledata_t ue_guard_b_mod = { "ue_guard_b", ue_guard_b_modevent, NULL }; DECLARE_MODULE(ue_guard_b, ue_guard_b_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); MODULE_DEPEND(ue_guard_b, uether, 1, 1, 1); |