]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rand: use blocking getrandom call on Linux when supported
authorJoe Richey joerichey@google.com <joerichey@google.com>
Mon, 22 May 2017 21:36:43 +0000 (14:36 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 23 May 2017 04:54:42 +0000 (04:54 +0000)
By changing getRandomLinux to immediately use the getrandom() syscall
without GRND_NONBLOCK, we now only fall back to reading from
/dev/urandom on Linux if the kernel does not support the getrandom()
syscall. This means reads for crypto/rand will now block if the kernel
has insufficient entropy on Linux kernels after v3.16.

Before, if the kernel had insufficient entropy, it would fall back to
reading from /dev/urandom. This would potentially return predictable
data.

Fixes #19274

Change-Id: I1cb081ce2f3096f18ad2820e52ecdbd993dc2afc
Reviewed-on: https://go-review.googlesource.com/43852
Reviewed-by: Filippo Valsorda <hi@filippo.io>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/crypto/rand/rand_linux.go

index 472daa7650b7a2ce869e63441994a345bb6e0844..8a4c757236387934ad520a12a3bbce366734faee 100644 (file)
@@ -6,34 +6,20 @@ package rand
 
 import (
        "internal/syscall/unix"
-       "sync"
 )
 
 func init() {
        altGetRandom = getRandomLinux
 }
 
-var (
-       once       sync.Once
-       useSyscall bool
-)
-
-func pickStrategy() {
-       // Test whether we should use the system call or /dev/urandom.
-       // We'll fall back to urandom if:
-       // - the kernel is too old (before 3.17)
-       // - the machine has no entropy available (early boot + no hardware
-       //   entropy source?) and we want to avoid blocking later.
-       var buf [1]byte
-       n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
-       useSyscall = n == 1 && err == nil
-}
-
+// If the kernel is too old (before 3.17) to support the getrandom syscall(),
+// unix.GetRandom will immediately return ENOSYS and we will then fall back to
+// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
+// result so we only suffer the syscall overhead once in this case.
+// If the kernel supports the getrandom() syscall, unix.GetRandom will block
+// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
+// In this case, unix.GetRandom will not return an error.
 func getRandomLinux(p []byte) (ok bool) {
-       once.Do(pickStrategy)
-       if !useSyscall {
-               return false
-       }
        n, err := unix.GetRandom(p, 0)
        return n == len(p) && err == nil
 }