DF-4874 / df4874_detach.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 | /* * DF-4874 PoC โ trigger side: detach the live nata afd0 device while the * raw-I/O storm has the cdev open and is inside / re-enters ad_strategy(). * * sysctl kern.df4874_cycles=4 * sysctl kern.df4874_ms=200 * sysctl kern.df4874_run=1 * * Each cycle: device_detach(afd0) โ the exact ad_detach() path * (ata-disk.c:167-203) that ends in kfree(adp) โ then re-attach via * device_probe_and_attach() so cycles can repeat. * * Expected baseline (bug present): kernel panic on the next post-detach * raw pread โ ad_strategy() fetches adp = device_get_ivars(dev) == NULL * and does devstat_start_transaction(&adp->stats) (ata-disk.c:360), a * write to near-NULL; or ad_done() does devstat_end_transaction_buf on * &((struct ad_softc *)NULL)->stats (ata-disk.c:376). Fatal trap 12. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> #include <sys/malloc.h> #include <sys/sysctl.h> #include <sys/kthread.h> #include <sys/thread2.h> #include <sys/bus.h> static int df4874_run; static int df4874_cycles = 4; static int df4874_ms = 200; static int df4874_last = -999; static int df4874_active; static void df4874_worker(void *arg __unused) { devclass_t dc; device_t dev; int i; dc = devclass_find("afd"); if (dc == NULL) { kprintf("df4874: afd devclass not found (kernel built without afd?)\n"); goto out; } dev = devclass_get_device(dc, 0); if (dev == NULL) { kprintf("df4874: afd0 device_t is NULL\n"); goto out; } for (i = 0; i < df4874_cycles; i++) { kprintf("df4874: cycle %d/%d detaching afd0 (%p)...\n", i + 1, df4874_cycles, dev); df4874_last = device_detach(dev); kprintf("df4874: device_detach -> %d\n", df4874_last); if (df4874_last != 0) break; tsleep(&df4874_worker, 0, "df4874a", (df4874_ms * hz) / 1000); kprintf("df4874: re-attaching afd0...\n"); if (device_probe_and_attach(dev)) { kprintf("df4874: re-attach failed\n"); break; } } out: df4874_run = 0; wakeup(&df4874_run); kthread_exit(); } static int df4874_sysctl_run(SYSCTL_HANDLER_ARGS) { int error, v = df4874_run; error = sysctl_handle_int(oidp, &v, 0, req); if (error != 0 || req->newptr == NULL) return (error); if (v != 0 && df4874_run == 0 && df4874_active == 0) { df4874_run = 1; df4874_active = 1; kthread_create(df4874_worker, NULL, NULL, "df4874w"); } return (0); } static int df4874_load(struct module *m, int what, void *arg __unused) { switch (what) { case MOD_LOAD: kprintf("df4874 detach-trigger loaded " "(kern.df4874_run=1 to go)\n"); break; case MOD_UNLOAD: kprintf("df4874 detach-trigger unloaded\n"); break; } return (0); } static moduledata_t df4874_mod = { "df4874", df4874_load, NULL }; DECLARE_MODULE(df4874, df4874_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); SYSCTL_NODE(_kern, OID_AUTO, df4874, CTLFLAG_RW, 0, "DF-4874 PoC"); SYSCTL_PROC(_kern_df4874, OID_AUTO, run, CTLTYPE_INT | CTLFLAG_RW, 0, 0, df4874_sysctl_run, "I", "start one detach/attach run"); SYSCTL_INT(_kern_df4874, OID_AUTO, cycles, CTLFLAG_RW, &df4874_cycles, 0, "detach cycles"); SYSCTL_INT(_kern_df4874, OID_AUTO, ms, CTLFLAG_RW, &df4874_ms, 0, "ms between detach and re-attach"); SYSCTL_INT(_kern_df4874, OID_AUTO, last, CTLFLAG_RD, &df4874_last, 0, "last device_detach() result"); |