Fix data race in RAND_DRBG_generate
authorBernd Edlinger <bernd.edlinger@hotmail.de>
Sun, 14 Oct 2018 10:35:19 +0000 (12:35 +0200)
committerBernd Edlinger <bernd.edlinger@hotmail.de>
Fri, 26 Oct 2018 13:33:37 +0000 (15:33 +0200)
Fixes #7394

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/7399)

crypto/rand/drbg_lib.c
crypto/rand/rand_lcl.h
crypto/rand/rand_lib.c

index 9d920cb..ec4aa69 100644 (file)
@@ -374,6 +374,13 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
         max_entropylen += drbg->max_noncelen;
     }
 
+    drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+    if (drbg->reseed_next_counter) {
+        drbg->reseed_next_counter++;
+        if(!drbg->reseed_next_counter)
+            drbg->reseed_next_counter = 1;
+    }
+
     if (drbg->get_entropy != NULL)
         entropylen = drbg->get_entropy(drbg, &entropy, min_entropy,
                                        min_entropylen, max_entropylen, 0);
@@ -401,12 +408,7 @@ int RAND_DRBG_instantiate(RAND_DRBG *drbg,
     drbg->state = DRBG_READY;
     drbg->reseed_gen_counter = 1;
     drbg->reseed_time = time(NULL);
-    if (drbg->reseed_prop_counter > 0) {
-        if (drbg->parent == NULL)
-            drbg->reseed_prop_counter++;
-        else
-            drbg->reseed_prop_counter = drbg->parent->reseed_prop_counter;
-    }
+    tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
 
  end:
     if (entropy != NULL && drbg->cleanup_entropy != NULL)
@@ -498,6 +500,14 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg,
     }
 
     drbg->state = DRBG_ERROR;
+
+    drbg->reseed_next_counter = tsan_load(&drbg->reseed_prop_counter);
+    if (drbg->reseed_next_counter) {
+        drbg->reseed_next_counter++;
+        if(!drbg->reseed_next_counter)
+            drbg->reseed_next_counter = 1;
+    }
+
     if (drbg->get_entropy != NULL)
         entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength,
                                        drbg->min_entropylen,
@@ -515,12 +525,7 @@ int RAND_DRBG_reseed(RAND_DRBG *drbg,
     drbg->state = DRBG_READY;
     drbg->reseed_gen_counter = 1;
     drbg->reseed_time = time(NULL);
-    if (drbg->reseed_prop_counter > 0) {
-        if (drbg->parent == NULL)
-            drbg->reseed_prop_counter++;
-        else
-            drbg->reseed_prop_counter = drbg->parent->reseed_prop_counter;
-    }
+    tsan_store(&drbg->reseed_prop_counter, drbg->reseed_next_counter);
 
  end:
     if (entropy != NULL && drbg->cleanup_entropy != NULL)
@@ -691,8 +696,11 @@ int RAND_DRBG_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen,
             || now - drbg->reseed_time >= drbg->reseed_time_interval)
             reseed_required = 1;
     }
-    if (drbg->reseed_prop_counter > 0 && drbg->parent != NULL) {
-        if (drbg->reseed_prop_counter != drbg->parent->reseed_prop_counter)
+    if (drbg->parent != NULL) {
+        unsigned int reseed_counter = tsan_load(&drbg->reseed_prop_counter);
+        if (reseed_counter > 0
+                && tsan_load(&drbg->parent->reseed_prop_counter)
+                   != reseed_counter)
             reseed_required = 1;
     }
 
@@ -764,7 +772,8 @@ int RAND_DRBG_set_callbacks(RAND_DRBG *drbg,
                             RAND_DRBG_get_nonce_fn get_nonce,
                             RAND_DRBG_cleanup_nonce_fn cleanup_nonce)
 {
-    if (drbg->state != DRBG_UNINITIALISED)
+    if (drbg->state != DRBG_UNINITIALISED
+            || drbg->parent != NULL)
         return 0;
     drbg->get_entropy = get_entropy;
     drbg->cleanup_entropy = cleanup_entropy;
@@ -942,7 +951,7 @@ static RAND_DRBG *drbg_setup(RAND_DRBG *parent, int drbg_type)
         goto err;
 
     /* enable seed propagation */
-    drbg->reseed_prop_counter = 1;
+    tsan_store(&drbg->reseed_prop_counter, 1);
 
     /*
      * Ignore instantiation error to support just-in-time instantiation.
index 9004809..8abca4c 100644 (file)
@@ -16,6 +16,7 @@
 # include <openssl/hmac.h>
 # include <openssl/ec.h>
 # include <openssl/rand_drbg.h>
+# include "internal/tsan_assist.h"
 
 # include "internal/numbers.h"
 
@@ -258,7 +259,8 @@ struct rand_drbg_st {
      * is added by RAND_add() or RAND_seed() will have an immediate effect on
      * the output of RAND_bytes() resp. RAND_priv_bytes().
      */
-    unsigned int reseed_prop_counter;
+    TSAN_QUALIFIER unsigned int reseed_prop_counter;
+    unsigned int reseed_next_counter;
 
     size_t seedlen;
     DRBG_STATUS state;
index 29d93a8..440c19c 100644 (file)
@@ -174,6 +174,8 @@ size_t rand_drbg_get_entropy(RAND_DRBG *drbg,
                                    prediction_resistance,
                                    NULL, 0) != 0)
                 bytes = bytes_needed;
+            drbg->reseed_next_counter
+                = tsan_load(&drbg->parent->reseed_prop_counter);
             rand_drbg_unlock(drbg->parent);
 
             rand_pool_add_end(pool, bytes, 8 * bytes);