summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Wilcox (Oracle) <willy@infradead.org>2022-01-10 23:15:28 +0000
committerKees Cook <keescook@chromium.org>2022-04-13 12:15:51 -0700
commit0aef499f3172a60222ae7460d61b364c134d6e1a (patch)
tree5e358ea58cd25805b0b588bdbe198fb9d28e6733
parent4e140f59d285c1ca1e5c81b4c13e27366865bd09 (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
-rw-r--r--mm/usercopy.c16
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)) {