rand_unix.c: don't discard entropy bytes from syscall_random()
authorDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
Thu, 16 Aug 2018 19:05:47 +0000 (21:05 +0200)
committerDr. Matthias St. Pierre <Matthias.St.Pierre@ncp-e.com>
Sun, 19 Aug 2018 10:44:05 +0000 (12:44 +0200)
Fixes #6978

Don't discard partial reads from syscall_random() and retry instead.

Reviewed-by: Andy Polyakov <appro@openssl.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6990)

crypto/rand/rand_unix.c

index 74cc9e1..e63d778 100644 (file)
@@ -458,17 +458,25 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool)
     unsigned char *buffer;
 
 #   ifdef OPENSSL_RAND_SEED_GETRANDOM
-    bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
-    buffer = rand_pool_add_begin(pool, bytes_needed);
-    if (buffer != NULL) {
-        size_t bytes = 0;
-
-        if (syscall_random(buffer, bytes_needed) == (int)bytes_needed)
-            bytes = bytes_needed;
+    {
+        ssize_t bytes;
+        /* Maximum allowed number of consecutive unsuccessful attempts */
+        int attempts = 3;
 
-        rand_pool_add_end(pool, bytes, 8 * bytes);
-        entropy_available = rand_pool_entropy_available(pool);
+        bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+        while (bytes_needed != 0 && attempts-- > 0) {
+            buffer = rand_pool_add_begin(pool, bytes_needed);
+            bytes = syscall_random(buffer, bytes_needed);
+            if (bytes > 0) {
+                rand_pool_add_end(pool, bytes, 8 * bytes);
+                bytes_needed -= bytes;
+                attempts = 3; /* reset counter after successful attempt */
+            } else if (bytes < 0 && errno != EINTR) {
+                break;
+            }
+        }
     }
+    entropy_available = rand_pool_entropy_available(pool);
     if (entropy_available > 0)
         return entropy_available;
 #   endif