DF-5516 / ub5516attachstall_harness.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 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | /* * DF-5516 KLD harness -- production-code demonstration that * ubser_attach()'s GET_NUMSER vendor request pins the per-bus USB * explore (hub event) thread for the full USB_DEFAULT_TIMEOUT = 5000 ms * (usbdi.h:87) at every insertion of an evil BWCT-branded adapter. * * Evidence class: DF-5488/DF-5505 verbatim extraction. build.sh * sed-extracts ubser.c:242-262 (the "get number of serials" block of * ubser_attach) UNMODIFIED from the guest's md5-gated /usr/src tree * into ub5516_block.c; this module includes that fragment inside the * simulated attach. The only modeled pieces are the EP0 sink * (usbd_do_request_flags interposed) and device_printf. The fragment's * `goto detach' (ubser.c:257) binds to the local `detach:' label, which * stands in for the production label at ubser.c:296 (ubser_detach + * return ENXIO). * * REACHABILITY: ubser_probe (ubser.c:206-221) matches on * - usb_get_manufacturer(uaa->device) == "BWCT" (device string * descriptor -- attacker-controlled firmware), * - bInterfaceClass == 0xff, bInterfaceSubClass == 0x00 * so an evil adapter needs only a 4-byte manufacturer string and a * vendor-specific interface descriptor to be handed to ubser_attach. * GET_NUMSER is the FIRST thing attach does with the device * (ubser.c:242-251), synchronously, on the attaching thread -- the * per-bus USB explore thread that is enumerating every other device on * that bus (family mechanism, DF-5359/DF-5407/DF-5488/DF-5505). * * PHASE A silent evil device (NAKs the data stage until timeout): * the verbatim block sleeps the full 5000 ms in the "WXFER" * wait, gets USB_ERR_TIMEOUT, prints the verbatim error via * the verbatim usbd_errstr() call, and takes the verbatim * `goto detach' abort. EXPECT explore-thread occupancy * ~= 5000 ms, attach ABORT. * PHASE B slow-answer evil device (answers at 4900 ms, numser=4): * the request SUCCEEDS -- no error is visible anywhere in the * driver -- and attach CONTINUES (verbatim "found 4 serials"). * EXPECT occupancy ~= 4900 ms, attach CONTINUES (honest worst * case: an evil device need not fail anything). * PHASE C fixed build only (fix.diff: USB_DEFAULT_TIMEOUT -> 1000 at * ubser.c:251): EXPECT occupancy ~= 1000 ms fail-fast. * See run.fixed.log. */ #include <sys/param.h> #include <sys/types.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> #include <sys/lock.h> #include <sys/time.h> #include <machine/stdarg.h> #include <bus/u4b/usb.h> #include <bus/u4b/usbdi.h> MODULE_DEPEND(ub5516attach, usb, 1, 1, 1); MODULE_DEPEND(ub5516attach, ucom, 1, 1, 1); /* * Modeled EP0 sink. Signature must match usbdi.h:508-510 exactly * (the verbatim fragment calls it through that prototype). */ static int ub_evil_mode; /* 0 = silent, 1 = slow-answer */ static char ub_wchan[16]; usb_error_t usbd_do_request_flags(struct usb_device *udev, struct lock *lock, struct usb_device_request *req, void *data, uint16_t flags, uint16_t *actlen, usb_timeout_t timeout) { int ms = (int)timeout; kprintf("UB5516: EP0 bRequest=0x%02x wLength=%d (%d ms timeout): " "device %s\n", req->bRequest, UGETW(req->wLength), ms, ub_evil_mode ? "answers at just-under-timeout" : "silent -- NAKs until timeout"); if (ub_evil_mode) { tsleep(&ub_wchan, 0, "WXFER", USB_MS_TO_TICKS(ms - 100)); if (data != NULL) *(uint8_t *)data = 4; /* claims 4 serial ports */ return (USB_ERR_NORMAL_COMPLETION); } /* production passes lock == NULL here (ubser.c:249-251), so the * model plain-sleeps like the core requester does without a lock */ tsleep(&ub_wchan, 0, "WXFER", USB_MS_TO_TICKS(ms)); return (USB_ERR_TIMEOUT); } /* device_printf model (the verbatim block calls it at ubser.c:254/262) */ int device_printf(device_t dev, const char *fmt, ...) { __va_list ap; kprintf("UB5516 DEV: "); __va_start(ap, fmt); kvprintf(fmt, ap); __va_end(ap); return (0); } static int64_t ub_ms(struct timeval *t0, struct timeval *t1) { return ((int64_t)(t1->tv_sec - t0->tv_sec) * 1000 + (t1->tv_usec - t0->tv_usec) / 1000); } /* * The verbatim block needs `sc', `uaa', `req', `error', `dev' and the * VENDOR_GET_NUMSER / UT_READ_VENDOR_INTERFACE / USETW / UBSER_UNIT_MAX * definitions -- all provided by including the production file * (registration neutered), exactly like the DF-5447 rig. */ #undef DRIVER_MODULE #undef DRIVER_MODULE_ORDERED #undef MODULE_DEPEND #undef MODULE_VERSION #define DRIVER_MODULE(name, busname, driver, devclass, evh, arg) #define DRIVER_MODULE_ORDERED(name, busname, driver, devclass, evh, arg, order) #define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) #define MODULE_VERSION(module, version) #include "../ubser.c" static struct ubser_softc ub_sc; static struct usb_attach_arg ub_uaa; static int ub_devident; static device_t ub_dev = (device_t)&ub_devident; /* printf is modeled */ static void ub_touch_statics(void) { if (ubser_devclass != NULL) kprintf("UB5516: unexpected devclass %p\n", ubser_devclass); kprintf("UB5516: production driver \"%s\" compiled into harness " "(registration neutered)\n", ubser_driver.name); } static void ub_simulate_attach(char tag, int evil_mode) { struct timeval t0, t1; struct usb_device_request req; int error; ub_evil_mode = evil_mode; memset(&ub_sc, 0, sizeof(ub_sc)); memset(&ub_uaa, 0, sizeof(ub_uaa)); ub_uaa.info.bIfaceNum = 0; ub_uaa.device = (void *)&ub_wchan; /* model sink ignores it */ { /* local aliases exactly as ubser_attach declares them * (ubser.c:226-230) */ struct usb_attach_arg *uaa = &ub_uaa; struct ubser_softc *sc = &ub_sc; device_t dev = ub_dev; sc->sc_iface_no = uaa->info.bIfaceNum; microtime(&t0); kprintf("UB5516[%c]: --- insertion: ubser_attach runs on the " "per-bus USB explore thread, GET_NUMSER first " "(ubser.c:242-251) --- (t=0)\n", tag); /* THE VERBATIM PRODUCTION BLOCK, extracted by build.sh from * ubser.c:242-262 of the md5-gated guest tree. Its `goto detach' * binds to the local label below, which stands in for the production * label at ubser.c:296-298 (ubser_detach(dev); return ENXIO). */ #include "ub5516_block.c" /* success fall-through: production continues into * usbd_transfer_setup (ubser.c:264) */ microtime(&t1); kprintf("UB5516[%c]: explore-thread occupancy %jd ms; attach " "CONTINUES past the block (usbd_transfer_setup next, " "ubser.c:264)\n", tag, (intmax_t)ub_ms(&t0, &t1)); goto out; detach: microtime(&t1); kprintf("UB5516[%c]: explore-thread occupancy %jd ms; attach " "ABORT via verbatim `goto detach' (production target " "ubser.c:296-298: ubser_detach + ENXIO)\n", tag, (intmax_t)ub_ms(&t0, &t1)); out: ; } } static int ub_modevent(module_t mod, int type, void *data) { int error = 0; switch (type) { case MOD_LOAD: kprintf("UB5516: DF-5516 ubser attach-pin harness " "(USB_DEFAULT_TIMEOUT=%d ms, usbdi.h:87)\n", USB_DEFAULT_TIMEOUT); ub_touch_statics(); ub_simulate_attach('A', 0); /* silent evil: full 5 s */ ub_simulate_attach('B', 1); /* slow answer: 4.9 s, success */ kprintf("UB5516: harness complete (phase C = fixed build " "rerun, see run.fixed.log)\n"); break; case MOD_UNLOAD: break; default: error = EOPNOTSUPP; break; } return (error); } static moduledata_t ub_mod = { "ub5516attach", ub_modevent, 0 }; DECLARE_MODULE(ub5516attach, ub_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |