aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChressie Himpel <chressie@google.com>2022-04-21 17:30:08 +0200
committerChressie Himpel <chressie@google.com>2022-04-21 17:30:08 +0200
commit19e4b10f2fcad0a43adcd3e59877e9f638330f44 (patch)
tree883595817cbea02482e200163fb1e750a2ab4639 /src
parente07d63964b6db13c5439f6d0a5d136e43da74016 (diff)
parent3ae414c31e59c9ee210fa3606f36cf0ea36b9906 (diff)
downloadgo-19e4b10f2fcad0a43adcd3e59877e9f638330f44.tar.xz
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: I30dbbe508a6252d50b4154cb9a8299cf0a054449
Diffstat (limited to 'src')
-rw-r--r--src/crypto/rand/rand_batched_test.go2
-rw-r--r--src/crypto/rand/rand_unix.go62
2 files changed, 19 insertions, 45 deletions
diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go
index 7a981e7892..dfb9517d5e 100644
--- a/src/crypto/rand/rand_batched_test.go
+++ b/src/crypto/rand/rand_batched_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
+//go:build unix
package rand
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 0b137e131f..87ba9e3af7 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -10,11 +10,11 @@
package rand
import (
- "bufio"
"errors"
"io"
"os"
"sync"
+ "sync/atomic"
"syscall"
"time"
)
@@ -35,7 +35,7 @@ func init() {
type reader struct {
f io.Reader
mu sync.Mutex
- used bool // whether this reader has been used
+ used uint32 // Atomic: 0 - never used, 1 - used, but f == nil, 2 - used, and f != nil
}
// altGetRandom if non-nil specifies an OS-specific function to get
@@ -43,24 +43,11 @@ type reader struct {
var altGetRandom func([]byte) (ok bool)
// batched returns a function that calls f to populate a []byte by chunking it
-// into subslices of, at most, readMax bytes, buffering min(readMax, 4096)
-// bytes at a time.
+// into subslices of, at most, readMax bytes.
func batched(f func([]byte) error, readMax int) func([]byte) bool {
- bufferSize := 4096
- if bufferSize > readMax {
- bufferSize = readMax
- }
- fullBuffer := make([]byte, bufferSize)
- var buf []byte
return func(out []byte) bool {
- // First we copy any amount remaining in the buffer.
- n := copy(out, buf)
- out, buf = out[n:], buf[n:]
-
- // Then, if we're requesting more than the buffer size,
- // generate directly into the output, chunked by readMax.
- for len(out) >= len(fullBuffer) {
- read := len(out) - (len(out) % len(fullBuffer))
+ for len(out) > 0 {
+ read := len(out)
if read > readMax {
read = readMax
}
@@ -69,22 +56,6 @@ func batched(f func([]byte) error, readMax int) func([]byte) bool {
}
out = out[read:]
}
-
- // If there's a partial block left over, fill the buffer,
- // and copy in the remainder.
- if len(out) > 0 {
- if f(fullBuffer[:]) != nil {
- return false
- }
- buf = fullBuffer[:]
- n = copy(out, buf)
- out, buf = out[n:], buf[n:]
- }
-
- if len(out) > 0 {
- panic("crypto/rand batching failed to fill buffer")
- }
-
return true
}
}
@@ -95,10 +66,7 @@ func warnBlocked() {
func (r *reader) Read(b []byte) (n int, err error) {
boring.Unreachable()
- r.mu.Lock()
- defer r.mu.Unlock()
- if !r.used {
- r.used = true
+ if atomic.CompareAndSwapUint32(&r.used, 0, 1) {
// First use of randomness. Start timer to warn about
// being blocked on entropy not being available.
t := time.AfterFunc(time.Minute, warnBlocked)
@@ -107,14 +75,20 @@ func (r *reader) Read(b []byte) (n int, err error) {
if altGetRandom != nil && altGetRandom(b) {
return len(b), nil
}
- if r.f == nil {
- f, err := os.Open(urandomDevice)
- if err != nil {
- return 0, err
+ if atomic.LoadUint32(&r.used) != 2 {
+ r.mu.Lock()
+ if r.used != 2 {
+ f, err := os.Open(urandomDevice)
+ if err != nil {
+ r.mu.Unlock()
+ return 0, err
+ }
+ r.f = hideAgainReader{f}
+ atomic.StoreUint32(&r.used, 2)
}
- r.f = bufio.NewReader(hideAgainReader{f})
+ r.mu.Unlock()
}
- return r.f.Read(b)
+ return io.ReadFull(r.f, b)
}
// hideAgainReader masks EAGAIN reads from /dev/urandom.