1
0
mirror of https://github.com/golang/go synced 2024-11-25 19:57:56 -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:
Filippo Valsorda 2024-08-26 19:37:15 +02:00
parent 55b930eb07
commit 63cd5a39e9
6 changed files with 62 additions and 7 deletions

View File

@ -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 enabled by default on listerners. Using multipathtcp="0" reverts to the
pre-Go 1.24 behavior. 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
Go 1.23 changed the channels created by package time to be unbuffered Go 1.23 changed the channels created by package time to be unbuffered

View File

@ -8,6 +8,7 @@ package rand
import ( import (
"crypto/internal/boring" "crypto/internal/boring"
"internal/godebug"
"io" "io"
"os" "os"
"sync" "sync"
@ -64,6 +65,8 @@ func (r *reader) Read(b []byte) (n int, err error) {
//go:linkname fatal //go:linkname fatal
func fatal(string) func fatal(string)
var randcrash = godebug.New("randcrash")
// Read fills b with cryptographically secure random bytes. It never returns an // Read fills b with cryptographically secure random bytes. It never returns an
// error, and always fills b entirely. // error, and always fills b entirely.
// //
@ -83,6 +86,10 @@ func Read(b []byte) (n int, err error) {
copy(b, bb) copy(b, bb)
} }
if err != nil { 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()) fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + err.Error())
panic("unreachable") // To be sure. panic("unreachable") // To be sure.
} }

View File

@ -48,20 +48,18 @@ func TestNoGetrandom(t *testing.T) {
return return
} }
buf := &bytes.Buffer{}
cmd := testenv.Command(t, os.Args[0], "-test.v") cmd := testenv.Command(t, os.Args[0], "-test.v")
cmd.Stdout = buf
cmd.Stderr = buf
cmd.Env = append(os.Environ(), "GO_GETRANDOM_DISABLED=1") cmd.Env = append(os.Environ(), "GO_GETRANDOM_DISABLED=1")
if err := cmd.Run(); err != nil { out, err := cmd.CombinedOutput()
t.Errorf("subprocess failed: %v\n%s", err, buf.Bytes()) if err != nil {
t.Errorf("subprocess failed: %v\n%s", err, out)
return 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") 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") t.Errorf("subprocess did not run TestRead")
} }
}() }()

View File

@ -8,7 +8,9 @@ import (
"bytes" "bytes"
"compress/flate" "compress/flate"
"crypto/internal/boring" "crypto/internal/boring"
"errors"
"internal/race" "internal/race"
"internal/testenv"
"io" "io"
"os" "os"
"runtime" "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) { func BenchmarkRead(b *testing.B) {
b.Run("4", func(b *testing.B) { b.Run("4", func(b *testing.B) {
benchmarkRead(b, 4) benchmarkRead(b, 4)

View File

@ -47,6 +47,7 @@ var All = []Info{
{Name: "netedns0", Package: "net", Changed: 19, Old: "0"}, {Name: "netedns0", Package: "net", Changed: 19, Old: "0"},
{Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"}, {Name: "panicnil", Package: "runtime", Changed: 21, Old: "1"},
{Name: "randautoseed", Package: "math/rand"}, {Name: "randautoseed", Package: "math/rand"},
{Name: "randcrash", Package: "crypto/rand", Changed: 24, Old: "0"},
{Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"}, {Name: "randseednop", Package: "math/rand", Changed: 24, Old: "0"},
{Name: "tarinsecurepath", Package: "archive/tar"}, {Name: "tarinsecurepath", Package: "archive/tar"},
{Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"}, {Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"},

View File

@ -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 The number of non-default behaviors executed by the math/rand
package due to a non-default GODEBUG=randautoseed=... setting. 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 /godebug/non-default-behavior/randseednop:events
The number of non-default behaviors executed by the math/rand The number of non-default behaviors executed by the math/rand
package due to a non-default GODEBUG=randseednop=... setting. package due to a non-default GODEBUG=randseednop=... setting.