From cc3685b0dca0597c075036cdff25ada134be30aa Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Fri, 22 Sep 2017 07:35:21 +0800 Subject: [PATCH] arc4random: Make arc4random context per-cpu. Critical section is commented out, no consumers from ISRs/ithreads. --- sys/libkern/arc4random.c | 161 ++++++++++++++------------ sys/platform/pc64/x86_64/mp_machdep.c | 9 ++ sys/platform/vkernel64/x86_64/mp.c | 6 + sys/sys/libkern.h | 1 + 4 files changed, 104 insertions(+), 73 deletions(-) diff --git a/sys/libkern/arc4random.c b/sys/libkern/arc4random.c index cba0cd6132..1aeb7ad7c9 100644 --- a/sys/libkern/arc4random.c +++ b/sys/libkern/arc4random.c @@ -12,21 +12,28 @@ */ #include +#include #include #include #include +#include + #define ARC4_MAXRUNS 16384 #define ARC4_RESEED_SECONDS 300 #define ARC4_KEYBYTES 32 /* 256 bit key */ -static uint8_t arc4_i, arc4_j; -static int arc4_initialized = 0; -static int arc4_numruns = 0; -static uint8_t arc4_sbox[256]; -static struct timeval arc4_tv_nextreseed; +struct arc4_data { + uint8_t arc4_i; + uint8_t arc4_j; + int arc4_numruns; + time_t arc4_nextreseed; + uint8_t arc4_sbox[256]; +}; + +static struct arc4_data *arc4_data_pcpu[MAXCPU]; -static uint8_t arc4_randbyte(void); +static uint8_t arc4_randbyte(struct arc4_data *); static __inline void arc4_swap(uint8_t *a, uint8_t *b) @@ -42,7 +49,7 @@ arc4_swap(uint8_t *a, uint8_t *b) * Stir our S-box. */ static void -arc4_randomstir (void) +arc4_randomstir(struct arc4_data *d) { uint8_t key[256]; int r, n; @@ -53,91 +60,68 @@ arc4_randomstir (void) */ r = read_random_unlimited(key, ARC4_KEYBYTES); /* If r == 0 || -1, just use what was on the stack. */ - if (r > 0) - { + if (r > 0) { for (n = r; n < sizeof(key); n++) key[n] = key[n % r]; } for (n = 0; n < 256; n++) { - arc4_j = (arc4_j + arc4_sbox[n] + key[n]) % 256; - arc4_swap(&arc4_sbox[n], &arc4_sbox[arc4_j]); + d->arc4_j = (d->arc4_j + d->arc4_sbox[n] + key[n]) % 256; + arc4_swap(&d->arc4_sbox[n], &d->arc4_sbox[d->arc4_j]); } /* * Discard early keystream, as per recommendations in: * "(Not So) Random Shuffles of RC4" by Ilya Mironov. */ - for (n = 0; n < 768*4; n++) - arc4_randbyte(); + for (n = 0; n < 768 * 4; n++) + arc4_randbyte(d); /* Reset for next reseed cycle. */ - getmicrotime(&arc4_tv_nextreseed); - arc4_tv_nextreseed.tv_sec += ARC4_RESEED_SECONDS; - arc4_numruns = 0; -} - -/* - * Initialize our S-box to its beginning defaults. - */ -static void -arc4_init(void) -{ - int n; - - arc4_i = arc4_j = 0; - for (n = 0; n < 256; n++) - arc4_sbox[n] = (uint8_t)n; - - arc4_randomstir(); - arc4_initialized = 1; - - /* - * Discard early keystream, as per recommendations in: - * "(Not So) Random Shuffles of RC4" by Ilya Mironov. - */ - for (n = 0; n < 768 * 4; n++) - arc4_randbyte(); + d->arc4_nextreseed = time_uptime + ARC4_RESEED_SECONDS; + d->arc4_numruns = 0; } /* * Generate a random byte. */ static uint8_t -arc4_randbyte(void) +arc4_randbyte(struct arc4_data *d) { uint8_t arc4_t; - arc4_i = (arc4_i + 1) % 256; - arc4_j = (arc4_j + arc4_sbox[arc4_i]) % 256; + d->arc4_i = (d->arc4_i + 1) % 256; + d->arc4_j = (d->arc4_j + d->arc4_sbox[d->arc4_i]) % 256; - arc4_swap(&arc4_sbox[arc4_i], &arc4_sbox[arc4_j]); + arc4_swap(&d->arc4_sbox[d->arc4_i], &d->arc4_sbox[d->arc4_j]); - arc4_t = (arc4_sbox[arc4_i] + arc4_sbox[arc4_j]) % 256; - return arc4_sbox[arc4_t]; + arc4_t = (d->arc4_sbox[d->arc4_i] + d->arc4_sbox[d->arc4_j]) % 256; + return d->arc4_sbox[arc4_t]; } uint32_t karc4random(void) { + struct arc4_data *d = arc4_data_pcpu[mycpuid]; uint32_t ret; - struct timeval tv_now; - /* Initialize array if needed. */ - if (!arc4_initialized) - arc4_init(); +#if 0 + /* No one call this function in ISR/ithread. */ + crit_enter(); +#endif - getmicrotime(&tv_now); - if ((++arc4_numruns > ARC4_MAXRUNS) || - (tv_now.tv_sec > arc4_tv_nextreseed.tv_sec)) - { - arc4_randomstir(); - } + if (++(d->arc4_numruns) > ARC4_MAXRUNS || + time_uptime > d->arc4_nextreseed) + arc4_randomstir(d); - ret = arc4_randbyte(); - ret |= arc4_randbyte() << 8; - ret |= arc4_randbyte() << 16; - ret |= arc4_randbyte() << 24; + ret = arc4_randbyte(d); + ret |= arc4_randbyte(d) << 8; + ret |= arc4_randbyte(d) << 16; + ret |= arc4_randbyte(d) << 24; + +#if 0 + crit_exit(); +#endif return ret; } @@ -145,22 +129,53 @@ karc4random(void) void karc4rand(void *ptr, size_t len) { - uint8_t *p; - struct timeval tv_now; + struct arc4_data *d = arc4_data_pcpu[mycpuid]; + uint8_t *p = ptr; - p = ptr; +#if 0 + /* No one call this function in ISR/ithread. */ + crit_enter(); +#endif - /* Initialize array if needed. */ - if (!arc4_initialized) - arc4_init(); - - getmicrotime(&tv_now); - if ((++arc4_numruns > ARC4_MAXRUNS) || - (tv_now.tv_sec > arc4_tv_nextreseed.tv_sec)) - { - arc4_randomstir(); - } + if (++(d->arc4_numruns) > ARC4_MAXRUNS || + time_uptime > d->arc4_nextreseed) + arc4_randomstir(d); while (len--) - *p++ = arc4_randbyte(); + *p++ = arc4_randbyte(d); + +#if 0 + crit_exit(); +#endif +} + +/* + * Initialize our S-box to its beginning defaults. + */ +void +arc4_init_pcpu(int cpuid) +{ + struct arc4_data *d; + int n; + + KASSERT(arc4_data_pcpu[cpuid] == NULL, + ("arc4 was initialized on cpu%d", cpuid)); + + d = (void *)kmem_alloc3(&kernel_map, sizeof(*d), VM_SUBSYS_GD, + KM_CPU(cpuid)); + memset(d, 0, sizeof(*d)); + + for (n = 0; n < 256; n++) + d->arc4_sbox[n] = (uint8_t)n; + + arc4_randomstir(d); + + /* + * Discard early keystream, as per recommendations in: + * "(Not So) Random Shuffles of RC4" by Ilya Mironov. + */ + for (n = 0; n < 768 * 4; n++) + arc4_randbyte(d); + + arc4_data_pcpu[cpuid] = d; } diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index 86c91b4fd6..c45474c6ca 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -466,6 +466,9 @@ start_all_aps(u_int boot_addr) gd->gd_acpi_id = CPUID_TO_ACPIID(gd->mi.gd_cpuid); + /* initialize arc4random. */ + arc4_init_pcpu(x); + /* setup a vector to our boot code */ *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET; *((volatile u_short *) WARMBOOT_SEG) = (boot_addr >> 4); @@ -523,6 +526,9 @@ start_all_aps(u_int boot_addr) VM_SUBSYS_IPIQ, KM_CPU(0)); bzero(mycpu->gd_ipiq, ipiq_size); + /* initialize arc4random. */ + arc4_init_pcpu(0); + /* restore the warmstart vector */ *(u_long *) WARMBOOT_OFF = mpbioswarmvec; outb(CMOS_REG, BIOS_RESET); @@ -1615,6 +1621,9 @@ mp_bsp_simple_setup(void) VM_SUBSYS_IPIQ); bzero(mycpu->gd_ipiq, ipiq_size); + /* initialize arc4random. */ + arc4_init_pcpu(0); + pmap_set_opt(); if (cpu_feature & CPUID_TSC) diff --git a/sys/platform/vkernel64/x86_64/mp.c b/sys/platform/vkernel64/x86_64/mp.c index 56455b597c..a1da2d2e8d 100644 --- a/sys/platform/vkernel64/x86_64/mp.c +++ b/sys/platform/vkernel64/x86_64/mp.c @@ -177,6 +177,9 @@ mp_start(void) VM_SUBSYS_IPIQ); bzero(mycpu->gd_ipiq, ipiq_size); + /* initialize arc4random. */ + arc4_init_pcpu(0); + /* * cpu 1-(n-1) */ @@ -443,6 +446,9 @@ start_all_aps(u_int boot_addr) VM_SUBSYS_IPIQ); bzero(gd->mi.gd_ipiq, ipiq_size); + /* initialize arc4random. */ + arc4_init_pcpu(x); + /* * Setup the AP boot stack */ diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h index 5e14818a25..4edab19334 100644 --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -92,6 +92,7 @@ static __inline quad_t qabs(quad_t a) { return (a < 0 ? -a : a); } /* Prototypes for non-quad routines. */ uint32_t karc4random(void); void karc4rand(void *, size_t); +void arc4_init_pcpu(int cpuid); int bcmp(const void *, const void *, size_t); void *kbsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); -- 2.41.0