Skip to content

Commit c050d42

Browse files
committed
crypto/rand: crash program if Read would return an error
Fixes #66821 Fixes #54980 Change-Id: Ib081f4e4f75c7936fc3f5b31d3bd07cca1c2a55c Reviewed-on: https://go-review.googlesource.com/c/go/+/602497 Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Daniel McCarney <[email protected]>
1 parent a62566f commit c050d42

File tree

4 files changed

+32
-24
lines changed

4 files changed

+32
-24
lines changed

src/crypto/rand/example_test.go

+4-19
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,10 @@
44

55
package rand_test
66

7-
import (
8-
"bytes"
9-
"crypto/rand"
10-
"fmt"
11-
)
7+
import "crypto/rand"
128

13-
// This example reads 10 cryptographically secure pseudorandom numbers from
14-
// rand.Reader and writes them to a byte slice.
159
func ExampleRead() {
16-
c := 10
17-
b := make([]byte, c)
18-
_, err := rand.Read(b)
19-
if err != nil {
20-
fmt.Println("error:", err)
21-
return
22-
}
23-
// The slice should now contain random bytes instead of only zeroes.
24-
fmt.Println(bytes.Equal(b, make([]byte, c)))
25-
26-
// Output:
27-
// false
10+
// Note that no error handling is necessary, as Read always succeeds.
11+
key := make([]byte, 32)
12+
rand.Read(key)
2813
}

src/crypto/rand/rand.go

+20-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"io"
1212
"sync/atomic"
1313
"time"
14+
_ "unsafe"
1415
)
1516

1617
// Reader is a global, shared instance of a cryptographically
@@ -23,6 +24,9 @@ import (
2324
// - On Windows, Reader uses the ProcessPrng API.
2425
// - On js/wasm, Reader uses the Web Crypto API.
2526
// - On wasip1/wasm, Reader uses random_get.
27+
//
28+
// All the platform APIs above are documented to never return an error
29+
// when used as they are in this package.
2630
var Reader io.Reader
2731

2832
func init() {
@@ -55,10 +59,23 @@ func (r *reader) Read(b []byte) (n int, err error) {
5559
return len(b), nil
5660
}
5761

58-
// Read is a helper function that calls Reader.Read using io.ReadFull.
59-
// On return, n == len(b) if and only if err == nil.
62+
// fatal is [runtime.fatal], pushed via linkname.
63+
//
64+
//go:linkname fatal
65+
func fatal(string)
66+
67+
// Read fills b with cryptographically secure random bytes. It never returns an
68+
// error, and always fills b entirely.
69+
//
70+
// If [Reader] is set to a non-default value, Read calls [io.ReadFull] on
71+
// [Reader] and crashes the program irrecoverably if an error is returned.
6072
func Read(b []byte) (n int, err error) {
61-
return io.ReadFull(Reader, b)
73+
_, err = io.ReadFull(Reader, b)
74+
if err != nil {
75+
fatal("crypto/rand: failed to read random data (see https://go.dev/issue/66821): " + err.Error())
76+
panic("unreachable") // To be sure.
77+
}
78+
return len(b), nil
6279
}
6380

6481
// batched returns a function that calls f to populate a []byte by chunking it

src/crypto/rand/util.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
)
1313

1414
// Prime returns a number of the given bit length that is prime with high probability.
15-
// Prime will return error for any error returned by [rand.Read] or if bits < 2.
15+
// Prime will return error for any error returned by rand.Read or if bits < 2.
1616
func Prime(rand io.Reader, bits int) (*big.Int, error) {
1717
if bits < 2 {
1818
return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
@@ -58,7 +58,8 @@ func Prime(rand io.Reader, bits int) (*big.Int, error) {
5858
}
5959
}
6060

61-
// Int returns a uniform random value in [0, max). It panics if max <= 0.
61+
// Int returns a uniform random value in [0, max). It panics if max <= 0, and
62+
// returns an error if rand.Read returns one.
6263
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
6364
if max.Sign() <= 0 {
6465
panic("crypto/rand: argument to Int is <= 0")

src/runtime/panic.go

+5
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,11 @@ func sync_fatal(s string) {
10331033
fatal(s)
10341034
}
10351035

1036+
//go:linkname rand_fatal crypto/rand.fatal
1037+
func rand_fatal(s string) {
1038+
fatal(s)
1039+
}
1040+
10361041
// throw triggers a fatal error that dumps a stack trace and exits.
10371042
//
10381043
// throw should be used for runtime-internal fatal errors where Go itself,

0 commit comments

Comments
 (0)