// 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 rand 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 }