Skip to content

Commit 95d991d

Browse files
josephlrbradfitz
authored andcommitted
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 <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent f3f29d1 commit 95d991d

File tree

1 file changed

+7
-21
lines changed

1 file changed

+7
-21
lines changed

src/crypto/rand/rand_linux.go

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,20 @@ package rand
66

77
import (
88
"internal/syscall/unix"
9-
"sync"
109
)
1110

1211
func init() {
1312
altGetRandom = getRandomLinux
1413
}
1514

16-
var (
17-
once sync.Once
18-
useSyscall bool
19-
)
20-
21-
func pickStrategy() {
22-
// Test whether we should use the system call or /dev/urandom.
23-
// We'll fall back to urandom if:
24-
// - the kernel is too old (before 3.17)
25-
// - the machine has no entropy available (early boot + no hardware
26-
// entropy source?) and we want to avoid blocking later.
27-
var buf [1]byte
28-
n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
29-
useSyscall = n == 1 && err == nil
30-
}
31-
15+
// If the kernel is too old (before 3.17) to support the getrandom syscall(),
16+
// unix.GetRandom will immediately return ENOSYS and we will then fall back to
17+
// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
18+
// result so we only suffer the syscall overhead once in this case.
19+
// If the kernel supports the getrandom() syscall, unix.GetRandom will block
20+
// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
21+
// In this case, unix.GetRandom will not return an error.
3222
func getRandomLinux(p []byte) (ok bool) {
33-
once.Do(pickStrategy)
34-
if !useSyscall {
35-
return false
36-
}
3723
n, err := unix.GetRandom(p, 0)
3824
return n == len(p) && err == nil
3925
}

0 commit comments

Comments
 (0)