mirror of
https://github.com/golang/go
synced 2024-11-21 23:24:41 -07:00
crypto/rand: add randcrash=0 GODEBUG
For #66821 Change-Id: I525c308d6d6243a2bc805e819dcf40b67e52ade5 Reviewed-on: https://go-review.googlesource.com/c/go/+/608435 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Daniel McCarney <daniel@binaryparadox.net> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
55b930eb07
commit
63cd5a39e9
@ -168,6 +168,11 @@ For Go 1.24, it now defaults to multipathtcp="2", thus
|
||||
enabled by default on listerners. Using multipathtcp="0" reverts to the
|
||||
pre-Go 1.24 behavior.
|
||||
|
||||
Go 1.24 changed [`crypto/rand.Read`](/pkg/crypto/rand/#Read) to crash the
|
||||
program on any error. This setting is controlled by the `randcrash` setting.
|
||||
For Go 1.24 it defaults to `randcrash=1`.
|
||||
Using `randcrash=0` reverts to the pre-Go 1.24 behavior.
|
||||
|
||||
### Go 1.23
|
||||
|
||||
Go 1.23 changed the channels created by package time to be unbuffered
|
||||
|
@ -8,6 +8,7 @@ package rand
|
||||
|
||||
import (
|
||||
"crypto/internal/boring"
|
||||
"internal/godebug"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
@ -64,6 +65,8 @@ func (r *reader) Read(b []byte) (n int, err error) {
|
||||
//go:linkname fatal
|
||||
func fatal(string)
|
||||
|
||||
var randcrash = godebug.New("randcrash")
|
||||
|
||||
// Read fills b with cryptographically secure random bytes. It never returns an
|
||||
// error, and always fills b entirely.
|
||||
//
|
||||
@ -83,6 +86,10 @@ func Read(b []byte) (n int, err error) {
|
||||
copy(b, bb)
|
||||
}
|
||||
if err != nil {
|
||||
if randcrash.Value() == "0" {
|
||||
randcrash.IncNonDefault()
|
||||
return 0, err
|
||||
}
|
||||
fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + err.Error())
|
||||
panic("unreachable") // To be sure.
|
||||
}
|
||||
|
@ -48,20 +48,18 @@ func TestNoGetrandom(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
cmd := testenv.Command(t, os.Args[0], "-test.v")
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
cmd.Env = append(os.Environ(), "GO_GETRANDOM_DISABLED=1")
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Errorf("subprocess failed: %v\n%s", err, buf.Bytes())
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("subprocess failed: %v\n%s", err, out)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Contains(buf.Bytes(), []byte("GetRandom returned ENOSYS")) {
|
||||
if !bytes.Contains(out, []byte("GetRandom returned ENOSYS")) {
|
||||
t.Errorf("subprocess did not disable getrandom")
|
||||
}
|
||||
if !bytes.Contains(buf.Bytes(), []byte("TestRead")) {
|
||||
if !bytes.Contains(out, []byte("TestRead")) {
|
||||
t.Errorf("subprocess did not run TestRead")
|
||||
}
|
||||
}()
|
||||
|
@ -8,7 +8,9 @@ import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"crypto/internal/boring"
|
||||
"errors"
|
||||
"internal/race"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
@ -189,6 +191,44 @@ func TestNoUrandomFallback(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadError(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping test in short mode")
|
||||
}
|
||||
testenv.MustHaveExec(t)
|
||||
|
||||
// We run this test in a subprocess because it's expected to crash the
|
||||
// program unless the GODEBUG is set.
|
||||
if os.Getenv("GO_TEST_READ_ERROR") == "1" {
|
||||
defer func(r io.Reader) { Reader = r }(Reader)
|
||||
Reader = readerFunc(func([]byte) (int, error) {
|
||||
return 0, errors.New("error")
|
||||
})
|
||||
if _, err := Read(make([]byte, 32)); err == nil {
|
||||
t.Error("Read did not return error")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
cmd := testenv.Command(t, os.Args[0], "-test.run=TestReadError")
|
||||
cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1")
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Error("subprocess succeeded unexpectedly")
|
||||
}
|
||||
exp := "fatal error: crypto/rand: failed to read random data"
|
||||
if !bytes.Contains(out, []byte(exp)) {
|
||||
t.Errorf("subprocess output does not contain %q: %s", exp, out)
|
||||
}
|
||||
|
||||
cmd = testenv.Command(t, os.Args[0], "-test.run=TestReadError")
|
||||
cmd.Env = append(os.Environ(), "GO_TEST_READ_ERROR=1", "GODEBUG=randcrash=0")
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("subprocess failed: %v\n%s", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRead(b *testing.B) {
|
||||
b.Run("4", func(b *testing.B) {
|
||||
benchmarkRead(b, 4)
|
||||
|
@ -47,6 +47,7 @@ var All = []Info{
|
||||
{Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
|
||||
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
|
||||
{Name: "randautoseed", Package: "math/rand"},
|
||||
{Name: "randcrash", Package: "crypto/rand", Changed: 24, Old: "0"},
|
||||
{Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"},
|
||||
{Name: "tarinsecurepath", Package: "archive/tar"},
|
||||
{Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"},
|
||||
|
@ -306,6 +306,10 @@ Below is the full list of supported metrics, ordered lexicographically.
|
||||
The number of non-default behaviors executed by the math/rand
|
||||
package due to a non-default GODEBUG=randautoseed=... setting.
|
||||
|
||||
/godebug/non-default-behavior/randcrash:events
|
||||
The number of non-default behaviors executed by the crypto/rand
|
||||
package due to a non-default GODEBUG=randcrash=... setting.
|
||||
|
||||
/godebug/non-default-behavior/randseednop:events
|
||||
The number of non-default behaviors executed by the math/rand
|
||||
package due to a non-default GODEBUG=randseednop=... setting.
|
||||
|
Loading…
Reference in New Issue
Block a user