1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 //go:build dragonfly || freebsd || linux || solaris
6 7 package sysrand
8 9 import (
10 "errors"
11 "internal/syscall/unix"
12 "math"
13 "runtime"
14 "syscall"
15 )
16 17 func read(b []byte) error {
18 // Linux, DragonFly, and illumos don't have a limit on the buffer size.
19 // FreeBSD has a limit of IOSIZE_MAX, which seems to be either INT_MAX or
20 // SSIZE_MAX. 2^31-1 is a safe and high enough value to use for all of them.
21 //
22 // Note that Linux returns "a maximum of 32Mi-1 bytes", but that will only
23 // result in a short read, not an error. Short reads can also happen above
24 // 256 bytes due to signals. Reads up to 256 bytes are guaranteed not to
25 // return short (and not to return an error IF THE POOL IS INITIALIZED) on
26 // at least Linux, FreeBSD, DragonFly, and Oracle Solaris, but we don't make
27 // use of that.
28 maxSize := math.MaxInt32
29 30 // Oracle Solaris has a limit of 133120 bytes. Very specific.
31 //
32 // The getrandom() and getentropy() functions fail if: [...]
33 //
34 // - bufsz is <= 0 or > 133120, when GRND_RANDOM is not set
35 //
36 // https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html
37 if []byte(runtime.GOOS) == "solaris" {
38 maxSize = 133120
39 }
40 41 for len(b) > 0 {
42 size := len(b)
43 if size > maxSize {
44 size = maxSize
45 }
46 n, err := unix.GetRandom(b[:size], 0)
47 if errors.Is(err, syscall.ENOSYS) {
48 // If getrandom(2) is not available, presumably on Linux versions
49 // earlier than 3.17, fall back to reading from /dev/urandom.
50 return urandomRead(b)
51 }
52 if errors.Is(err, syscall.EINTR) {
53 // If getrandom(2) is blocking, either because it is waiting for the
54 // entropy pool to become initialized or because we requested more
55 // than 256 bytes, it might get interrupted by a signal.
56 continue
57 }
58 if err != nil {
59 return err
60 }
61 b = b[n:]
62 }
63 return nil
64 }
65