DF-0220 / zero_scan.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 | /* * DF-0220 boot-window scanner (unprivileged). * * The finding claims an unprivileged user can observe the deterministic * pre-reseed csprng output ("zero key window") via /dev/urandom, getrandom(2) * and the kern.random sysctl (CTLFLAG_ANYBODY). This tool samples all three * interfaces as hard as possible for a configurable time (default 15 s), * counting all-zero 32-byte blocks, which is the degenerate pre-reseed * csprng contribution in rand_mode=csprng. (In the default mixed mode the * csprng contribution is XORed with IBAA, so a zero csprng block would NOT * show as zero bytes; the manufactured-window experiment in * csprng_force_zero.c covers that case with kmem introspection.) * * Run as the unprivileged user, as early after boot as possible. * * Build: cc -O2 -o zero_scan zero_scan.c * Run: ./zero_scan [seconds=15] */ #include <sys/types.h> #include <sys/sysctl.h> #include <sys/time.h> #include <sys/random.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BLK 32 static double uptime_sec(void) { struct timespec ts; if (clock_gettime(CLOCK_UPTIME, &ts) == 0) return ts.tv_sec + ts.tv_nsec / 1e9; return -1.0; } static int allzero(const unsigned char *b, int n) { int i; for (i = 0; i < n; i++) if (b[i]) return 0; return 1; } int main(int argc, char **argv) { double secs = 15.0, t0; unsigned char buf[BLK]; long n_ur = 0, n_gr = 0, n_kr = 0, z_ur = 0, z_gr = 0, z_kr = 0; int fd; ssize_t r; if (argc > 1) secs = atof(argv[1]); if (secs <= 0) secs = 15.0; fd = open("/dev/urandom", O_RDONLY); if (fd < 0) { perror("open /dev/urandom"); return 1; } printf("zero_scan: sampling %d-byte blocks for %.1f s " "(uid=%d, uptime_at_start=%.3f)\n", BLK, secs, getuid(), uptime_sec()); t0 = uptime_sec(); while (uptime_sec() - t0 < secs) { r = read(fd, buf, BLK); if (r == BLK) { n_ur++; if (allzero(buf, BLK)) z_ur++; } memset(buf, 0xa5, BLK); r = getrandom(buf, BLK, 0); if (r == BLK) { n_gr++; if (allzero(buf, BLK)) z_gr++; } { size_t sz = BLK; memset(buf, 0x5a, BLK); if (sysctlbyname("kern.random", buf, &sz, NULL, 0) == 0 && sz == BLK) { n_kr++; if (allzero(buf, BLK)) z_kr++; } } usleep(20000); } printf("samples: /dev/urandom=%ld getrandom=%ld kern.random=%ld\n", n_ur, n_gr, n_kr); printf("all-zero blocks: /dev/urandom=%ld getrandom=%ld kern.random=%ld\n", z_ur, z_gr, z_kr); printf("uptime_at_end=%.3f\n", uptime_sec()); if (z_ur == 0 && z_gr == 0 && z_kr == 0) printf("RESULT: NO zero block observed on any interface\n"); else printf("RESULT: ZERO BLOCKS OBSERVED (window caught?)\n"); return 0; } |