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/random.c | 40 | ||||
| -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 |
6 files changed, 54 insertions, 4 deletions
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl index d6b867921612..5b46a618aeb1 100644 --- a/arch/x86/syscalls/syscall_32.tbl +++ b/arch/x86/syscalls/syscall_32.tbl | |||
| @@ -360,3 +360,4 @@ | |||
| 360 | 351 i386 sched_setattr sys_sched_setattr | 360 | 351 i386 sched_setattr sys_sched_setattr |
| 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 | 355 i386 getrandom sys_getrandom | ||
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl index ec255a1646d2..0dc4bf891460 100644 --- a/arch/x86/syscalls/syscall_64.tbl +++ b/arch/x86/syscalls/syscall_64.tbl | |||
| @@ -323,6 +323,7 @@ | |||
| 323 | 314 common sched_setattr sys_sched_setattr | 323 | 314 common sched_setattr sys_sched_setattr |
| 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 | 318 common getrandom sys_getrandom | ||
| 326 | 327 | ||
| 327 | # | 328 | # |
| 328 | # x32-specific system call numbers start at 512 to avoid cache impact | 329 | # x32-specific system call numbers start at 512 to avoid cache impact |
diff --git a/drivers/char/random.c b/drivers/char/random.c index aa22fe551c2a..7d1682ea1e86 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -258,6 +258,8 @@ | |||
| 258 | #include <linux/kmemcheck.h> | 258 | #include <linux/kmemcheck.h> |
| 259 | #include <linux/workqueue.h> | 259 | #include <linux/workqueue.h> |
| 260 | #include <linux/irq.h> | 260 | #include <linux/irq.h> |
| 261 | #include <linux/syscalls.h> | ||
| 262 | #include <linux/completion.h> | ||
| 261 | 263 | ||
| 262 | #include <asm/processor.h> | 264 | #include <asm/processor.h> |
| 263 | #include <asm/uaccess.h> | 265 | #include <asm/uaccess.h> |
| @@ -404,6 +406,7 @@ static struct poolinfo { | |||
| 404 | */ | 406 | */ |
| 405 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); | 407 | static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); |
| 406 | 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); | ||
| 407 | static struct fasync_struct *fasync; | 410 | static struct fasync_struct *fasync; |
| 408 | 411 | ||
| 409 | /********************************************************************** | 412 | /********************************************************************** |
| @@ -657,6 +660,7 @@ retry: | |||
| 657 | r->entropy_total = 0; | 660 | r->entropy_total = 0; |
| 658 | if (r == &nonblocking_pool) { | 661 | if (r == &nonblocking_pool) { |
| 659 | prandom_reseed_late(); | 662 | prandom_reseed_late(); |
| 663 | wake_up_interruptible(&urandom_init_wait); | ||
| 660 | pr_notice("random: %s pool is initialized\n", r->name); | 664 | pr_notice("random: %s pool is initialized\n", r->name); |
| 661 | } | 665 | } |
| 662 | } | 666 | } |
| @@ -1174,13 +1178,14 @@ static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, | |||
| 1174 | { | 1178 | { |
| 1175 | ssize_t ret = 0, i; | 1179 | ssize_t ret = 0, i; |
| 1176 | __u8 tmp[EXTRACT_SIZE]; | 1180 | __u8 tmp[EXTRACT_SIZE]; |
| 1181 | int large_request = (nbytes > 256); | ||
| 1177 | 1182 | ||
| 1178 | trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); | 1183 | trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); |
| 1179 | xfer_secondary_pool(r, nbytes); | 1184 | xfer_secondary_pool(r, nbytes); |
| 1180 | nbytes = account(r, nbytes, 0, 0); | 1185 | nbytes = account(r, nbytes, 0, 0); |
| 1181 | 1186 | ||
| 1182 | while (nbytes) { | 1187 | while (nbytes) { |
| 1183 | if (need_resched()) { | 1188 | if (large_request && need_resched()) { |
| 1184 | if (signal_pending(current)) { | 1189 | if (signal_pending(current)) { |
| 1185 | if (ret == 0) | 1190 | if (ret == 0) |
| 1186 | ret = -ERESTARTSYS; | 1191 | ret = -ERESTARTSYS; |
| @@ -1355,7 +1360,7 @@ static int arch_random_refill(void) | |||
| 1355 | } | 1360 | } |
| 1356 | 1361 | ||
| 1357 | static ssize_t | 1362 | static ssize_t |
| 1358 | random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | 1363 | _random_read(int nonblock, char __user *buf, size_t nbytes) |
| 1359 | { | 1364 | { |
| 1360 | ssize_t n; | 1365 | ssize_t n; |
| 1361 | 1366 | ||
| @@ -1379,7 +1384,7 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
| 1379 | if (arch_random_refill()) | 1384 | if (arch_random_refill()) |
| 1380 | continue; | 1385 | continue; |
| 1381 | 1386 | ||
| 1382 | if (file->f_flags & O_NONBLOCK) | 1387 | if (nonblock) |
| 1383 | return -EAGAIN; | 1388 | return -EAGAIN; |
| 1384 | 1389 | ||
| 1385 | wait_event_interruptible(random_read_wait, | 1390 | wait_event_interruptible(random_read_wait, |
| @@ -1391,6 +1396,12 @@ random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | |||
| 1391 | } | 1396 | } |
| 1392 | 1397 | ||
| 1393 | static ssize_t | 1398 | static ssize_t |
| 1399 | random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | ||
| 1400 | { | ||
| 1401 | return _random_read(file->f_flags & O_NONBLOCK, buf, nbytes); | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | static ssize_t | ||
| 1394 | urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | 1405 | urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) |
| 1395 | { | 1406 | { |
| 1396 | int ret; | 1407 | int ret; |
| @@ -1533,6 +1544,29 @@ const struct file_operations urandom_fops = { | |||
| 1533 | .llseek = noop_llseek, | 1544 | .llseek = noop_llseek, |
| 1534 | }; | 1545 | }; |
| 1535 | 1546 | ||
| 1547 | SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, | ||
| 1548 | unsigned int, flags) | ||
| 1549 | { | ||
| 1550 | if (flags & ~(GRND_NONBLOCK|GRND_RANDOM)) | ||
| 1551 | return -EINVAL; | ||
| 1552 | |||
| 1553 | if (count > INT_MAX) | ||
| 1554 | count = INT_MAX; | ||
| 1555 | |||
| 1556 | if (flags & GRND_RANDOM) | ||
| 1557 | return _random_read(flags & GRND_NONBLOCK, buf, count); | ||
| 1558 | |||
| 1559 | if (unlikely(nonblocking_pool.initialized == 0)) { | ||
| 1560 | if (flags & GRND_NONBLOCK) | ||
| 1561 | return -EAGAIN; | ||
| 1562 | wait_event_interruptible(urandom_init_wait, | ||
| 1563 | nonblocking_pool.initialized); | ||
| 1564 | if (signal_pending(current)) | ||
| 1565 | return -ERESTARTSYS; | ||
| 1566 | } | ||
| 1567 | return urandom_read(NULL, buf, count, NULL); | ||
| 1568 | } | ||
| 1569 | |||
| 1536 | /*************************************************************** | 1570 | /*************************************************************** |
| 1537 | * Random UUID interface | 1571 | * Random UUID interface |
| 1538 | * | 1572 | * |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b0881a0ed322..43324a897cf2 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
| @@ -866,4 +866,7 @@ asmlinkage long sys_process_vm_writev(pid_t pid, | |||
| 866 | asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, | 866 | asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, |
| 867 | unsigned long idx1, unsigned long idx2); | 867 | unsigned long idx1, unsigned long idx2); |
| 868 | asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); | 868 | asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); |
| 869 | asmlinkage long sys_getrandom(char __user *buf, size_t count, | ||
| 870 | unsigned int flags); | ||
| 871 | |||
| 869 | #endif | 872 | #endif |
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 333640608087..1d104a2ca643 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h | |||
| @@ -699,9 +699,11 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr) | |||
| 699 | __SYSCALL(__NR_sched_getattr, sys_sched_getattr) | 699 | __SYSCALL(__NR_sched_getattr, sys_sched_getattr) |
| 700 | #define __NR_renameat2 276 | 700 | #define __NR_renameat2 276 |
| 701 | __SYSCALL(__NR_renameat2, sys_renameat2) | 701 | __SYSCALL(__NR_renameat2, sys_renameat2) |
| 702 | #define __NR_getrandom 278 | ||
| 703 | __SYSCALL(__NR_getrandom, sys_getrandom) | ||
| 702 | 704 | ||
| 703 | #undef __NR_syscalls | 705 | #undef __NR_syscalls |
| 704 | #define __NR_syscalls 277 | 706 | #define __NR_syscalls 279 |
| 705 | 707 | ||
| 706 | /* | 708 | /* |
| 707 | * All syscalls below here should go away really, | 709 | * All syscalls below here should go away really, |
diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index fff3528a078f..3f93d1695e7f 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h | |||
| @@ -40,4 +40,13 @@ struct rand_pool_info { | |||
| 40 | __u32 buf[0]; | 40 | __u32 buf[0]; |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | /* | ||
| 44 | * Flags for getrandom(2) | ||
| 45 | * | ||
| 46 | * GRND_NONBLOCK Don't block and return EAGAIN instead | ||
| 47 | * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom | ||
| 48 | */ | ||
| 49 | #define GRND_NONBLOCK 0x0001 | ||
| 50 | #define GRND_RANDOM 0x0002 | ||
| 51 | |||
| 43 | #endif /* _UAPI_LINUX_RANDOM_H */ | 52 | #endif /* _UAPI_LINUX_RANDOM_H */ |
