-
Notifications
You must be signed in to change notification settings - Fork 17.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
crypto/rand: remove /dev/urandom fallback and improve getrandom batching
The fallback was reachable on - Linux, where starting in Go 1.24 we require a kernel with getrandom(2), see #67001. - FreeBSD, which added getrandom(2) in FreeBSD 12.0, which we require since Go 1.19. - OpenBSD, which added getentropy(2) in OpenBSD 5.6, and we only support the latest version. - DragonFly BSD, which has getrandom(2) and where we support only the latest version. - NetBSD, where we switched to kern.arandom in CL 511036, available since NetBSD 4.0. - illumos, which has getrandom(2). (Supported versions unclear.) - Solaris, which had getrandom(2) at least since Oracle Solaris 11.4. - AIX, which... ugh, fine, but that code is now in rand_aix.go. At the end of the day the platform-specific code is just a global func(b []byte) error, so simplified the package around that assumption. This also includes the following change, which used to be a separate CL. crypto/rand: improve getrandom batching and retry logic The previous logic assumed getrandom never returned short, and then applied stricter-than-necessary batch size limits, presumably to avoid short returns. This was still not sufficient because above 256 bytes getrandom(2) can be interrupted by a signal and return short *or* it can simply return EINTR if the pool is not initialized (regardless of buffer size). https://man.archlinux.org/man/getrandom.2#Interruption_by_a_signal_handler Whether this ever failed in practice is unknown: it would have been masked by the /dev/urandom fallback before. Instead, we apply buffer size limits only where necessary (really, only Solaris in practice and FreeBSD in theory) and then handle gracefully short returns and EINTR. Change-Id: I8677b457aab68a8fb6137a3b43538efc62eb7c93 It turns out that we now know that large getrandom calls *did* fail in practice, falling back on /dev/urandom, because when we removed the fallback TestBidiStreamReverseProxy with its 4KiB read started failing. https://cr-buildbucket.appspot.com/build/8740779846954406033 For #66821 Change-Id: Iaca62997604f326501a51401cdc2659c2790ff22 Reviewed-on: https://go-review.googlesource.com/c/go/+/602495 Reviewed-by: Roland Shoemaker <roland@golang.org> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
- Loading branch information
1 parent
2f50798
commit a62566f
Showing
12 changed files
with
259 additions
and
214 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright 2010 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package rand | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"os" | ||
"sync" | ||
"sync/atomic" | ||
"syscall" | ||
) | ||
|
||
const urandomDevice = "/dev/urandom" | ||
|
||
var ( | ||
f io.Reader | ||
mu sync.Mutex | ||
used atomic.Bool | ||
) | ||
|
||
func read(b []byte) error { | ||
if !used.Load() { | ||
mu.Lock() | ||
if !used.Load() { | ||
dev, err := os.Open(urandomDevice) | ||
if err != nil { | ||
mu.Unlock() | ||
return err | ||
} | ||
f = hideAgainReader{dev} | ||
used.Store(true) | ||
} | ||
mu.Unlock() | ||
} | ||
if _, err := io.ReadFull(f, b); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// hideAgainReader masks EAGAIN reads from /dev/urandom. | ||
// See golang.org/issue/9205. | ||
type hideAgainReader struct { | ||
r io.Reader | ||
} | ||
|
||
func (hr hideAgainReader) Read(p []byte) (n int, err error) { | ||
n, err = hr.r.Read(p) | ||
if errors.Is(err, syscall.EAGAIN) { | ||
err = nil | ||
} | ||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.