From 95d991d30c59edc4943bd8baf5c664c5f8b1cebe Mon Sep 17 00:00:00 2001 From: "Joe Richey joerichey@google.com" Date: Mon, 22 May 2017 14:36:43 -0700 Subject: [PATCH] crypto/rand: use blocking getrandom call on Linux when supported 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 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/crypto/rand/rand_linux.go | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go index 472daa7650..8a4c757236 100644 --- a/src/crypto/rand/rand_linux.go +++ b/src/crypto/rand/rand_linux.go @@ -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 } -- 2.50.0