diff options
Diffstat (limited to 'fs/select.c')
-rw-r--r-- | fs/select.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/select.c b/fs/select.c index 8ed9da50896a..3d4f85defeab 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/sched/rt.h> | 29 | #include <linux/sched/rt.h> |
30 | #include <linux/freezer.h> | 30 | #include <linux/freezer.h> |
31 | #include <net/busy_poll.h> | 31 | #include <net/busy_poll.h> |
32 | #include <linux/vmalloc.h> | ||
32 | 33 | ||
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
34 | 35 | ||
@@ -554,7 +555,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
554 | fd_set_bits fds; | 555 | fd_set_bits fds; |
555 | void *bits; | 556 | void *bits; |
556 | int ret, max_fds; | 557 | int ret, max_fds; |
557 | unsigned int size; | 558 | size_t size, alloc_size; |
558 | struct fdtable *fdt; | 559 | struct fdtable *fdt; |
559 | /* Allocate small arguments on the stack to save memory and be faster */ | 560 | /* Allocate small arguments on the stack to save memory and be faster */ |
560 | long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; | 561 | long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; |
@@ -581,7 +582,14 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
581 | if (size > sizeof(stack_fds) / 6) { | 582 | if (size > sizeof(stack_fds) / 6) { |
582 | /* Not enough space in on-stack array; must use kmalloc */ | 583 | /* Not enough space in on-stack array; must use kmalloc */ |
583 | ret = -ENOMEM; | 584 | ret = -ENOMEM; |
584 | bits = kmalloc(6 * size, GFP_KERNEL); | 585 | if (size > (SIZE_MAX / 6)) |
586 | goto out_nofds; | ||
587 | |||
588 | alloc_size = 6 * size; | ||
589 | bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN); | ||
590 | if (!bits && alloc_size > PAGE_SIZE) | ||
591 | bits = vmalloc(alloc_size); | ||
592 | |||
585 | if (!bits) | 593 | if (!bits) |
586 | goto out_nofds; | 594 | goto out_nofds; |
587 | } | 595 | } |
@@ -618,7 +626,7 @@ int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, | |||
618 | 626 | ||
619 | out: | 627 | out: |
620 | if (bits != stack_fds) | 628 | if (bits != stack_fds) |
621 | kfree(bits); | 629 | kvfree(bits); |
622 | out_nofds: | 630 | out_nofds: |
623 | return ret; | 631 | return ret; |
624 | } | 632 | } |