diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:16:24 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-06 11:16:24 -0400 |
| commit | f4f142ed4ef835709c7e6d12eaca10d190bcebed (patch) | |
| tree | a0bc6850239fe3551bb67f5707bfef153ac437fe /drivers | |
| parent | bb2cbf5e9367d8598fecd0c48dead69560750223 (diff) | |
| parent | e02b876597777ab26288dd2611a97b597d14d661 (diff) | |
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
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/char/hw_random/core.c | 67 | ||||
| -rw-r--r-- | drivers/char/random.c | 315 |
2 files changed, 252 insertions, 130 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index c4419ea1ab07..6e02ec103cc7 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/fs.h> | 38 | #include <linux/fs.h> |
| 39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
| 40 | #include <linux/miscdevice.h> | 40 | #include <linux/miscdevice.h> |
| 41 | #include <linux/kthread.h> | ||
| 41 | #include <linux/delay.h> | 42 | #include <linux/delay.h> |
| 42 | #include <linux/slab.h> | 43 | #include <linux/slab.h> |
| 43 | #include <linux/random.h> | 44 | #include <linux/random.h> |
| @@ -50,10 +51,22 @@ | |||
| 50 | 51 | ||
| 51 | 52 | ||
| 52 | static struct hwrng *current_rng; | 53 | static struct hwrng *current_rng; |
| 54 | static struct task_struct *hwrng_fill; | ||
| 53 | static LIST_HEAD(rng_list); | 55 | static LIST_HEAD(rng_list); |
| 54 | static DEFINE_MUTEX(rng_mutex); | 56 | static DEFINE_MUTEX(rng_mutex); |
| 55 | static int data_avail; | 57 | static int data_avail; |
| 56 | static u8 *rng_buffer; | 58 | static u8 *rng_buffer, *rng_fillbuf; |
| 59 | static unsigned short current_quality; | ||
| 60 | static unsigned short default_quality; /* = 0; default to "off" */ | ||
| 61 | |||
| 62 | module_param(current_quality, ushort, 0644); | ||
| 63 | MODULE_PARM_DESC(current_quality, | ||
| 64 | "current hwrng entropy estimation per mill"); | ||
| 65 | module_param(default_quality, ushort, 0644); | ||
| 66 | MODULE_PARM_DESC(default_quality, | ||
| 67 | "default entropy content of hwrng per mill"); | ||
| 68 | |||
| 69 | static void start_khwrngd(void); | ||
| 57 | 70 | ||
| 58 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, | 71 | static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, |
| 59 | int wait); | 72 | int wait); |
| @@ -89,6 +102,15 @@ static inline int hwrng_init(struct hwrng *rng) | |||
| 89 | return ret; | 102 | return ret; |
| 90 | } | 103 | } |
| 91 | add_early_randomness(rng); | 104 | add_early_randomness(rng); |
| 105 | |||
| 106 | current_quality = rng->quality ? : default_quality; | ||
| 107 | current_quality &= 1023; | ||
| 108 | |||
| 109 | if (current_quality == 0 && hwrng_fill) | ||
| 110 | kthread_stop(hwrng_fill); | ||
| 111 | if (current_quality > 0 && !hwrng_fill) | ||
| 112 | start_khwrngd(); | ||
| 113 | |||
| 92 | return 0; | 114 | return 0; |
| 93 | } | 115 | } |
| 94 | 116 | ||
| @@ -325,6 +347,36 @@ err_misc_dereg: | |||
| 325 | goto out; | 347 | goto out; |
| 326 | } | 348 | } |
| 327 | 349 | ||
| 350 | static int hwrng_fillfn(void *unused) | ||
| 351 | { | ||
| 352 | long rc; | ||
| 353 | |||
| 354 | while (!kthread_should_stop()) { | ||
| 355 | if (!current_rng) | ||
| 356 | break; | ||
| 357 | rc = rng_get_data(current_rng, rng_fillbuf, | ||
| 358 | rng_buffer_size(), 1); | ||
| 359 | if (rc <= 0) { | ||
| 360 | pr_warn("hwrng: no data available\n"); | ||
| 361 | msleep_interruptible(10000); | ||
| 362 | continue; | ||
| 363 | } | ||
| 364 | add_hwgenerator_randomness((void *)rng_fillbuf, rc, | ||
| 365 | rc * current_quality * 8 >> 10); | ||
| 366 | } | ||
| 367 | hwrng_fill = NULL; | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static void start_khwrngd(void) | ||
| 372 | { | ||
| 373 | hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); | ||
| 374 | if (hwrng_fill == ERR_PTR(-ENOMEM)) { | ||
| 375 | pr_err("hwrng_fill thread creation failed"); | ||
| 376 | hwrng_fill = NULL; | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 328 | int hwrng_register(struct hwrng *rng) | 380 | int hwrng_register(struct hwrng *rng) |
| 329 | { | 381 | { |
| 330 | int err = -EINVAL; | 382 | int err = -EINVAL; |
| @@ -343,6 +395,13 @@ int hwrng_register(struct hwrng *rng) | |||
| 343 | if (!rng_buffer) | 395 | if (!rng_buffer) |
| 344 | goto out_unlock; | 396 | goto out_unlock; |
| 345 | } | 397 | } |
| 398 | if (!rng_fillbuf) { | ||
| 399 | rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL); | ||
| 400 | if (!rng_fillbuf) { | ||
| 401 | kfree(rng_buffer); | ||
| 402 | goto out_unlock; | ||
| 403 | } | ||
| 404 | } | ||
| 346 | 405 | ||
| 347 | /* Must not register two RNGs with the same name. */ | 406 | /* Must not register two RNGs with the same name. */ |
| 348 | err = -EEXIST; | 407 | err = -EEXIST; |
| @@ -406,8 +465,11 @@ void hwrng_unregister(struct hwrng *rng) | |||
| 406 | current_rng = NULL; | 465 | current_rng = NULL; |
| 407 | } | 466 | } |
| 408 | } | 467 | } |
| 409 | if (list_empty(&rng_list)) | 468 | if (list_empty(&rng_list)) { |
| 410 | unregister_miscdev(); | 469 | unregister_miscdev(); |
| 470 | if (hwrng_fill) | ||
| 471 | kthread_stop(hwrng_fill); | ||
| 472 | } | ||
| 411 | 473 | ||
| 412 | mutex_unlock(&rng_mutex); | 474 | mutex_unlock(&rng_mutex); |
| 413 | } | 475 | } |
| @@ -418,6 +480,7 @@ static void __exit hwrng_exit(void) | |||
| 418 | mutex_lock(&rng_mutex); | 480 | mutex_lock(&rng_mutex); |
| 419 | BUG_ON(current_rng); | 481 | BUG_ON(current_rng); |
| 420 | kfree(rng_buffer); | 482 | kfree(rng_buffer); |
| 483 | kfree(rng_fillbuf); | ||
| 421 | mutex_unlock(&rng_mutex); | 484 | mutex_unlock(&rng_mutex); |
| 422 | } | 485 | } |
| 423 | 486 | ||
diff --git a/drivers/char/random.c b/drivers/char/random.c index 71529e196b84..c18d41db83d8 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -250,6 +250,7 @@ | |||
| 250 | #include <linux/interrupt.h> | 250 | #include <linux/interrupt.h> |
| 251 | #include <linux/mm.h> | 251 | #include <linux/mm.h> |
| 252 | #include <linux/spinlock.h> | 252 | #include <linux/spinlock.h> |
| 253 | #include <linux/kthread.h> | ||
| 253 | #include <linux/percpu.h> | 254 | #include <linux/percpu.h> |
| 254 | #include <linux/cryptohash.h> | 255 | #include <linux/cryptohash.h> |
| 255 | #include <linux/fips.h> | 256 | #include <linux/fips.h> |
| @@ -257,6 +258,8 @@ | |||
| 257 | #include <linux/kmemcheck.h> | 258 | #include <linux/kmemcheck.h> |
| 258 | #include <linux/workqueue.h> | 259 | #include <linux/workqueue.h> |
| 259 | #include <linux/irq.h> | 260 | #include <linux/irq.h> |
| 261 | #include <linux/syscalls.h> | ||
| 262 | #include <linux/completion.h> | ||
| 260 | 263 | ||
| 261 | #include <asm/processor.h> | 264 | #include <asm/processor.h> |
| 262 | #include <asm/uaccess.h> | 265 | #include <asm/uaccess.h> |
| @@ -267,6 +270,8 @@ | |||
| 267 | #define CREATE_TRACE_POINTS | 270 | #define CREATE_TRACE_POINTS |
| 268 | #include <trace/events/random.h> | 271 | #include <trace/events/random.h> |
| 269 | 272 | ||
| 273 | /* #define ADD_INTERRUPT_BENCH */ | ||
| 274 | |||
| 270 | /* | 275 | /* |
| 271 | * Configuration information | 276 | * Configuration information |
| 272 | */ | 277 | */ |
| @@ -401,6 +406,7 @@ static struct poolinfo { | |||
| 401 | */ | 406 | */ |
| 402 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); | 407 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); |
| 403 | static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); | 408 | static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); |
| 409 | static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait); | ||
| 404 | static struct fasync_struct *fasync; | 410 | static struct fasync_struct *fasync; |
| 405 | 411 | ||
| 406 | /********************************************************************** | 412 | /********************************************************************** |
| @@ -481,9 +487,9 @@ static __u32 const twist_table[8] = { | |||
| 481 | * the entropy is concentrated in the low-order bits. | 487 | * the entropy is concentrated in the low-order bits. |
| 482 | */ | 488 | */ |
| 483 | static void _mix_pool_bytes(struct entropy_store *r, const void *in, | ||
