Message ID | 20211216215351.3811471-3-willy@infradead.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Assorted improvements to usercopy | expand |
On Thu, 16 Dec 2021 at 21:55, Matthew Wilcox (Oracle) <willy@infradead.org> wrote: > > 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. ... > + offset = ptr - vm->addr; > + if (offset + n > vm->size) > + usercopy_abort("vmalloc", NULL, to_user, offset, n); > + return; > + } Instead of vm->size, call get_vm_area_size() so any guard page is trimmed from the length. Mark
diff --git a/mm/usercopy.c b/mm/usercopy.c index 8c039302465f..63476e1506e0 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> @@ -237,6 +238,21 @@ static inline void check_heap_object(const void *ptr, unsigned long n, return; } + if (is_vmalloc_addr(ptr)) { + struct vm_struct *vm = find_vm_area(ptr); + unsigned long offset; + + if (!vm) { + usercopy_abort("vmalloc", "no area", to_user, 0, n); + return; + } + + offset = ptr - vm->addr; + if (offset + n > vm->size) + usercopy_abort("vmalloc", NULL, to_user, offset, n); + return; + } + page = virt_to_head_page(ptr); if (PageSlab(page)) {