arc4random: Make arc4random context per-cpu.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 21 Sep 2017 23:35:21 +0000 (07:35 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 21 Sep 2017 23:35:21 +0000 (07:35 +0800)
Critical section is commented out, no consumers from ISRs/ithreads.

sys/libkern/arc4random.c
sys/platform/pc64/x86_64/mp_machdep.c
sys/platform/vkernel64/x86_64/mp.c
sys/sys/libkern.h

index cba0cd6..1aeb7ad 100644 (file)
  */
 
 #include <sys/types.h>
+#include <sys/systm.h>
 #include <sys/random.h>
 #include <sys/libkern.h>
 #include <sys/time.h>
 
+#include <vm/vm_extern.h>
+
 #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;
 }
index 86c91b4..c45474c 100644 (file)
@@ -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)
index 56455b5..a1da2d2 100644 (file)
@@ -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
                  */
index 5e14818..4edab19 100644 (file)
@@ -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 *));