Skip to content

Commit 1961d8d

Browse files
committed
crypto/rand: warn to stderr if blocked 60+ sec on first Reader.Read call
Fixes #22614 Change-Id: I220afbaaeab4dec6d59eeeef12107234a77f1587 Reviewed-on: https://go-review.googlesource.com/c/139419 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent d16e4d3 commit 1961d8d

File tree

3 files changed

+21
-0
lines changed

3 files changed

+21
-0
lines changed

src/crypto/rand/rand.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@ var Reader io.Reader
2323
func Read(b []byte) (n int, err error) {
2424
return io.ReadFull(Reader, b)
2525
}
26+
27+
func warnBlocked() {
28+
println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
29+
}

src/crypto/rand/rand_unix.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"os"
1919
"runtime"
2020
"sync"
21+
"sync/atomic"
2122
"time"
2223
)
2324

@@ -39,13 +40,20 @@ type devReader struct {
3940
name string
4041
f io.Reader
4142
mu sync.Mutex
43+
used int32 // atomic; whether this devReader has been used
4244
}
4345

4446
// altGetRandom if non-nil specifies an OS-specific function to get
4547
// urandom-style randomness.
4648
var altGetRandom func([]byte) (ok bool)
4749

4850
func (r *devReader) Read(b []byte) (n int, err error) {
51+
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
52+
// First use of randomness. Start timer to warn about
53+
// being blocked on entropy not being available.
54+
t := time.AfterFunc(60*time.Second, warnBlocked)
55+
defer t.Stop()
56+
}
4957
if altGetRandom != nil && r.name == urandomDevice && altGetRandom(b) {
5058
return len(b), nil
5159
}

src/crypto/rand/rand_windows.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ package rand
1010
import (
1111
"os"
1212
"sync"
13+
"sync/atomic"
1314
"syscall"
15+
"time"
1416
)
1517

1618
// Implemented by using Windows CryptoAPI 2.0.
@@ -19,11 +21,18 @@ func init() { Reader = &rngReader{} }
1921

2022
// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
2123
type rngReader struct {
24+
used int32 // atomic; whether this rngReader has been used
2225
prov syscall.Handle
2326
mu sync.Mutex
2427
}
2528

2629
func (r *rngReader) Read(b []byte) (n int, err error) {
30+
if atomic.CompareAndSwapInt32(&r.used, 0, 1) {
31+
// First use of randomness. Start timer to warn about
32+
// being blocked on entropy not being available.
33+
t := time.AfterFunc(60*time.Second, warnBlocked)
34+
defer t.Stop()
35+
}
2736
r.mu.Lock()
2837
if r.prov == 0 {
2938
const provType = syscall.PROV_RSA_FULL

0 commit comments

Comments
 (0)