]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/rand: warn to stderr if blocked 60+ sec on first Reader.Read call
authorBrad Fitzpatrick <bradfitz@golang.org>
Wed, 3 Oct 2018 22:18:07 +0000 (22:18 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 3 Oct 2018 22:50:25 +0000 (22:50 +0000)
Fixes #22614

Change-Id: I220afbaaeab4dec6d59eeeef12107234a77f1587
Reviewed-on: https://go-review.googlesource.com/c/139419
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/crypto/rand/rand.go
src/crypto/rand/rand_unix.go
src/crypto/rand/rand_windows.go

index 952d20aa16d7cdaac98df45ab0f95c1012aaf917..a5ccd19de3299489e30dc432483b5fbf9d3fa3a7 100644 (file)
@@ -23,3 +23,7 @@ var Reader io.Reader
 func Read(b []byte) (n int, err error) {
        return io.ReadFull(Reader, b)
 }
+
+func warnBlocked() {
+       println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
+}
index cebb7a761cd0de1b0c4dc546dd6128a3e6c9f58f..d49f693746dcc8af240ad1439cccd3e8ac50d3f7 100644 (file)
@@ -18,6 +18,7 @@ import (
        "os"
        "runtime"
        "sync"
+       "sync/atomic"
        "time"
 )
 
@@ -39,6 +40,7 @@ type devReader struct {
        name string
        f    io.Reader
        mu   sync.Mutex
+       used int32 // atomic; whether this devReader has been used
 }
 
 // altGetRandom if non-nil specifies an OS-specific function to get
@@ -46,6 +48,12 @@ type devReader struct {
 var altGetRandom func([]byte) (ok bool)
 
 func (r *devReader) Read(b []byte) (n int, err error) {
+       if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
+               // First use of randomness. Start timer to warn about
+               // being blocked on entropy not being available.
+               t := time.AfterFunc(60*time.Second, warnBlocked)
+               defer t.Stop()
+       }
        if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
                return len(b), nil
        }
index 4d7511a84004100a20f6615cb1d8a5ee8efb8597..78a4ed6d67b5c843d94f89e5c5bfea5b1a77c9b6 100644 (file)
@@ -10,7 +10,9 @@ package rand
 import (
        "os"
        "sync"
+       "sync/atomic"
        "syscall"
+       "time"
 )
 
 // Implemented by using Windows CryptoAPI 2.0.
@@ -19,11 +21,18 @@ func init() { Reader = &rngReader{} }
 
 // A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
 type rngReader struct {
+       used int32 // atomic; whether this rngReader has been used
        prov syscall.Handle
        mu   sync.Mutex
 }
 
 func (r *rngReader) Read(b []byte) (n int, err error) {
+       if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
+               // First use of randomness. Start timer to warn about
+               // being blocked on entropy not being available.
+               t := time.AfterFunc(60*time.Second, warnBlocked)
+               defer t.Stop()
+       }
        r.mu.Lock()
        if r.prov == 0 {
                const provType = syscall.PROV_RSA_FULL