| // Copyright 2014 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. |
| |
| //go:build dragonfly || freebsd || linux || solaris |
| |
| package sysrand |
| |
| import ( |
| "errors" |
| "internal/syscall/unix" |
| "math" |
| "runtime" |
| "syscall" |
| ) |
| |
| func read(b []byte) error { |
| // Linux, DragonFly, and illumos don't have a limit on the buffer size. |
| // FreeBSD has a limit of IOSIZE_MAX, which seems to be either INT_MAX or |
| // SSIZE_MAX. 2^31-1 is a safe and high enough value to use for all of them. |
| // |
| // Note that Linux returns "a maximum of 32Mi-1 bytes", but that will only |
| // result in a short read, not an error. Short reads can also happen above |
| // 256 bytes due to signals. Reads up to 256 bytes are guaranteed not to |
| // return short (and not to return an error IF THE POOL IS INITIALIZED) on |
| // at least Linux, FreeBSD, DragonFly, and Oracle Solaris, but we don't make |
| // use of that. |
| maxSize := math.MaxInt32 |
| |
| // Oracle Solaris has a limit of 133120 bytes. Very specific. |
| // |
| // The getrandom() and getentropy() functions fail if: [...] |
| // |
| // - bufsz is <= 0 or > 133120, when GRND_RANDOM is not set |
| // |
| // https://docs.oracle.com/cd/E88353_01/html/E37841/getrandom-2.html |
| if runtime.GOOS == "solaris" { |
| maxSize = 133120 |
| } |
| |
| for len(b) > 0 { |
| size := len(b) |
| if size > maxSize { |
| size = maxSize |
| } |
| n, err := unix.GetRandom(b[:size], 0) |
| if errors.Is(err, syscall.ENOSYS) { |
| // If getrandom(2) is not available, presumably on Linux versions |
| // earlier than 3.17, fall back to reading from /dev/urandom. |
| return urandomRead(b) |
| } |
| if errors.Is(err, syscall.EINTR) { |
| // If getrandom(2) is blocking, either because it is waiting for the |
| // entropy pool to become initialized or because we requested more |
| // than 256 bytes, it might get interrupted by a signal. |
| continue |
| } |
| if err != nil { |
| return err |
| } |
| b = b[n:] |
| } |
| return nil |
| } |