aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hw_random
diff options
context:
space:
mode:
authorTorsten Duwe <duwe@lst.de>2014-06-14 23:46:03 -0400
committerTheodore Ts'o <tytso@mit.edu>2014-07-15 04:49:40 -0400
commitbe4000bc4644d027c519b6361f5ae3bbfc52c347 (patch)
tree4ce9e61ae36a8261d41d8bae1a4c8a78b3d04416 /drivers/char/hw_random
parentc84dbf61a7b322188d2a7fddc0cc6317ac6713e2 (diff)
hwrng: create filler thread
This can be viewed as the in-kernel equivalent of hwrngd; like FUSE it is a good thing to have a mechanism in user land, but for some reasons (simplicity, secrecy, integrity, speed) it may be better to have it in kernel space. This patch creates a thread once a hwrng registers, and uses the previously established add_hwgenerator_randomness() to feed its data to the input pool as long as needed. A derating factor is used to bias the entropy estimation and to disable this mechanism entirely when set to zero. Signed-off-by: Torsten Duwe <duwe@suse.de> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Acked-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'drivers/char/hw_random')
-rw-r--r--drivers/char/hw_random/core.c69
1 files changed, 64 insertions, 5 deletions
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 334601cc81cf..48b3c812b9ec 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,18 @@
50 51
51 52
52static struct hwrng *current_rng; 53static struct hwrng *current_rng;
54static struct task_struct *hwrng_fill;
53static LIST_HEAD(rng_list); 55static LIST_HEAD(rng_list);
54static DEFINE_MUTEX(rng_mutex); 56static DEFINE_MUTEX(rng_mutex);
55static int data_avail; 57static int data_avail;
56static u8 *rng_buffer; 58static u8 *rng_buffer, *rng_fillbuf;
59static unsigned short current_quality = 700; /* an arbitrary 70% */
60
61module_param(current_quality, ushort, 0644);
62MODULE_PARM_DESC(current_quality,
63 "current hwrng entropy estimation per mill");
64
65static void start_khwrngd(void);
57 66
58static size_t rng_buffer_size(void) 67static size_t rng_buffer_size(void)
59{ 68{
@@ -62,9 +71,18 @@ static size_t rng_buffer_size(void)
62 71
63static inline int hwrng_init(struct hwrng *rng) 72static inline int hwrng_init(struct hwrng *rng)
64{ 73{
65 if (!rng->init) 74 int err;
66 return 0; 75
67 return rng->init(rng); 76 if (rng->init) {
77 err = rng->init(rng);
78 if (err)
79 return err;
80 }
81
82 if (current_quality > 0 && !hwrng_fill)
83 start_khwrngd();
84
85 return 0;
68} 86}
69 87
70static inline void hwrng_cleanup(struct hwrng *rng) 88static inline void hwrng_cleanup(struct hwrng *rng)
@@ -300,6 +318,36 @@ err_misc_dereg:
300 goto out; 318 goto out;
301} 319}
302 320
321static int hwrng_fillfn(void *unused)
322{
323 long rc;
324
325 while (!kthread_should_stop()) {
326 if (!current_rng)
327 break;
328 rc = rng_get_data(current_rng, rng_fillbuf,
329 rng_buffer_size(), 1);
330 if (rc <= 0) {
331 pr_warn("hwrng: no data available\n");
332 msleep_interruptible(10000);
333 continue;
334 }
335 add_hwgenerator_randomness((void *)rng_fillbuf, rc,
336 (rc*current_quality)>>10);
337 }
338 hwrng_fill = 0;
339 return 0;
340}
341
342static void start_khwrngd(void)
343{
344 hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng");
345 if (hwrng_fill == ERR_PTR(-ENOMEM)) {
346 pr_err("hwrng_fill thread creation failed");
347 hwrng_fill = NULL;
348 }
349}
350
303int hwrng_register(struct hwrng *rng) 351int hwrng_register(struct hwrng *rng)
304{ 352{
305 int err = -EINVAL; 353 int err = -EINVAL;
@@ -320,6 +368,13 @@ int hwrng_register(struct hwrng *rng)
320 if (!rng_buffer) 368 if (!rng_buffer)
321 goto out_unlock; 369 goto out_unlock;
322 } 370 }
371 if (!rng_fillbuf) {
372 rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL);
373 if (!rng_fillbuf) {
374 kfree(rng_buffer);
375 goto out_unlock;
376 }
377 }
323 378
324 /* Must not register two RNGs with the same name. */ 379 /* Must not register two RNGs with the same name. */
325 err = -EEXIST; 380 err = -EEXIST;
@@ -375,8 +430,11 @@ void hwrng_unregister(struct hwrng *rng)
375 current_rng = NULL; 430 current_rng = NULL;
376 } 431 }
377 } 432 }
378 if (list_empty(&rng_list)) 433 if (list_empty(&rng_list)) {
379 unregister_miscdev(); 434 unregister_miscdev();
435 if (hwrng_fill)
436 kthread_stop(hwrng_fill);
437 }
380 438
381 mutex_unlock(&rng_mutex); 439 mutex_unlock(&rng_mutex);
382} 440}
@@ -387,6 +445,7 @@ static void __exit hwrng_exit(void)
387 mutex_lock(&rng_mutex); 445 mutex_lock(&rng_mutex);
388 BUG_ON(current_rng); 446 BUG_ON(current_rng);
389 kfree(rng_buffer); 447 kfree(rng_buffer);
448 kfree(rng_fillbuf);
390 mutex_unlock(&rng_mutex); 449 mutex_unlock(&rng_mutex);
391} 450}
392 451