Cleanups and bug fixes to /dev/random, add a new getrandom(2) system

call, which is a superset of OpenBSD's getentropy(2) call, for use
 with userspace crypto libraries such as LibreSSL.  Also add the
 ability to have a kernel thread to pull entropy from hardware rng
 devices into /dev/random.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJT4VkhAAoJENNvdpvBGATwGMwP/0DvcJnk8Xg2pE67GrBlkL4V
 ltDYZBUNI3Z9YqPFMbN02kt8jBJ4o8NVrD9XXSAmk0NbNV6pc4SdGUU7BBcms4BF
 DX4CasmQS1EMKOxsszlvEbj9Q25u9ODJhUKsr1ZQKe3wfjx1gKRQ1QHHcrqgbGc0
 tjkBU/TW+8daza6dGYrUrO34BPeN5Y4xbBG5WmVOLGgbDH7J3ZKGzkG21R5zHraI
 tPJzZ3KGj+Cf1TtamBOpyF+SLqM7qi43JY/1l8LfDzJgJhB3NxOR1ig/Pk6z1qLi
 2xYm1hb+EQqJGaToMXEl5fLLcYfnJmLYD/dWNq/pOVXFqC5cGxYIH1h+Nwzywvy3
 hVqh4yDU5HXgu8mOMPPc23azicJflZwCNq0vTTDE+orYnb8n9Sbg0l+rUQ45BZua
 tVfGKT1LZuYtM0axYQ4fIfqS9bxsyRJcF6HNNaEMQJsm0V0prwlz0hXkaod1uOJd
 CwOn9+CpZUGCgj5paRS+zTOtcl39+X1tIhcWTHEDMpMzIqnk8KpkLGqCDisBZNBF
 UbjEaTA8w6tBxRX5FZ9qdmRFvsxCJH7nOxmmsaIOZ/7QXQHQNrxI2+v6yd4HWJAw
 yZnaVR5o6sojKc8zp9nOXQ219G1zvt4l6XyTqIP+gKWJGDKGCsMXXzEg1OchO+rI
 Oo8s5+ytZB9qei7QwLAf
 =wLqJ
 -----END PGP SIGNATURE-----

Merge tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random

Pull randomness updates from Ted Ts'o:
 "Cleanups and bug fixes to /dev/random, add a new getrandom(2) system
  call, which is a superset of OpenBSD's getentropy(2) call, for use
  with userspace crypto libraries such as LibreSSL.

  Also add the ability to have a kernel thread to pull entropy from
  hardware rng devices into /dev/random"

* tag 'random_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/random:
  hwrng: Pass entropy to add_hwgenerator_randomness() in bits, not bytes
  random: limit the contribution of the hw rng to at most half
  random: introduce getrandom(2) system call
  hw_random: fix sparse warning (NULL vs 0 for pointer)
  random: use registers from interrupted code for CPU's w/o a cycle counter
  hwrng: add per-device entropy derating
  hwrng: create filler thread
  random: add_hwgenerator_randomness() for feeding entropy from devices
  random: use an improved fast_mix() function
  random: clean up interrupt entropy accounting for archs w/o cycle counters
  random: only update the last_pulled time if we actually transferred entropy
  random: remove unneeded hash of a portion of the entropy pool
  random: always update the entropy pool under the spinlock
This commit is contained in:
Linus Torvalds 2014-08-06 08:16:24 -07:00
commit f4f142ed4e
8 changed files with 273 additions and 130 deletions

View File

@ -361,3 +361,4 @@
352 i386 sched_getattr sys_sched_getattr
353 i386 renameat2 sys_renameat2
354 i386 seccomp sys_seccomp
355 i386 getrandom sys_getrandom

View File

@ -324,6 +324,7 @@
315 common sched_getattr sys_sched_getattr
316 common renameat2 sys_renameat2
317 common seccomp sys_seccomp
318 common getrandom sys_getrandom
#
# x32-specific system call numbers start at 512 to avoid cache impact

View File

@ -38,6 +38,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/kthread.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/random.h>
@ -50,10 +51,22 @@
static struct hwrng *current_rng;
static struct task_struct *hwrng_fill;
static LIST_HEAD(rng_list);
static DEFINE_MUTEX(rng_mutex);
static int data_avail;
static u8 *rng_buffer;
static u8 *rng_buffer, *rng_fillbuf;
static unsigned short current_quality;
static unsigned short default_quality; /* = 0; default to "off" */
module_param(current_quality, ushort, 0644);
MODULE_PARM_DESC(current_quality,
"current hwrng entropy estimation per mill");
module_param(default_quality, ushort, 0644);
MODULE_PARM_DESC(default_quality,
"default entropy content of hwrng per mill");
static void start_khwrngd(void);
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
int wait);
@ -89,6 +102,15 @@ static inline int hwrng_init(struct hwrng *rng)
return ret;
}
add_early_randomness(rng);
current_quality = rng->quality ? : default_quality;
current_quality &= 1023;
if (current_quality == 0 && hwrng_fill)
kthread_stop(hwrng_fill);
if (current_quality > 0 && !hwrng_fill)
start_khwrngd();
return 0;
}
@ -325,6 +347,36 @@ err_misc_dereg:
goto out;
}
static int hwrng_fillfn(void *unused)
{
long rc;
while (!kthread_should_stop()) {
if (!current_rng)
break;
rc = rng_get_data(current_rng, rng_fillbuf,
rng_buffer_size(), 1);
if (rc <= 0) {
pr_warn("hwrng: no data available\n");
msleep_interruptible(10000);
continue;
}
add_hwgenerator_randomness((void *)rng_fillbuf, rc,
rc * current_quality * 8 >> 10);
}
hwrng_fill = NULL;
return 0;
}
static void start_khwrngd(void)
{
hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
if (hwrng_fill == ERR_PTR(-ENOMEM)) {
pr_err("hwrng_fill thread creation failed");
hwrng_fill = NULL;
}
}
int hwrng_register(struct hwrng *rng)
{
int err = -EINVAL;
@ -343,6 +395,13 @@ int hwrng_register(struct hwrng *rng)
if (!rng_buffer)
goto out_unlock;
}
if (!rng_fillbuf) {
rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
if (!rng_fillbuf) {
kfree(rng_buffer);
goto out_unlock;
}
}
/* Must not register two RNGs with the same name. */
err = -EEXIST;
@ -406,8 +465,11 @@ void hwrng_unregister(struct hwrng *rng)
current_rng = NULL;
}
}
if (list_empty(&rng_list))
if (list_empty(&rng_list)) {
unregister_miscdev();
if (hwrng_fill)
kthread_stop(hwrng_fill);
}
mutex_unlock(&rng_mutex);
}
@ -418,6 +480,7 @@ static void __exit hwrng_exit(void)
mutex_lock(&rng_mutex);
BUG_ON(current_rng);
kfree(rng_buffer);
kfree(rng_fillbuf);
mutex_unlock(&rng_mutex);
}

View File

@ -250,6 +250,7 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/percpu.h>
#include <linux/cryptohash.h>
#include <linux/fips.h>
@ -257,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>
@ -267,6 +270,8 @@
#define CREATE_TRACE_POINTS
#include <trace/events/random.h>
/* #define ADD_INTERRUPT_BENCH */
/*
* Configuration information
*/
@ -401,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;
/**********************************************************************
@ -481,9 +487,9 @@ static __u32 const twist_table[8] = {
* the entropy is concentrated in the low-order bits.
*/
static void _mix_pool_bytes(struct entropy_store *r, const void *in,
int nbytes, __u8 out[64])
int nbytes)
{
unsigned long i, j, tap1, tap2, tap3, tap4, tap5;
unsigned long i, tap1, tap2, tap3, tap4, tap5;
int input_rotate;
int wordmask = r->poolinfo->poolwords - 1;
const char *bytes = in;
@ -495,9 +501,8 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in,
tap4 = r->poolinfo->tap4;
tap5 = r->poolinfo->tap5;
smp_rmb();
input_rotate = ACCESS_ONCE(r->input_rotate);
i = ACCESS_ONCE(r->add_ptr);
input_rotate = r->input_rotate;
i = r->add_ptr;
/* mix one byte at a time to simplify size handling and churn faster */
while (nbytes--) {
@ -524,39 +529,33 @@ static void _mix_pool_bytes(struct entropy_store *r, const void *in,
input_rotate = (input_rotate + (i ? 7 : 14)) & 31;
}
ACCESS_ONCE(r->input_rotate) = input_rotate;
ACCESS_ONCE(r->add_ptr) = i;
smp_wmb();
if (out)
for (j = 0; j < 16; j++)
((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
r->input_rotate = input_rotate;
r->add_ptr = i;
}
static void __mix_pool_bytes(struct entropy_store *r, const void *in,
int nbytes, __u8 out[64])
int nbytes)
{
trace_mix_pool_bytes_nolock(r->name, nbytes, _RET_IP_);
_mix_pool_bytes(r, in, nbytes, out);
_mix_pool_bytes(r, in, nbytes);
}
static void mix_pool_bytes(struct entropy_store *r, const void *in,
int nbytes, __u8 out[64])
int nbytes)
{
unsigned long flags;
trace_mix_pool_bytes(r->name, nbytes, _RET_IP_);
spin_lock_irqsave(&r->lock, flags);
_mix_pool_bytes(r, in, nbytes, out);
_mix_pool_bytes(r, in, nbytes);
spin_unlock_irqrestore(&r->lock, flags);
}
struct fast_pool {
__u32 pool[4];
unsigned long last;
unsigned short count;
unsigned char rotate;
unsigned char last_timer_intr;
unsigned short reg_idx;
unsigned char count;
};
/*
@ -564,25 +563,29 @@ struct fast_pool {
* collector. It's hardcoded for an 128 bit pool and assumes that any
* locks that might be needed are taken by the caller.
*/
static void fast_mix(struct fast_pool *f, __u32 input[4])
static void fast_mix(struct fast_pool *f)
{
__u32 w;
unsigned input_rotate = f->rotate;
__u32 a = f->pool[0], b = f->pool[1];
__u32 c = f->pool[2], d = f->pool[3];
w = rol32(input[0], input_rotate) ^ f->pool[0] ^ f->pool[3];
f->pool[0] = (w >> 3) ^ twist_table[w & 7];
input_rotate = (input_rotate + 14) & 31;
w = rol32(input[1], input_rotate) ^ f->pool[1] ^ f->pool[0];
f->pool[1] = (w >> 3) ^ twist_table[w & 7];
input_rotate = (input_rotate + 7) & 31;
w = rol32(input[2], input_rotate) ^ f->pool[2] ^ f->pool[1];
f->pool[2] = (w >> 3) ^ twist_table[w & 7];
input_rotate = (input_rotate + 7) & 31;
w = rol32(input[3], input_rotate) ^ f->pool[3] ^ f->pool[2];
f->pool[3] = (w >> 3) ^ twist_table[w & 7];
input_rotate = (input_rotate + 7) & 31;
a += b; c += d;
b = rol32(a, 6); d = rol32(c, 27);
d ^= a; b ^= c;
f->rotate = input_rotate;
a += b; c += d;
b = rol32(a, 16); d = rol32(c, 14);
d ^= a; b ^= c;
a += b; c += d;
b = rol32(a, 6); d = rol32(c, 27);
d ^= a; b ^= c;
a += b; c += d;
b = rol32(a, 16); d = rol32(c, 14);
d ^= a; b ^= c;
f->pool[0] = a; f->pool[1] = b;
f->pool[2] = c; f->pool[3] = d;
f->count++;
}
@ -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);
}
}
@ -739,13 +743,13 @@ void add_device_randomness(const void *buf, unsigned int size)
trace_add_device_randomness(size, _RET_IP_);
spin_lock_irqsave(&input_pool.lock, flags);
_mix_pool_bytes(&input_pool, buf, size, NULL);
_mix_pool_bytes(&input_pool, &time, sizeof(time), NULL);
_mix_pool_bytes(&input_pool, buf, size);
_mix_pool_bytes(&input_pool, &time, sizeof(time));
spin_unlock_irqrestore(&input_pool.lock, flags);
spin_lock_irqsave(&nonblocking_pool.lock, flags);
_mix_pool_bytes(&nonblocking_pool, buf, size, NULL);
_mix_pool_bytes(&nonblocking_pool, &time, sizeof(time), NULL);
_mix_pool_bytes(&nonblocking_pool, buf, size);
_mix_pool_bytes(&nonblocking_pool, &time, sizeof(time));
spin_unlock_irqrestore(&nonblocking_pool.lock, flags);
}
EXPORT_SYMBOL(add_device_randomness);
@ -778,7 +782,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num)
sample.cycles = random_get_entropy();
sample.num = num;
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
mix_pool_bytes(r, &sample, sizeof(sample), NULL);
mix_pool_bytes(r, &sample, sizeof(sample));
/*
* Calculate number of bits of randomness we probably added.
@ -835,6 +839,38 @@ EXPORT_SYMBOL_GPL(add_input_randomness);
static DEFINE_PER_CPU(struct fast_pool, irq_randomness);
#ifdef ADD_INTERRUPT_BENCH
static unsigned long avg_cycles, avg_deviation;
#define AVG_SHIFT 8 /* Exponential average factor k=1/256 */
#define FIXED_1_2 (1 << (AVG_SHIFT-1))
static void add_interrupt_bench(cycles_t start)
{
long delta = random_get_entropy() - start;
/* Use a weighted moving average */
delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT);
avg_cycles += delta;
/* And average deviation */
delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT);
avg_deviation += delta;
}
#else
#define add_interrupt_bench(x)
#endif
static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
{
__u32 *ptr = (__u32 *) regs;
if (regs == NULL)
return 0;
if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32))
f->reg_idx = 0;
return *(ptr + f->reg_idx++);
}
void add_interrupt_randomness(int irq, int irq_flags)
{
struct entropy_store *r;
@ -842,55 +878,52 @@ void add_interrupt_randomness(int irq, int irq_flags)
struct pt_regs *regs = get_irq_regs();
unsigned long now = jiffies;
cycles_t cycles = random_get_entropy();
__u32 input[4], c_high, j_high;
__u32 c_high, j_high;
__u64 ip;
unsigned long seed;
int credit;
int credit = 0;
if (cycles == 0)
cycles = get_reg(fast_pool, regs);
c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
input[0] = cycles ^ j_high ^ irq;
input[1] = now ^ c_high;
fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
fast_pool->pool[1] ^= now ^ c_high;
ip = regs ? instruction_pointer(regs) : _RET_IP_;
input[2] = ip;
input[3] = ip >> 32;
fast_pool->pool[2] ^= ip;
fast_pool->pool[3] ^= (sizeof(ip) > 4) ? ip >> 32 :
get_reg(fast_pool, regs);
fast_mix(fast_pool, input);
fast_mix(fast_pool);
add_interrupt_bench(cycles);
if ((fast_pool->count & 63) && !time_after(now, fast_pool->last + HZ))
if ((fast_pool->count < 64) &&
!time_after(now, fast_pool->last + HZ))
return;
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
if (!spin_trylock(&r->lock))
return;
fast_pool->last = now;
r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool;
__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL);
/*
* If we don't have a valid cycle counter, and we see
* back-to-back timer interrupts, then skip giving credit for
* any entropy, otherwise credit 1 bit.
*/
credit = 1;
if (cycles == 0) {
if (irq_flags & __IRQF_TIMER) {
if (fast_pool->last_timer_intr)
credit = 0;
fast_pool->last_timer_intr = 1;
} else
fast_pool->last_timer_intr = 0;
}
__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool));
/*
* If we have architectural seed generator, produce a seed and
* add it to the pool. For the sake of paranoia count it as
* 50% entropic.
* add it to the pool. For the sake of paranoia don't let the
* architectural seed generator dominate the input from the
* interrupt noise.
*/
if (arch_get_random_seed_long(&seed)) {
__mix_pool_bytes(r, &seed, sizeof(seed), NULL);
credit += sizeof(seed) * 4;
__mix_pool_bytes(r, &seed, sizeof(seed));
credit = 1;
}
spin_unlock(&r->lock);
credit_entropy_bits(r, credit);
fast_pool->count = 0;
/* award one bit for the contents of the fast pool */
credit_entropy_bits(r, credit + 1);
}
#ifdef CONFIG_BLOCK
@ -922,6 +955,11 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf,
static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes);
static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
{
if (!r->pull ||
r->entropy_count >= (nbytes << (ENTROPY_SHIFT + 3)) ||
r->entropy_count > r->poolinfo->poolfracbits)
return;
if (r->limit == 0 && random_min_urandom_seed) {
unsigned long now = jiffies;
@ -930,10 +968,8 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
return;
r->last_pulled = now;
}
if (r->pull &&
r->entropy_count < (nbytes << (ENTROPY_SHIFT + 3)) &&
r->entropy_count < r->poolinfo->poolfracbits)
_xfer_secondary_pool(r, nbytes);
_xfer_secondary_pool(r, nbytes);
}
static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
@ -953,7 +989,7 @@ static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes)
ENTROPY_BITS(r), ENTROPY_BITS(r->pull));
bytes = extract_entropy(r->pull, tmp, bytes,
random_read_wakeup_bits / 8, rsvd_bytes);
mix_pool_bytes(r, tmp, bytes, NULL);
mix_pool_bytes(r, tmp, bytes);
credit_entropy_bits(r, bytes*8);
}
@ -1039,7 +1075,6 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
unsigned long l[LONGS(20)];
} hash;
__u32 workspace[SHA_WORKSPACE_WORDS];
__u8 extract[64];
unsigned long flags;
/*
@ -1068,15 +1103,9 @@ static void extract_buf(struct entropy_store *r, __u8 *out)
* brute-forcing the feedback as hard as brute-forcing the
* hash.
*/
__mix_pool_bytes(r, hash.w, sizeof(hash.w), extract);
__mix_pool_bytes(r, hash.w, sizeof(hash.w));
spin_unlock_irqrestore(&r->lock, flags);
/*
* To avoid duplicates, we atomically extract a portion of the
* pool while mixing, and hash one final time.
*/
sha_transform(hash.w, extract, workspace);
memset(extract, 0, sizeof(extract));
memset(workspace, 0, sizeof(workspace));
/*
@ -1160,13 +1189,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;
@ -1263,14 +1293,14 @@ static void init_std_data(struct entropy_store *r)
unsigned long rv;
r->last_pulled = jiffies;
mix_pool_bytes(r, &now, sizeof(now), NULL);
mix_pool_bytes(r, &now, sizeof(now));
for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) {
if (!arch_get_random_seed_long(&rv) &&
!arch_get_random_long(&rv))
rv = random_get_entropy();
mix_pool_bytes(r, &rv, sizeof(rv), NULL);
mix_pool_bytes(r, &rv, sizeof(rv));
}
mix_pool_bytes(r, utsname(), sizeof(*(utsname())), NULL);
mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
}
/*
@ -1309,39 +1339,8 @@ void rand_initialize_disk(struct gendisk *disk)
}
#endif
/*
* Attempt an emergency refill using arch_get_random_seed_long().
*
* As with add_interrupt_randomness() be paranoid and only
* credit the output as 50% entropic.
*/
static int arch_random_refill(void)
{
const unsigned int nlongs = 64; /* Arbitrary number */
unsigned int n = 0;
unsigned int i;
unsigned long buf[nlongs];
if (!arch_has_random_seed())
return 0;
for (i = 0; i < nlongs; i++) {
if (arch_get_random_seed_long(&buf[n]))
n++;
}
if (n) {
unsigned int rand_bytes = n * sizeof(unsigned long);
mix_pool_bytes(&input_pool, buf, rand_bytes, NULL);
credit_entropy_bits(&input_pool, rand_bytes*4);
}
return n;
}
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;
@ -1360,12 +1359,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
return n;
/* Pool is (near) empty. Maybe wait and retry. */
/* First try an emergency refill */
if (arch_random_refill())
continue;
if (file->f_flags & O_NONBLOCK)
if (nonblock)
return -EAGAIN;
wait_event_interruptible(random_read_wait,
@ -1376,6 +1370,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)
{
@ -1424,7 +1424,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count)
count -= bytes;
p += bytes;
mix_pool_bytes(r, buf, bytes, NULL);
mix_pool_bytes(r, buf, bytes);
cond_resched();
}
@ -1520,6 +1520,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
*
@ -1663,6 +1686,22 @@ struct ctl_table random_table[] = {
.mode = 0444,
.proc_handler = proc_do_uuid,
},
#ifdef ADD_INTERRUPT_BENCH
{
.procname = "add_interrupt_avg_cycles",
.data = &avg_cycles,
.maxlen = sizeof(avg_cycles),
.mode = 0444,
.proc_handler = proc_doulongvec_minmax,
},
{
.procname = "add_interrupt_avg_deviation",
.data = &avg_deviation,
.maxlen = sizeof(avg_deviation),
.mode = 0444,
.proc_handler = proc_doulongvec_minmax,
},
#endif
{ }
};
#endif /* CONFIG_SYSCTL */
@ -1719,3 +1758,23 @@ randomize_range(unsigned long start, unsigned long end, unsigned long len)
return 0;
return PAGE_ALIGN(get_random_int() % range + start);
}
/* Interface for in-kernel drivers of true hardware RNGs.
* Those devices may produce endless random bits and will be throttled
* when our pool is full.
*/
void add_hwgenerator_randomness(const char *buffer, size_t count,
size_t entropy)
{
struct entropy_store *poolp = &input_pool;
/* Suspend writing if we're above the trickle threshold.
* We'll be woken up again once below random_write_wakeup_thresh,
* or when the calling thread is about to terminate.
*/
wait_event_interruptible(random_write_wait, kthread_should_stop() ||
ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits);
mix_pool_bytes(poolp, buffer, count);
credit_entropy_bits(poolp, entropy);
}
EXPORT_SYMBOL_GPL(add_hwgenerator_randomness);

View File

@ -29,6 +29,8 @@
* @read: New API. drivers can fill up to max bytes of data
* into the buffer. The buffer is aligned for any type.
* @priv: Private data, for use by the RNG driver.
* @quality: Estimation of true entropy in RNG's bitstream
* (per mill).
*/
struct hwrng {
const char *name;
@ -38,6 +40,7 @@ struct hwrng {
int (*data_read)(struct hwrng *rng, u32 *data);
int (*read)(struct hwrng *rng, void *data, size_t max, bool wait);
unsigned long priv;
unsigned short quality;
/* internal. */
struct list_head list;
@ -47,5 +50,7 @@ struct hwrng {
extern int hwrng_register(struct hwrng *rng);
/** Unregister a Hardware Random Number Generator driver. */
extern void hwrng_unregister(struct hwrng *rng);
/** Feed random bits into the pool. */
extern void add_hwgenerator_randomness(const char *buffer, size_t count, size_t entropy);
#endif /* LINUX_HWRANDOM_H_ */

View File

@ -868,4 +868,7 @@ asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type,
asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags);
asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
const char __user *uargs);
asmlinkage long sys_getrandom(char __user *buf, size_t count,
unsigned int flags);
#endif

View File

@ -701,9 +701,11 @@ __SYSCALL(__NR_sched_getattr, sys_sched_getattr)
__SYSCALL(__NR_renameat2, sys_renameat2)
#define __NR_seccomp 277
__SYSCALL(__NR_seccomp, sys_seccomp)
#define __NR_getrandom 278
__SYSCALL(__NR_getrandom, sys_getrandom)
#undef __NR_syscalls
#define __NR_syscalls 278
#define __NR_syscalls 279
/*
* All syscalls below here should go away really,

View File

@ -40,4 +40,13 @@ struct rand_pool_info {
__u32 buf[0];
};
/*
* Flags for getrandom(2)
*
* GRND_NONBLOCK Don't block and return EAGAIN instead
* GRND_RANDOM Use the /dev/random pool instead of /dev/urandom
*/
#define GRND_NONBLOCK 0x0001
#define GRND_RANDOM 0x0002
#endif /* _UAPI_LINUX_RANDOM_H */