diff options
author | Aleksa Sarai <cyphar@cyphar.com> | 2019-09-30 21:10:55 -0400 |
---|---|---|
committer | Christian Brauner <christian.brauner@ubuntu.com> | 2019-10-01 09:45:22 -0400 |
commit | c2ba8f41ad366dc12840dd87d8f1565185845126 (patch) | |
tree | 7e6407dae5d248995ecbc56b808f49d8b687fd70 /kernel | |
parent | dff3a85feceade213daf153556fd32a3b0a73c63 (diff) |
perf_event_open: switch to copy_struct_from_user()
Switch perf_event_open() syscall from it's own copying
struct perf_event_attr from userspace to the new dedicated
copy_struct_from_user() helper.
The change is very straightforward, and helps unify the syscall
interface for struct-from-userspace syscalls.
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Reviewed-by: Christian Brauner <christian.brauner@ubuntu.com>
[christian.brauner@ubuntu.com: improve commit message]
Link: https://lore.kernel.org/r/20191001011055.19283-5-cyphar@cyphar.com
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/core.c | 47 |
1 files changed, 9 insertions, 38 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index 4655adbbae10..3f0cb82e4fbc 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -10586,55 +10586,26 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, | |||
10586 | u32 size; | 10586 | u32 size; |
10587 | int ret; | 10587 | int ret; |
10588 | 10588 | ||
10589 | if (!access_ok(uattr, PERF_ATTR_SIZE_VER0)) | 10589 | /* Zero the full structure, so that a short copy will be nice. */ |
10590 | return -EFAULT; | ||
10591 | |||
10592 | /* | ||
10593 | * zero the full structure, so that a short copy will be nice. | ||
10594 | */ | ||
10595 | memset(attr, 0, sizeof(*attr)); | 10590 | memset(attr, 0, sizeof(*attr)); |
10596 | 10591 | ||
10597 | ret = get_user(size, &uattr->size); | 10592 | ret = get_user(size, &uattr->size); |
10598 | if (ret) | 10593 | if (ret) |
10599 | return ret; | 10594 | return ret; |
10600 | 10595 | ||
10601 | if (size > PAGE_SIZE) /* silly large */ | 10596 | /* ABI compatibility quirk: */ |
10602 | goto err_size; | 10597 | if (!size) |
10603 | |||
10604 | if (!size) /* abi compat */ | ||
10605 | size = PERF_ATTR_SIZE_VER0; | 10598 | size = PERF_ATTR_SIZE_VER0; |
10606 | 10599 | if (size < PERF_ATTR_SIZE_VER0 || size > PAGE_SIZE) | |
10607 | if (size < PERF_ATTR_SIZE_VER0) | ||
10608 | goto err_size; | 10600 | goto err_size; |
10609 | 10601 | ||
10610 | /* | 10602 | ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size); |
10611 | * If we're handed a bigger struct than we know of, | 10603 | if (ret) { |
10612 | * ensure all the unknown bits are 0 - i.e. new | 10604 | if (ret == -E2BIG) |
10613 | * user-space does not rely on any kernel feature | 10605 | goto err_size; |
10614 | * extensions we dont know about yet. | 10606 | return ret; |
10615 | */ | ||
10616 | if (size > sizeof(*attr)) { | ||
10617 | unsigned char __user *addr; | ||
10618 | unsigned char __user *end; | ||
10619 | unsigned char val; | ||
10620 | |||
10621 | addr = (void __user *)uattr + sizeof(*attr); | ||
10622 | end = (void __user *)uattr + size; | ||
10623 | |||
10624 | for (; addr < end; addr++) { | ||
10625 | ret = get_user(val, addr); | ||
10626 | if (ret) | ||
10627 | return ret; | ||
10628 | if (val) | ||
10629 | goto err_size; | ||
10630 | } | ||
10631 | size = sizeof(*attr); | ||
10632 | } | 10607 | } |
10633 | 10608 | ||
10634 | ret = copy_from_user(attr, uattr, size); | ||
10635 | if (ret) | ||
10636 | return -EFAULT; | ||
10637 | |||
10638 | attr->size = size; | 10609 | attr->size = size; |
10639 | 10610 | ||
10640 | if (attr->__reserved_1) | 10611 | if (attr->__reserved_1) |