diff options
author | Matthew Wilcox (Oracle) <willy@infradead.org> | 2022-01-10 23:15:28 +0000 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2022-04-13 12:15:51 -0700 |
commit | 0aef499f3172a60222ae7460d61b364c134d6e1a (patch) | |
tree | 5e358ea58cd25805b0b588bdbe198fb9d28e6733 /mm | |
parent | 4e140f59d285c1ca1e5c81b4c13e27366865bd09 (diff) |
mm/usercopy: Detect vmalloc overruns
If you have a vmalloc() allocation, or an address from calling vmap(),
you cannot overrun the vm_area which describes it, regardless of the
size of the underlying allocation. This probably doesn't do much for
security because vmalloc comes with guard pages these days, but it
prevents usercopy aborts when copying to a vmap() of smaller pages.
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20220110231530.665970-3-willy@infradead.org
Diffstat (limited to 'mm')
-rw-r--r-- | mm/usercopy.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/mm/usercopy.c b/mm/usercopy.c index ff13e7708faa..e1e856dca124 100644 --- a/mm/usercopy.c +++ b/mm/usercopy.c @@ -17,6 +17,7 @@ #include <linux/sched/task.h> #include <linux/sched/task_stack.h> #include <linux/thread_info.h> +#include <linux/vmalloc.h> #include <linux/atomic.h> #include <linux/jump_label.h> #include <asm/sections.h> @@ -238,6 +239,21 @@ static inline void check_heap_object(const void *ptr, unsigned long n, return; } + if (is_vmalloc_addr(ptr)) { + struct vm_struct *area = find_vm_area(ptr); + unsigned long offset; + + if (!area) { + usercopy_abort("vmalloc", "no area", to_user, 0, n); + return; + } + + offset = ptr - area->addr; + if (offset + n > get_vm_area_size(area)) + usercopy_abort("vmalloc", NULL, to_user, offset, n); + return; + } + folio = virt_to_folio(ptr); if (folio_test_slab(folio)) { |