Skip to content
  • Theodore Ts'o's avatar
    random: introduce getrandom(2) system call · c6e9d6f3
    Theodore Ts'o authored
    
    
    The getrandom(2) system call was requested by the LibreSSL Portable
    developers.  It is analoguous to the getentropy(2) system call in
    OpenBSD.
    
    The rationale of this system call is to provide resiliance against
    file descriptor exhaustion attacks, where the attacker consumes all
    available file descriptors, forcing the use of the fallback code where
    /dev/[u]random is not available.  Since the fallback code is often not
    well-tested, it is better to eliminate this potential failure mode
    entirely.
    
    The other feature provided by this new system call is the ability to
    request randomness from the /dev/urandom entropy pool, but to block
    until at least 128 bits of entropy has been accumulated in the
    /dev/urandom entropy pool.  Historically, the emphasis in the
    /dev/urandom development has been to ensure that urandom pool is
    initialized as quickly as possible after system boot, and preferably
    before the init scripts start execution.
    
    This is because changing /dev/urandom reads to block represents an
    interface change that could potentially break userspace which is not
    acceptable.  In practice, on most x86 desktop and server systems, in
    general the entropy pool can be initialized before it is needed (and
    in modern kernels, we will printk a warning message if not).  However,
    on an embedded system, this may not be the case.  And so with this new
    interface, we can provide the functionality of blocking until the
    urandom pool has been initialized.  Any userspace program which uses
    this new functionality must take care to assure that if it is used
    during the boot process, that it will not cause the init scripts or
    other portions of the system startup to hang indefinitely.
    
    SYNOPSIS
    	#include <linux/random.h>
    
    	int getrandom(void *buf, size_t buflen, unsigned int flags);
    
    DESCRIPTION
    	The system call getrandom() fills the buffer pointed to by buf
    	with up to buflen random bytes which can be used to seed user
    	space random number generators (i.e., DRBG's) or for other
    	cryptographic uses.  It should not be used for Monte Carlo
    	simulations or other programs/algorithms which are doing
    	probabilistic sampling.
    
    	If the GRND_RANDOM flags bit is set, then draw from the
    	/dev/random pool instead of the /dev/urandom pool.  The
    	/dev/random pool is limited based on the entropy that can be
    	obtained from environmental noise, so if there is insufficient
    	entropy, the requested number of bytes may not be returned.
    	If there is no entropy available at all, getrandom(2) will
    	either block, or return an error with errno set to EAGAIN if
    	the GRND_NONBLOCK bit is set in flags.
    
    	If the GRND_RANDOM bit is not set, then the /dev/urandom pool
    	will be used.  Unlike using read(2) to fetch data from
    	/dev/urandom, if the urandom pool has not been sufficiently
    	initialized, getrandom(2) will block (or return -1 with the
    	errno set to EAGAIN if the GRND_NONBLOCK bit is set in flags).
    
    	The getentropy(2) system call in OpenBSD can be emulated using
    	the following function:
    
                int getentropy(void *buf, size_t buflen)
                {
                        int     ret;
    
                        if (buflen > 256)
                                goto failure;
                        ret = getrandom(buf, buflen, 0);
                        if (ret < 0)
                                return ret;
                        if (ret == buflen)
                                return 0;
                failure:
                        errno = EIO;
                        return -1;
                }
    
    RETURN VALUE
           On success, the number of bytes that was filled in the buf is
           returned.  This may not be all the bytes requested by the
           caller via buflen if insufficient entropy was present in the
           /dev/random pool, or if the system call was interrupted by a
           signal.
    
           On error, -1 is returned, and errno is set appropriately.
    
    ERRORS
    	EINVAL		An invalid flag was passed to getrandom(2)
    
    	EFAULT		buf is outside the accessible address space.
    
    	EAGAIN		The requested entropy was not available, and
    			getentropy(2) would have blocked if the
    			GRND_NONBLOCK flag was not set.
    
    	EINTR		While blocked waiting for entropy, the call was
    			interrupted by a signal handler; see the description
    			of how interrupted read(2) calls on "slow" devices
    			are handled with and without the SA_RESTART flag
    			in the signal(7) man page.
    
    NOTES
    	For small requests (buflen <= 256) getrandom(2) will not
    	return EINTR when reading from the urandom pool once the
    	entropy pool has been initialized, and it will return all of
    	the bytes that have been requested.  This is the recommended
    	way to use getrandom(2), and is designed for compatibility
    	with OpenBSD's getentropy() system call.
    
    	However, if you are using GRND_RANDOM, then getrandom(2) may
    	block until the entropy accounting determines that sufficient
    	environmental noise has been gathered such that getrandom(2)
    	will be operating as a NRBG instead of a DRBG for those people
    	who are working in the NIST SP 800-90 regime.  Since it may
    	block for a long time, these guarantees do *not* apply.  The
    	user may want to interrupt a hanging process using a signal,
    	so blocking until all of the requested bytes are returned
    	would be unfriendly.
    
    	For this reason, the user of getrandom(2) MUST always check
    	the return value, in case it returns some error, or if fewer
    	bytes than requested was returned.  In the case of
    	!GRND_RANDOM and small request, the latter should never
    	happen, but the careful userspace code (and all crypto code
    	should be careful) should check for this anyway!
    
    	Finally, unless you are doing long-term key generation (and
    	perhaps not even then), you probably shouldn't be using
    	GRND_RANDOM.  The cryptographic algorithms used for
    	/dev/urandom are quite conservative, and so should be
    	sufficient for all purposes.  The disadvantage of GRND_RANDOM
    	is that it can block, and the increased complexity required to
    	deal with partially fulfilled getrandom(2) requests.
    
    Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
    Reviewed-by: default avatarZach Brown <zab@zabbo.net>
    c6e9d6f3