Commit 0aef499f authored by Matthew Wilcox (Oracle)'s avatar Matthew Wilcox (Oracle) Committed by Kees Cook

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: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20220110231530.665970-3-willy@infradead.org
parent 4e140f59
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/sched/task.h> #include <linux/sched/task.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <linux/thread_info.h> #include <linux/thread_info.h>
#include <linux/vmalloc.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/jump_label.h> #include <linux/jump_label.h>
#include <asm/sections.h> #include <asm/sections.h>
...@@ -238,6 +239,21 @@ static inline void check_heap_object(const void *ptr, unsigned long n, ...@@ -238,6 +239,21 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
return; 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); folio = virt_to_folio(ptr);
if (folio_test_slab(folio)) { if (folio_test_slab(folio)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment