linux-crypto.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andy Lutomirski <luto@amacapital.net>
To: Theodore Ts'o <tytso@mit.edu>, linux-kernel@vger.kernel.org
Cc: linux-abi@vger.kernel.org, linux-crypto@vger.kernel.org,
	beck@openbsd.org
Subject: Re: [PATCH, RFC] random: introduce getrandom(2) system call
Date: Thu, 17 Jul 2014 13:27:06 -0700	[thread overview]
Message-ID: <53C8319A.8090108@amacapital.net> (raw)
In-Reply-To: <1405588695-12014-1-git-send-email-tytso@mit.edu>

On 07/17/2014 02:18 AM, Theodore Ts'o wrote:
> 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 hte case.  And so with a new interface, we can provide
> this requested functionality of blocking until the urandom pool has
> been initialized.  Any userspace program which uses this new
> functionality must make sure that if it is used in early boot, that it
> will not cause the boot up 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 processes.  It should not be used Monte Carlo
> 	simulations or for other probabilistic sampling applications.
> 
> 	If the GRND_RANDOM flags bit is set, then draw from the
> 	/dev/random pool instead of /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 return an error with errno set to EAGAIN, or block if
> 	the GRND_BLOCK flags bit is set.
> 
> 	If the GRND_RANDOM flags bit is not set, then the /dev/raundom
> 	pool will be used.  Unlike reading from the /dev/urandom, if
> 	the urandom pool has not been sufficiently initialized,
> 	getrandom(2) will either return an error with errno set to
> 	EGAIN, or block if the GRND_BLOCK flags bit is set.
> 
> RETURN VALUE
>        On success, the number of bytes that was returned is returned.
> 
>        On error, -1 is returned, and errno is set appropriately
> 
> ERRORS
> 	EINVAL		The buflen value was invalid.
> 
> 	EFAULT		buf is outside your accessible address space.
> 
> 	EAGAIN		The requested entropy was not available, and the
> 			getentropy(2) would have blocked if GRND_BLOCK flag
> 			was set.
> 
> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
> ---
>  arch/x86/syscalls/syscall_32.tbl  |  1 +
>  arch/x86/syscalls/syscall_64.tbl  |  1 +
>  drivers/char/random.c             | 35 +++++++++++++++++++++++++++++++++--
>  include/linux/syscalls.h          |  3 +++
>  include/uapi/asm-generic/unistd.h |  4 +++-
>  include/uapi/linux/random.h       |  9 +++++++++
>  6 files changed, 50 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
> index d6b8679..f484e39 100644
> --- a/arch/x86/syscalls/syscall_32.tbl
> +++ b/arch/x86/syscalls/syscall_32.tbl
> @@ -360,3 +360,4 @@
>  351	i386	sched_setattr		sys_sched_setattr
>  352	i386	sched_getattr		sys_sched_getattr
>  353	i386	renameat2		sys_renameat2
> +354	i386	getrandom		sys_getrandom
> diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
> index ec255a1..6705032 100644
> --- a/arch/x86/syscalls/syscall_64.tbl
> +++ b/arch/x86/syscalls/syscall_64.tbl
> @@ -323,6 +323,7 @@
>  314	common	sched_setattr		sys_sched_setattr
>  315	common	sched_getattr		sys_sched_getattr
>  316	common	renameat2		sys_renameat2
> +317	common	getrandom		sys_getrandom
>  
>  #
>  # x32-specific system call numbers start at 512 to avoid cache impact
> diff --git a/drivers/char/random.c b/drivers/char/random.c
> index aa22fe5..76a56f6 100644
> --- a/drivers/char/random.c
> +++ b/drivers/char/random.c
> @@ -258,6 +258,8 @@
>  #include <linux/kmemcheck.h>
>  #include <linux/workqueue.h>
>  #include <linux/irq.h>
> +#include <linux/syscalls.h>
> +#include <linux/completion.h>
>  
>  #include <asm/processor.h>
>  #include <asm/uaccess.h>
> @@ -469,6 +471,8 @@ static struct entropy_store nonblocking_pool = {
>  					push_to_pool),
>  };
>  
> +DECLARE_COMPLETION(urandom_initialized);
> +
>  static __u32 const twist_table[8] = {
>  	0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
>  	0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
> @@ -657,6 +661,7 @@ retry:
>  		r->entropy_total = 0;
>  		if (r == &nonblocking_pool) {
>  			prandom_reseed_late();
> +			complete_all(&urandom_initialized);
>  			pr_notice("random: %s pool is initialized\n", r->name);
>  		}
>  	}
> @@ -1355,7 +1360,7 @@ static int arch_random_refill(void)
>  }
>  
>  static ssize_t
> -random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
> +_random_read(int nonblock, char __user *buf, size_t nbytes)
>  {
>  	ssize_t n;
>  
> @@ -1379,7 +1384,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
>  		if (arch_random_refill())
>  			continue;
>  
> -		if (file->f_flags & O_NONBLOCK)
> +		if (nonblock)
>  			return -EAGAIN;
>  
>  		wait_event_interruptible(random_read_wait,
> @@ -1391,6 +1396,12 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
>  }
>  
>  static ssize_t
> +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
> +{
> +	return _random_read(file->f_flags & O_NONBLOCK, buf, nbytes);
> +}
> +
> +static ssize_t
>  urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
>  {
>  	int ret;
> @@ -1533,6 +1544,26 @@ const struct file_operations urandom_fops = {
>  	.llseek = noop_llseek,
>  };
>  
> +SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
> +		unsigned int, flags)
> +{
> +	int r;
> +

As previously noted, this needs to validate flags.

> +	if (count > 256)
> +		return -EINVAL;

I think I'd rather see this allow any length, at least when using urandom.

> +
> +	if (flags & GRND_RANDOM) {
> +		return _random_read(!(flags & GRND_BLOCK), buf, count);
> +	}
> +	if (flags & GRND_BLOCK) {
> +		r = wait_for_completion_interruptible(&urandom_initialized);
> +		if (r)
> +			return r;
> +	} else if (!completion_done(&urandom_initialized))
> +		return -EAGAIN;
> +	return urandom_read(NULL, buf, count, NULL);

This can return -ERESTARTSYS.  Does it need any logic to restart correctly?

I don't think it's possible for the urandom case to succeed without
filling the buffer.  If that's true, can we document it and add a
corresponding BUG_ON/WARN_ON in the syscall implementation?

--Andy

> +/*
> + * Flags for getrandom(2)
> + *
> + * GAND_BLOCK 		Allow getrandom(2) to block
> + * GAND_RANDOM		Use the /dev/random pool instead of /dev/urandom

GRND?

> + */
> +#define GRND_BLOCK	0x0001
> +#define GRND_RANDOM	0x0002
> +
>  #endif /* _UAPI_LINUX_RANDOM_H */
> 

  parent reply	other threads:[~2014-07-17 20:27 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-17  9:18 [PATCH, RFC] random: introduce getrandom(2) system call Theodore Ts'o
2014-07-17 10:57 ` Hannes Frederic Sowa
2014-07-17 12:52   ` Theodore Ts'o
2014-07-17 13:15     ` Hannes Frederic Sowa
2014-07-17 12:09 ` Tobias Klauser
2014-07-17 12:52   ` Theodore Ts'o
2014-07-17 16:12 ` Christoph Hellwig
2014-07-17 17:01   ` Theodore Ts'o
2014-07-17 17:05     ` Bob Beck
2014-07-17 17:34       ` Theodore Ts'o
2014-07-17 17:45         ` Bob Beck
2014-07-17 17:46           ` Bob Beck
2014-07-17 17:57             ` Bob Beck
2014-07-17 22:30           ` Theodore Ts'o
2014-07-17 19:56         ` Bob Beck
2014-07-21  0:25     ` Dwayne Litzenberger
2014-07-21  7:18       ` Theodore Ts'o
2014-07-17 19:31 ` Greg KH
2014-07-17 19:33 ` Greg KH
2014-07-17 19:48 ` Zach Brown
     [not found]   ` <20140717194812.GC24196-fypN+1c5dIyjpB87vu3CluTW4wlIGRCZ@public.gmane.org>
2014-07-17 20:54     ` Theodore Ts'o
     [not found]       ` <20140717205417.GT1491-AKGzg7BKzIDYtjvyW6yDsg@public.gmane.org>
2014-07-17 21:39         ` Zach Brown
2014-07-17 20:27 ` Andy Lutomirski [this message]
     [not found]   ` <53C8319A.8090108-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
2014-07-17 21:14     ` Theodore Ts'o
2014-07-18 16:36 ` Rolf Eike Beer
2014-07-20 15:50 ` Andi Kleen
2014-07-20 17:06   ` Theodore Ts'o
2014-07-20 17:27 ` Andreas Schwab
2014-07-20 17:41   ` Theodore Ts'o
2014-07-21  6:18 ` Dwayne Litzenberger
2014-07-23  8:42 ` Manuel Schölling
  -- strict thread matches above, loose matches on Subject: below --
2014-07-17 18:48 Mark Kettenis
2014-07-17 20:35 ` Andy Lutomirski
2014-07-17 21:28   ` Theodore Ts'o
2014-07-17 21:37     ` Andy Lutomirski
2014-07-17 22:21   ` David Lang
2014-07-20 16:26 George Spelvin
2014-07-20 17:03 ` George Spelvin
2014-07-20 21:32   ` Hannes Frederic Sowa
2014-07-21 11:21     ` George Spelvin
2014-07-21 15:27       ` Hannes Frederic Sowa
2014-07-22  1:02         ` Hannes Frederic Sowa
2014-07-22  4:44           ` Theodore Ts'o
2014-07-22  9:49             ` Hannes Frederic Sowa
2014-07-22 22:59               ` Theodore Ts'o
2014-07-23  9:47                 ` Hannes Frederic Sowa
2014-07-23 11:52                   ` George Spelvin
2014-07-23 12:10                     ` Hannes Frederic Sowa
2014-07-30 12:50                       ` Pavel Machek
2014-07-20 17:24 ` Theodore Ts'o

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53C8319A.8090108@amacapital.net \
    --to=luto@amacapital.net \
    --cc=beck@openbsd.org \
    --cc=linux-abi@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).