|
@@ -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>
|
|
@@ -404,6 +406,7 @@ static struct poolinfo {
|
|
|
*/
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
|
|
|
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
|
|
|
+static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait);
|
|
|
static struct fasync_struct *fasync;
|
|
|
|
|
|
/**********************************************************************
|
|
@@ -657,6 +660,7 @@ retry:
|
|
|
r->entropy_total = 0;
|
|
|
if (r == &nonblocking_pool) {
|
|
|
prandom_reseed_late();
|
|
|
+ wake_up_interruptible(&urandom_init_wait);
|
|
|
pr_notice("random: %s pool is initialized\n", r->name);
|
|
|
}
|
|
|
}
|
|
@@ -1174,13 +1178,14 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
|
|
|
{
|
|
|
ssize_t ret = 0, i;
|
|
|
__u8 tmp[EXTRACT_SIZE];
|
|
|
+ int large_request = (nbytes > 256);
|
|
|
|
|
|
trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
|
|
|
xfer_secondary_pool(r, nbytes);
|
|
|
nbytes = account(r, nbytes, 0, 0);
|
|
|
|
|
|
while (nbytes) {
|
|
|
- if (need_resched()) {
|
|
|
+ if (large_request && need_resched()) {
|
|
|
if (signal_pending(current)) {
|
|
|
if (ret == 0)
|
|
|
ret = -ERESTARTSYS;
|
|
@@ -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,
|
|
@@ -1390,6 +1395,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)
|
|
|
{
|
|
@@ -1533,6 +1544,29 @@ const struct file_operations urandom_fops = {
|
|
|
.llseek = noop_llseek,
|
|
|
};
|
|
|
|
|
|
+SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
|
|
|
+ unsigned int, flags)
|
|
|
+{
|
|
|
+ if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (count > INT_MAX)
|
|
|
+ count = INT_MAX;
|
|
|
+
|
|
|
+ if (flags & GRND_RANDOM)
|
|
|
+ return _random_read(flags & GRND_NONBLOCK, buf, count);
|
|
|
+
|
|
|
+ if (unlikely(nonblocking_pool.initialized == 0)) {
|
|
|
+ if (flags & GRND_NONBLOCK)
|
|
|
+ return -EAGAIN;
|
|
|
+ wait_event_interruptible(urandom_init_wait,
|
|
|
+ nonblocking_pool.initialized);
|
|
|
+ if (signal_pending(current))
|
|
|
+ return -ERESTARTSYS;
|
|
|
+ }
|
|
|
+ return urandom_read(NULL, buf, count, NULL);
|
|
|
+}
|
|
|
+
|
|
|
/***************************************************************
|
|
|
* Random UUID interface
|
|
|
*
|