Merge branch '2.5.x'
authorMark Wooding <mdw@distorted.org.uk>
Mon, 16 Dec 2019 17:21:25 +0000 (17:21 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 16 Dec 2019 17:21:25 +0000 (17:21 +0000)
* 2.5.x:
  debian/catacomb2.symbols: Bump versions for fixed functions.
  rand/rand.c: Mix the pool key in `rand_gate' and `rand_stretch'.
  rand/lcrand.c: Swap flags and max so generator not advertised as strong.
  pub/dh-kcdsa.c: Free the correct factor.
  math/limlee.c: Don't leak the factor vector on overall failure.
  math/limlee.c: Handle an abort from `pgen' correctly.
  math/pgen.c: Don't free the tester if it's not set up.
  math/ec-exp.h: Fix segfault when base point is at infinity.
  key/key-data.c (key_copydata): Fix catastrophic bug.
  key/key-data.c (key_split): Fix long-standing reference leak.
  key/key-misc.c (key_bytag): Don't give up because a by-id search fails.
  base/dispatch.c, etc.: Check that `rdrand' works.

1  2 
base/dispatch.c
rand/lcrand.c
rand/rand.c

diff --combined base/dispatch.c
@@@ -43,6 -43,7 +43,6 @@@
  
  #if CPUFAM_X86 || CPUFAM_AMD64
  
 -#  define EFLAGS_ID (1u << 21)
  #  define CPUID1D_SSE2 (1u << 26)
  #  define CPUID1D_FXSR (1u << 24)
  #  define CPUID1C_PCLMUL (1u << 1)
  #  define CPUID1C_RDRAND (1u << 30)
  
  struct cpuid { unsigned a, b, c, d; };
 -
 -/* --- @cpuid@ --- *
 - *
 - * Arguments: @struct cpuid *cc@ = where to write the result
 - *            @unsigned a, c@ = EAX and ECX registers to set
 - *
 - * Returns:   ---
 - *
 - * Use:               Minimal C wrapper around the x86 `CPUID' instruction.  Checks
 - *            that the instruction is actually available before invoking
 - *            it; fills the output structure with zero if it's not going to
 - *            work.
 - */
 -
 -#ifdef __GNUC__
 -#  if CPUFAM_X86
 -static __inline__ unsigned getflags(void)
 -  { unsigned f; __asm__ ("pushf; popl %0" : "=g" (f)); return (f); }
 -static __inline__ unsigned setflags(unsigned f)
 -{
 -  unsigned ff;
 -  __asm__ ("pushf; pushl %1; popf; pushf; popl %0; popf"
 -         : "=r" (ff)
 -         : "r" (f));
 -  return (ff);
 -}
 -#  else
 -static __inline__ unsigned long getflags(void)
 -  { unsigned long f; __asm__ ("pushf; popq %0" : "=g" (f)); return (f); }
 -static __inline__ unsigned long long setflags(unsigned long f)
 -{
 -  unsigned long ff;
 -  __asm__ ("pushf; pushq %1; popf; pushf; popq %0; popf"
 -         : "=r" (ff)
 -         : "r" (f));
 -  return (ff);
 -}
 -#  endif
 -#endif
 +extern int dispatch_x86ish_cpuid(struct cpuid *, unsigned a, unsigned c);
 +extern int dispatch_x86ish_xmmregisters_p(void);
  
  static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
  {
 -#ifdef __GNUC__
 -  unsigned f;
 -#endif
 -
 -  cc->a = cc->b = cc->c = cc->d = 0;
 -
 -#ifdef __GNUC__
 -  /* Stupid dance to detect whether the CPUID instruction is available. */
 -  f = getflags();
 -  if (!(setflags(f |  EFLAGS_ID) & EFLAGS_ID) ||
 -      setflags(f & ~EFLAGS_ID) & EFLAGS_ID) {
 +  int rc = dispatch_x86ish_cpuid(cc, a, c);
 +  if (rc)
      dispatch_debug("CPUID instruction not available");
 -    return;
 -  }
 -  setflags(f);
 -
 -  /* Alas, EBX is magical in PIC code, so abuse ESI instead.  This isn't
 -   * pretty, but it works.
 -   */
 -#  if CPUFAM_X86
 -  __asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx"
 -         : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d)
 -         : "a" (a) , "c" (c));
 -#  elif CPUFAM_AMD64
 -  __asm__ ("pushq %%rbx; cpuid; movl %%ebx, %%esi; popq %%rbx"
 -         : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d)
 -         : "a" (a) , "c" (c));
 -#  else
 -#    error "I'm confused."
 -#  endif
 -  dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x",
 -               a, c, cc->a, cc->b, cc->c, cc->d);
 -#else
 -  dispatch_debug("GNU inline assembler not available; can't CPUID");
 -#endif
 +  else
 +    dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x",
 +                 a, c, cc->a, cc->b, cc->c, cc->d);
  }
  
  static unsigned cpuid_maxleaf(void)
@@@ -95,12 -162,98 +95,65 @@@ static int cpuid_features_p(unsigned db
  
  static int xmm_registers_available_p(void)
  {
 -#ifdef __GNUC__
 -  unsigned f;
 -  /* This hack is by Agner Fog.  Use FXSAVE/FXRSTOR to figure out whether the
 -   * XMM registers are actually alive.
 -   */
 -  if (!cpuid_features_p(CPUID1D_FXSR, 0)) return (0);
 -#  if CPUFAM_X86
 -  __asm__ ("movl %%esp, %%edx; subl $512, %%esp; andl $~15, %%esp\n"
 -         "fxsave (%%esp)\n"
 -         "movl 160(%%esp), %%eax; xorl $0xaaaa5555, 160(%%esp)\n"
 -         "fxrstor (%%esp); fxsave (%%esp)\n"
 -         "movl 160(%%esp), %%ecx; movl %%eax, 160(%%esp)\n"
 -         "fxrstor (%%esp); movl %%edx, %%esp\n"
 -         "xorl %%ecx, %%eax"
 -         : "=a" (f)
 -         : /* no inputs */
 -         : "%ecx", "%edx");
 -#  elif CPUFAM_AMD64
 -  __asm__ ("movq %%rsp, %%rdx; subq $512, %%rsp; andq $~15, %%rsp\n"
 -         "fxsave (%%rsp)\n"
 -         "movl 160(%%rsp), %%eax; xorl $0xaaaa5555, 160(%%rsp)\n"
 -         "fxrstor (%%rsp); fxsave (%%rsp)\n"
 -         "movl 160(%%rsp), %%ecx; movl %%eax, 160(%%rsp)\n"
 -         "fxrstor (%%rsp); movq %%rdx, %%rsp\n"
 -         "xorl %%ecx, %%eax"
 -         : "=a" (f)
 -         : /* no inputs */
 -         : "%ecx", "%rdx");
 -#  else
 -#    error "I'm confused."
 -#  endif
 +  int f = dispatch_x86ish_xmmregisters_p();
 +
    dispatch_debug("XMM registers %savailable", f ? "" : "not ");
    return (f);
 -#else
 -  dispatch_debug("GNU inline assembler not available; can't check for XMM");
 -  return (0);
 -#endif
  }
  
+ /* --- @rdrand_works_p@ --- *
+  *
+  *
+  * Arguments: ---
+  *
+  * Returns:   Nonzero if the `rdrand' instruction actually works.  Assumes
+  *            that it's already been verified to be safe to issue.
+  */
+ #ifdef __GNUC__
+ static int rdrand(unsigned *x)
+ {
+   int i, rc;
+   unsigned _t;
+   i = 16;
+   __asm__ ("" : "=g" (_t));
+   __asm__ ("0: rdrand %2; jc 1f; decl %1; jnz 0b\n"
+          "mov $-1, %0; jmp 9f\n"
+          "1: movl %2, (%3); xorl %0, %0\n"
+          "9:"
+          : "=r" (rc), "+r" (i), "+r" (_t)
+          : "r" (x)
+          : "cc");
+   return (rc);
+ }
+ #endif
+ static int rdrand_works_p(void)
+ {
+   unsigned ref, x, i;
+   /* Check that it doesn't always give the same answer.  Try four times: this
+    * will fail with probability %$2^{-128}$% with a truly random generator,
+    * which seems fair enough.
+    */
+   if (rdrand(&ref)) goto fail;
+   for (i = 0; i < 4; i++) {
+     if (rdrand(&x)) goto fail;
+     if (x != ref) goto not_stuck;
+   }
+   dispatch_debug("RDRAND always returns 0x%08x!", ref);
+   return (0);
+ not_stuck:
+   dispatch_debug("RDRAND instruction looks plausible");
+   return (1);
+ fail:
+   dispatch_debug("RDRAND instruction fails too often");
+   return (0);
+ }
  #endif
  
  /*----- General feature probing using auxiliary vectors -------------------*/
@@@ -453,7 -606,7 +506,7 @@@ int cpu_feature_p(int feat
                 cpuid_features_p(CPUID1D_SSE2, CPUID1C_AESNI) &&
                 xmm_registers_available_p());
      CASE_CPUFEAT(X86_RDRAND, "x86:rdrand",
-                cpuid_features_p(0, CPUID1C_RDRAND));
+                cpuid_features_p(0, CPUID1C_RDRAND) && rdrand_works_p());
      CASE_CPUFEAT(X86_AVX, "x86:avx",
                 cpuid_features_p(0, CPUID1C_AVX) &&
                 xmm_registers_available_p());
diff --combined rand/lcrand.c
@@@ -33,7 -33,6 +33,7 @@@
  #include <string.h>
  
  #include <mLib/bits.h>
 +#include <mLib/macros.h>
  #include <mLib/sub.h>
  
  #include "grand.h"
@@@ -107,11 -106,15 +107,11 @@@ uint32 lcrand(uint32 x
  
    /* --- Now reduce mod p --- *
     *
 -   * I'm using shifts and adds to do the multiply step here.  This needs to
 -   * be changed if @D@ ever becomes something other than 5.
 +   * I'm using shifts and adds to do the multiply step here.
     */
  
 -#if D != 5
 -#  error "Change shift sequence!"
 -#endif
 -
    {
 +    STATIC_ASSERT(D == 5, "Shift sequence doesn't match prime");
      uint32 q;
  
      q = yy[1];
@@@ -241,7 -244,7 +241,7 @@@ static uint32 grange(grand *r, uint32 l
  
  static const grand_ops gops = {
    "lcrand",
-   LCRAND_P, 0,
+   0, LCRAND_P,
    gmisc, gdestroy,
    graw, gbyte, grand_defaultword, grange, grand_defaultfill
  };
diff --combined rand/rand.c
@@@ -161,14 -161,24 +161,14 @@@ CPU_DISPATCH(static, return, int, quick
  
  static int trivial_quick(rand_pool *r) { return (-1); }
  
 -#if __GNUC__ && (CPUFAM_X86 || CPUFAM_AMD64)
 -static int rdrand_quick(rand_pool *r)
 -{
 -  unsigned long rr;
 -  int i = 16;
 -
 -  __asm__ ("0: rdrand %0; jc 9f; dec %1; jnz 0b; 9:"
 -         : "=r" (rr), "=r" (i) : "1" (i) : "cc");
 -  if (!i) return (-1);
 -  rand_add(r, &rr, sizeof(rr), 8*sizeof(rr));
 -  return (0);
 -}
 +#if CPUFAM_X86 || CPUFAM_AMD64
 +extern int rand_quick_x86ish_rdrand(rand_pool */*r*/);
  #endif
  
  static quick__functype *pick_quick(void)
  {
 -#if __GNUC__ && (CPUFAM_X86 || CPUFAM_AMD64)
 -  DISPATCH_PICK_COND(rand_quick, rdrand_quick,
 +#if CPUFAM_X86 || CPUFAM_AMD64
 +  DISPATCH_PICK_COND(rand_quick, rand_quick_x86ish_rdrand,
                     cpu_feature_p(CPUFEAT_X86_RDRAND));
  #endif
    DISPATCH_PICK_FALLBACK(rand_quick, trivial_quick);
@@@ -251,7 -261,9 +251,7 @@@ void rand_add(rand_pool *r, const void 
    const octet *c = p;
    int i, rot;
  
 -#if RAND_POOLSZ != 128
 -#  error Polynomial in rand_add is out of date.  Fix it.
 -#endif
 +  STATIC_ASSERT(RAND_POOLSZ == 128, "Polynomial doesn't match pool size");
  
    RAND_RESOLVE(r);
  
@@@ -311,6 -323,7 +311,7 @@@ void rand_gate(rand_pool *r
  
    HASH_INIT(&hc);
    STORE32(g, r->gen); HASH(&hc, g, sizeof(g));
+   HASH(&hc, r->k.k, RAND_KEYSZ);
    HASH(&hc, r->pool, RAND_POOLSZ);
    HASH(&hc, r->buf, RAND_BUFSZ);
    HASH_DONE(&hc, h);
@@@ -361,6 -374,7 +362,7 @@@ void rand_stretch(rand_pool *r
  
    HASH_INIT(&hc);
    STORE32(g, r->gen); HASH(&hc, g, sizeof(g));
+   HASH(&hc, r->k.k, RAND_KEYSZ);
    HASH(&hc, r->pool, RAND_POOLSZ);
    HASH(&hc, r->buf, RAND_BUFSZ);
    HASH_DONE(&hc, h);