DF-5694 / arc4samp.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 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | /* * arc4samp.c - DragonFly kernel module (KLD) sampling the deployed * sys/libkern/arc4random.c generator from inside the running kernel. * * Evidence class: "KLD in-kernel sampling" for the pass-2 audit of * sys/libkern/arc4random.c. * * Devices: * /dev/arc4s32 - stream of karc4random() words (LE) * /dev/arc4sbuf - stream of karc4random_buf() bytes * /dev/arc4s64 - stream of karc4random64() words (LE) * /dev/arc4srep - one-shot text report: 2^20 karc4random64 draws, * counting draws whose upper 32 bits are 0xffffffff * and draws whose 4th byte (bits 24..31) is >= 0x80. * (sign-extension bug PoC; predicted ~50% / ~50%) * * Build: make (needs kernel source at /usr/src) * Load: kldload ./arc4samp.ko */ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> #include <sys/module.h> #include <sys/conf.h> #include <sys/devfs.h> #include <sys/uio.h> #include <sys/malloc.h> #include <sys/libkern.h> #include <sys/types.h> static d_open_t arc4samp_open; static d_close_t arc4samp_close; static d_read_t arc4samp_read; static struct dev_ops arc4samp_cdevsw = { { "arc4samp", 0, 0 }, .d_open = arc4samp_open, .d_close = arc4samp_close, .d_read = arc4samp_read, }; static int arc4samp_open(struct dev_open_args *ap) { /* fresh one-shot report per open */ ap->a_head.a_dev->si_drv1 = NULL; return 0; } static int arc4samp_close(struct dev_close_args *ap) { return 0; } static int arc4samp_read(struct dev_read_args *ap) { struct cdev *dev = ap->a_head.a_dev; struct uio *uio = ap->a_uio; uint8_t *buf; int error = 0; int unit = dev2unit(dev); buf = kmalloc(65536, M_TEMP, M_WAITOK); if (buf == NULL) return ENOMEM; while (uio->uio_resid > 0 && error == 0) { int n = (int)szmin(uio->uio_resid, 65536); switch (unit) { case 0: { /* karc4random words */ int off = 0; while (off + 4 <= n) { uint32_t v = karc4random(); memcpy(buf + off, &v, 4); off += 4; } break; } case 1: /* karc4random_buf stream */ karc4random_buf(buf, n); break; case 2: { /* karc4random64 words */ int off = 0; while (off + 8 <= n) { uint64_t v = karc4random64(); memcpy(buf + off, &v, 8); off += 8; } break; } case 3: { /* one-shot bias report (per open) */ const int NDRAWS = 1 << 20; uint64_t top32ones = 0, b3high = 0; int len; if (dev->si_drv1) goto out; /* EOF after first report */ dev->si_drv1 = (void *)1; for (int k = 0; k < NDRAWS; k++) { uint64_t v = karc4random64(); if (((v >> 32) & 0xffffffffULL) == 0xffffffffULL) top32ones++; if (((v >> 24) & 0xff) >= 0x80) b3high++; } len = ksnprintf((char *)buf, 65536, "karc4random64 draws=%d\n" "top32==0xffffffff: %ju (%d.%04d; bug predicts ~0.5000)\n" "byte3>=0x80: %ju (%d.%04d)\n", NDRAWS, (uintmax_t)top32ones, (int)(top32ones * 10000 / NDRAWS / 10000), (int)(top32ones * 10000 / NDRAWS % 10000), (uintmax_t)b3high, (int)(b3high * 10000 / NDRAWS / 10000), (int)(b3high * 10000 / NDRAWS % 10000)); error = uiomove(buf, len, uio); goto out; } default: error = ENXIO; goto out; } error = uiomove(buf, n, uio); } out: kfree(buf, M_TEMP); return error; } static int arc4samp_modevent(module_t mod, int type, void *data) { switch (type) { case MOD_LOAD: make_dev(&arc4samp_cdevsw, 0, UID_ROOT, GID_WHEEL, 0444, "arc4s32"); make_dev(&arc4samp_cdevsw, 1, UID_ROOT, GID_WHEEL, 0444, "arc4sbuf"); make_dev(&arc4samp_cdevsw, 2, UID_ROOT, GID_WHEEL, 0444, "arc4s64"); make_dev(&arc4samp_cdevsw, 3, UID_ROOT, GID_WHEEL, 0444, "arc4srep"); kprintf("arc4samp: loaded\n"); break; case MOD_UNLOAD: destroy_dev(devfs_find_device_by_name("arc4s32")); destroy_dev(devfs_find_device_by_name("arc4sbuf")); destroy_dev(devfs_find_device_by_name("arc4s64")); destroy_dev(devfs_find_device_by_name("arc4srep")); kprintf("arc4samp: unloaded\n"); break; default: return EOPNOTSUPP; } return 0; } DEV_MODULE(arc4samp, arc4samp_modevent, NULL); |