Skip to content

Commit

Permalink
crypto/rand: warn to stderr if blocked 60+ sec on first Reader.Read call
Browse files Browse the repository at this point in the history
Fixes #22614

Change-Id: I220afbaaeab4dec6d59eeeef12107234a77f1587
Reviewed-on: https://go-review.googlesource.com/c/139419
Reviewed-by: Ian Lance Taylor <iant@golang.org>
  • Loading branch information
bradfitz committed Oct 3, 2018
1 parent d16e4d3 commit 1961d8d
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/crypto/rand/rand.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
8 changes: 8 additions & 0 deletions src/crypto/rand/rand_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"os"
"runtime"
"sync"
"sync/atomic"
"time"
)

Expand All @@ -39,13 +40,20 @@ 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
// urandom-style randomness.
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
}
Expand Down
9 changes: 9 additions & 0 deletions src/crypto/rand/rand_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ package rand
import (
"os"
"sync"
"sync/atomic"
"syscall"
"time"
)

// Implemented by using Windows CryptoAPI 2.0.
Expand All @@ -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
Expand Down

0 comments on commit 1961d8d

Please sign in to comment.