DF-5640 / df5640.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 | /* * DF-5640 — harness for the unvalidated tsc_frequency division in * tsc_cputimer_register(). * * sys/cpu/x86_64/misc/cputimer_tsc.c:145-156 does: * * freq = tsc_frequency; // hardware/calibration-derived, unvalidated * tsc_cputimer.freq = freq; * kprintf("TSC: cputimer freq %ju\n", (uintmax_t)freq); * ... * cputimer_register(&tsc_cputimer); * cputimer_select(&tsc_cputimer, 0); * * and kern/kern_cputimer.c:99 unconditionally calls * cputimer_set_frequency(timer, timer->freq), which computes * * timer->freq64_usec = (1000000LL << 32) / freq; // :190 #DE if freq==0 * timer->freq64_nsec = (1000000000LL << 32) / freq; // :191 * * NOTE on methodology: a boot-loaded KLD cannot put the kernel globals into * the finding's precondition state before tsc_cputimer_register runs, because * preloaded modules are linked at SI_BOOT2_KLD (0x1e00000), which is AFTER * SI_BOOT2_POST_SMP (0x1cc0000). This was established empirically: a forcing * SYSINIT at SI_BOOT2_FINISH_SMP from a loader-loaded module executed after * the whole timer-registration pass (dmesg ordering, see VERDICT.md). * Therefore this harness REPLAYS the body of tsc_cputimer_register() * (cputimer_tsc.c:137-156) verbatim at kldload time, using the real * cputimer_register()/cputimer_select() production entry points, on a * replica struct with freq = 0 (the value tsc_frequency has when * startrtclock()'s calibration fails, clock.c:980-1043, combined with * tsc_mpsync forced to 1 -- hw.tsc_cputimer_force tunable, clock.c:871/1522, * or the ncpus==1 early-out at clock.c:1513-1516). * * The replica uses pri = CPUTIMER_PRI_DUMMY-1 so that, on a kernel where the * division is guarded, cputimer_select() would not install it as sys_cputimer * (the pri check at kern_cputimer.c:106 rejects it). The division at * kern_cputimer.c:99 happens BEFORE that check, so the unpatched kernel * divides by zero regardless. * * Expected result: * unpatched kernel: "DF5640: replaying ..." then * Fatal trap 6: divide error while in kernel mode -> panic * patched kernel (fix.diff): warning, module loads, system keeps running. */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/systm.h> #include <sys/systimer.h> #include <machine/cpufunc.h> #include <machine/clock.h> /* tsc_frequency, tsc_mpsync, tsc_invariant */ static sysclock_t df5640_count(void); /* Replica of tsc_cputimer (cputimer_tsc.c:55-66), freq=0 variant. */ static struct cputimer df5640_timer = { .name = "DF5640", .pri = CPUTIMER_PRI_DUMMY - 1, /* never selected */ .type = CPUTIMER_TSC, .count = df5640_count, .fromhz = cputimer_default_fromhz, .fromus = cputimer_default_fromus, .construct = cputimer_default_construct, .destruct = cputimer_default_destruct, .freq = 0, /* == tsc_frequency (failed cal.) */ }; static sysclock_t df5640_count(void) { return (rdtsc() + df5640_timer.base); } static int df5640_modevent(module_t mod __unused, int type, void *data __unused) { uint64_t freq; switch (type) { case MOD_LOAD: kprintf("DF5640: live state: tsc_mpsync=%d tsc_invariant=%d " "tsc_frequency=%ju sys_cputimer=%s (%ju Hz)\n", tsc_mpsync, tsc_invariant, (uintmax_t)tsc_frequency, sys_cputimer->name, (uintmax_t)sys_cputimer->freq); /* * --- verbatim replay of tsc_cputimer_register(), * --- cputimer_tsc.c:145-156, with tsc_frequency == 0. */ tsc_mpsync = 1; /* the finding's precondition, as if */ tsc_frequency = 0; /* hw.tsc_cputimer_force=1 w/ failed */ /* calibration (or UP + invariant) */ freq = tsc_frequency; df5640_timer.freq = freq; kprintf("DF5640: replaying cputimer_tsc.c:145-156 with " "freq=0 (divide error at kern_cputimer.c:190 expected)\n"); kprintf("TSC: cputimer freq %ju\n", (uintmax_t)freq); cputimer_register(&df5640_timer); /* cputimer_tsc.c:155 */ cputimer_select(&df5640_timer, 0); /* cputimer_tsc.c:156 */ kprintf("DF5640: NOT REACHED on an unpatched kernel\n"); return (0); default: return (EOPNOTSUPP); } } static moduledata_t df5640_mod = { "df5640", df5640_modevent, NULL }; DECLARE_MODULE(df5640, df5640_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); |