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
This commit is contained in:
Matthew Wilcox (Oracle) authored and Kees Cook committed 2022-04-13 12:15:51 -07:00
1 parent 4e140f59d2
commit 0aef499f31
1 file changed
+16
+16
View File
@@ -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)) {