diff options
| -rw-r--r-- | arch/x86/syscalls/syscall_32.tbl | 1 | ||||
| -rw-r--r-- | arch/x86/syscalls/syscall_64.tbl | 1 | ||||
| -rw-r--r-- | drivers/char/hw_random/core.c | 67 | ||||
| -rw-r--r-- | drivers/char/random.c | 315 | ||||
| -rw-r--r-- | include/linux/hw_random.h | 5 | ||||
| -rw-r--r-- | include/linux/syscalls.h | 3 | ||||
| -rw-r--r-- | include/uapi/asm-generic/unistd.h | 4 | ||||
| -rw-r--r-- | include/uapi/linux/random.h | 9 |
8 files changed, 274 insertions, 131 deletions
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index 7527eac24122..d1b4a119d4a5 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl | |||
| @@ -361,3 +361,4 @@ | |||
| 361 | 352 i386 sched_getattr sys_sched_getattr | 361 | 352 i386 sched_getattr sys_sched_getattr |
| 362 | 353 i386 renameat2 sys_renameat2 | 362 | 353 i386 renameat2 sys_renameat2 |
| 363 | 354 i386 seccomp sys_seccomp | 363 | 354 i386 seccomp sys_seccomp |
| 364 | 355 i386 getrandom sys_getrandom | ||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index 16272a6c12b7..252c804bb1aa 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl | |||
| @@ -324,6 +324,7 @@ | |||
| 324 | 315 common sched_getattr sys_sched_getattr | 324 | 315 common sched_getattr sys_sched_getattr |
| 325 | 316 common renameat2 sys_renameat2 | 325 | 316 common renameat2 sys_renameat2 |
| 326 | 317 common seccomp sys_seccomp | 326 | 317 common seccomp sys_seccomp |
| 327 | 318 common getrandom sys_getrandom | ||
| 327 | 328 | ||
| 328 | # | 329 | # |
| 329 | # x32-specific system call numbers start at 512 to avoid cache impact | 330 | # x32-specific system call numbers start at 512 to avoid cache impact |
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 */ | ||
