Make the random number generator predictable when fuzzing.
[openssl.git] / crypto / rand / md_rand.c
index 4b874e3bedf4a9459e1ee8487769076983938e02..0cf6e90834820f129ec29b7f6806e17df09b5c53 100644 (file)
 
 #include <openssl/err.h>
 
+#include <internal/thread_once.h>
+
 #ifdef OPENSSL_FIPS
 # include <openssl/fips.h>
 #endif
 
-#ifdef BN_DEBUG
+#if defined(BN_DEBUG) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 # define PREDICT
 #endif
 
 /* #define PREDICT      1 */
 
 #define STATE_SIZE      1023
-static int state_num = 0, state_index = 0;
+static size_t state_num = 0, state_index = 0;
 static unsigned char state[STATE_SIZE + MD_DIGEST_LENGTH];
 static unsigned char md[MD_DIGEST_LENGTH];
 static long md_count[2] = { 0, 0 };
@@ -60,7 +62,7 @@ static CRYPTO_THREAD_ID locking_threadid;
 int rand_predictable = 0;
 #endif
 
-static void rand_hw_seed(EVP_MD_CTX *ctx);
+static int rand_hw_seed(EVP_MD_CTX *ctx);
 
 static void rand_cleanup(void);
 static int rand_seed(const void *buf, int num);
@@ -85,10 +87,12 @@ static RAND_METHOD rand_meth = {
     rand_status
 };
 
-static void do_rand_lock_init(void)
+DEFINE_RUN_ONCE_STATIC(do_rand_lock_init)
 {
+    OPENSSL_init_crypto(0, NULL);
     rand_lock = CRYPTO_THREAD_lock_new();
     rand_tmp_lock = CRYPTO_THREAD_lock_new();
+    return rand_lock != NULL && rand_tmp_lock != NULL;
 }
 
 RAND_METHOD *RAND_OpenSSL(void)
@@ -141,7 +145,8 @@ static int rand_add(const void *buf, int num, double add)
     if (m == NULL)
         goto err;
 
-    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        goto err;
 
     /* check if we already have the lock */
     if (crypto_lock_rand) {
@@ -268,8 +273,8 @@ static int rand_seed(const void *buf, int num)
 static int rand_bytes(unsigned char *buf, int num, int pseudo)
 {
     static volatile int stirred_pool = 0;
-    int i, j, k, st_num, st_idx;
-    int num_ceil;
+    int i, j, k;
+    size_t num_ceil, st_idx, st_num;
     int ok;
     long md_c[2];
     unsigned char local_md[MD_DIGEST_LENGTH];
@@ -302,7 +307,7 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
 
 #ifdef PREDICT
     if (rand_predictable) {
-        static unsigned char val = 0;
+        unsigned char val = 0;
 
         for (i = 0; i < num; i++)
             buf[i] = val++;
@@ -339,7 +344,9 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
      * global 'md'.
      */
 
-    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        goto err_mem;
+
     CRYPTO_THREAD_write_lock(rand_lock);
     /*
      * We could end up in an async engine while holding this lock so ensure
@@ -446,7 +453,8 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
             if (!MD_Update(m, (unsigned char *)&tv, sizeof tv))
                 goto err;
             curr_time = 0;
-            rand_hw_seed(m);
+            if (!rand_hw_seed(m))
+                goto err;
         }
         if (!MD_Update(m, local_md, MD_DIGEST_LENGTH))
             goto err;
@@ -533,7 +541,9 @@ static int rand_status(void)
     int ret;
     int do_not_lock;
 
-    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        return 0;
+
     cur = CRYPTO_THREAD_get_current_id();
     /*
      * check if we already have the lock (could happen if a RAND_poll()
@@ -597,18 +607,20 @@ static int rand_status(void)
 size_t OPENSSL_ia32_rdrand(void);
 extern unsigned int OPENSSL_ia32cap_P[];
 
-static void rand_hw_seed(EVP_MD_CTX *ctx)
+static int rand_hw_seed(EVP_MD_CTX *ctx)
 {
     int i;
     if (!(OPENSSL_ia32cap_P[1] & (1 << (62 - 32))))
-        return;
+        return 1;
     for (i = 0; i < RDRAND_CALLS; i++) {
         size_t rnd;
         rnd = OPENSSL_ia32_rdrand();
         if (rnd == 0)
-            return;
-        MD_Update(ctx, (unsigned char *)&rnd, sizeof(size_t));
+            return 1;
+        if (!MD_Update(ctx, (unsigned char *)&rnd, sizeof(size_t)))
+            return 0;
     }
+    return 1;
 }
 
 /* XOR an existing buffer with random data */
@@ -641,9 +653,9 @@ void rand_hw_xor(unsigned char *buf, size_t num)
 
 #else
 
-static void rand_hw_seed(EVP_MD_CTX *ctx)
+static int rand_hw_seed(EVP_MD_CTX *ctx)
 {
-    return;
+    return 1;
 }
 
 void rand_hw_xor(unsigned char *buf, size_t num)