diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 601f64fcc8908b..c49a61d4045f84 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -6,6 +6,15 @@ menu "Character devices" source "drivers/tty/Kconfig" +config BSD_RANDOM + bool "random and urandom behave like they do on BSDs" + default n + help + When "y", the character devices for /dev/random and /dev/urandom behave + as they do on BSDs. This means that /dev/urandom will block if it hasn't + been initialized yet, and /dev/random will behave identically to + /dev/urandom. When "n" (the default), the legacy kernel behavior is used. + config DEVMEM bool "/dev/mem virtual device support" default y diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 71025c2f6bbb07..7be287eec4f655 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -797,8 +797,14 @@ static const struct memdev { #endif [5] = { "zero", 0666, &zero_fops, 0 }, [7] = { "full", 0666, &full_fops, 0 }, +#ifdef CONFIG_BSD_RANDOM + [8] = { "random", 0666, &bsd_urandom_fops, 0 }, + [9] = { "urandom", 0666, &bsd_urandom_fops, 0 }, +#else [8] = { "random", 0666, &random_fops, 0 }, [9] = { "urandom", 0666, &urandom_fops, 0 }, +#endif + [13] = { "bsd_urandom", 0666, &bsd_urandom_fops, 0 }, #ifdef CONFIG_PRINTK [11] = { "kmsg", 0644, &kmsg_fops, 0 }, #endif @@ -862,6 +868,13 @@ static int __init chr_dev_init(void) if ((minor == DEVPORT_MINOR) && !arch_has_dev_port()) continue; + /* Do not create a /dev/bsd_urandom, it's for people to mknod + * themselves, if they so choose. + */ + if (minor == 13) { + continue; + } + device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor), NULL, devlist[minor].name); } diff --git a/drivers/char/random.c b/drivers/char/random.c index 0158d3bff7e553..4f8f55a8593c18 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -981,7 +981,11 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) r->entropy_count > r->poolinfo->poolfracbits) return; - if (r->limit == 0 && random_min_urandom_seed) { + /* Only attempt to rate limit transfers of entropy if we're initialized. + Until we are initialized it makes sense to transfer all the entropy we + can. + */ + if (r->limit == 0 && r->initialized && random_min_urandom_seed) { unsigned long now = jiffies; if (time_before(now, @@ -1473,6 +1477,24 @@ urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) return ret; } +static ssize_t +bsd_urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) +{ + if (unlikely(nonblocking_pool.initialized == 0)) { + if (file->f_flags & O_NONBLOCK) { + return -EAGAIN; + } + printk_once(KERN_NOTICE "random: %s bsd urandom read waiting for " + "more entropy, currently %d bits available\n", + current->comm, nonblocking_pool.entropy_total); + wait_event_interruptible(urandom_init_wait, nonblocking_pool.initialized); + if (signal_pending(current)) { + return -ERESTARTSYS; + } + } + return urandom_read(file, buf, nbytes, ppos); +} + static unsigned int random_poll(struct file *file, poll_table * wait) { @@ -1488,6 +1510,18 @@ random_poll(struct file *file, poll_table * wait) return mask; } +static unsigned int +bsd_urandom_poll(struct file *file, poll_table *wait) { + unsigned int mask = 0; + + poll_wait(file, &urandom_init_wait, wait); + mask |= POLLIN | POLLRDNORM; + if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits) { + mask |= POLLOUT | POLLWRNORM; + } + return mask; +} + static int write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { @@ -1599,6 +1633,15 @@ const struct file_operations urandom_fops = { .llseek = noop_llseek, }; +const struct file_operations bsd_urandom_fops = { + .read = bsd_urandom_read, + .write = random_write, + .poll = bsd_urandom_poll, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .llseek = noop_llseek, +}; + SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, unsigned int, flags) { diff --git a/include/linux/random.h b/include/linux/random.h index e47e533742b5e3..6dca91f48a20c7 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -29,7 +29,7 @@ extern void get_random_bytes_arch(void *buf, int nbytes); extern int random_int_secret_init(void); #ifndef MODULE -extern const struct file_operations random_fops, urandom_fops; +extern const struct file_operations random_fops, urandom_fops, bsd_urandom_fops; #endif unsigned int get_random_int(void);