DF-5766 / csprng_dump.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 | /* * csprng_dump.c — live introspection of the kernel Fortuna states (DF-5766 PoC) * * Reads csprng_pcpu[] out of /dev/kmem (symbols from the installed kernel's * symtab; struct offsets from kernel.debug DWARF, see VERDICT.md) and dumps * each per-CPU csprng_state: reseed_cnt, pool[i].bytes, nrandevents, * last_reseed and the current ChaCha key. "poll" mode watches reseed_cnt. * * Run as root. Not a KLD: static kernel symbols cannot be linked by a module, * but are readable via /dev/kmem. */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #include <stdint.h> #include <sys/time.h> #define PCPU_SYM 0xffffffff81199140UL /* nm /boot/kernel/kernel: csprng_pcpu */ #define OFF_KEY 0 #define OFF_RCNT 32 #define OFF_POOL 104 #define POOL_STRIDE 112 #define OFF_NEV 4240 #define OFF_LAST 4256 static int kd; static int rd(uint64_t addr, void *buf, size_t len) { if (pread(kd, buf, len, (off_t)addr) != (ssize_t)len) { perror("pread kmem"); return -1; } return 0; } static void dump_one(uint64_t addr, int idx) { uint8_t st[6656]; uint64_t rc, pb[32], nev, tv[2]; uint8_t key[32]; int i; if (rd(addr, st, sizeof(st)) < 0) exit(1); memcpy(key, st + OFF_KEY, 32); memcpy(&rc, st + OFF_RCNT, 8); for (i = 0; i < 32; i++) memcpy(&pb[i], st + OFF_POOL + POOL_STRIDE * i, 8); memcpy(&nev, st + OFF_NEV, 8); memcpy(tv, st + OFF_LAST, 16); printf("state[%d] @%#llx: reseed_cnt=%llu pool0=%llu pool1=%llu " "pool2=%llu pool3=%llu nrandevents=%lld last_reseed=%lld.%06lld\n", idx, (unsigned long long)addr, (unsigned long long)rc, (unsigned long long)pb[0], (unsigned long long)pb[1], (unsigned long long)pb[2], (unsigned long long)pb[3], (long long)nev, (long long)tv[0], (long long)tv[1]); printf(" key="); for (i = 0; i < 32; i++) printf("%02x", key[i]); printf("\n pools:"); for (i = 0; i < 32; i++) printf(" %llu", (unsigned long long)pb[i]); printf("\n"); } int main(int argc, char **argv) { uint64_t base; int ncpu = 6, i; kd = open("/dev/kmem", O_RDONLY); if (kd < 0) { perror("open /dev/kmem"); return 1; } if (argc > 1 && strcmp(argv[1], "poll") == 0) { double secs = argc > 2 ? atof(argv[2]) : 30.0; uint64_t prev[64], now; struct timeval t0, t; int events = 0; if (rd(PCPU_SYM, &base, 8) < 0) return 1; for (i = 0; i < ncpu; i++) { prev[i] = 0; rd(base + 6656ULL * i + OFF_RCNT, &prev[i], 8); } gettimeofday(&t0, NULL); printf("poll %.1fs: initial reseed_cnt:", secs); for (i = 0; i < ncpu; i++) printf(" %llu", (unsigned long long)prev[i]); printf("\n"); for (;;) { usleep(50000); gettimeofday(&t, NULL); double el = (t.tv_sec - t0.tv_sec) + (t.tv_usec - t0.tv_usec) / 1e6; if (el > secs) break; for (i = 0; i < ncpu; i++) { rd(base + 6656ULL * i + OFF_RCNT, &now, 8); if (now != prev[i]) { prev[i] = now; events++; printf("t=%7.3f cpu%d reseed_cnt -> %llu\n", el, i, (unsigned long long)now); } } } printf("reseed transitions observed in window: %d\n", events); return 0; } if (rd(PCPU_SYM, &base, 8) < 0) return 1; printf("csprng_pcpu = %#llx (ncpu=%d)\n", (unsigned long long)base, ncpu); for (i = 0; i < ncpu; i++) dump_one(base + 6656ULL * i, i); return 0; } |