History

kasan: enable instrumentation of global variables

This feature let us to detect accesses out of bounds of global variables. This will work as for globals in kernel image, so for globals in modules. Currently this won't work for symbols in user-specified sections (e.g. __init, __read_mostly, ...) The idea of this is simple. Compiler increases each global variable by redzone size and add constructors invoking __asan_register_globals() function. Information about global variable (address, size, size with redzone ...) passed to __asan_register_globals() so we could poison variable's redzone. This patch also forces module_alloc() to return 8*PAGE_SIZE aligned address making shadow memory handling ( kasan_module_alloc()/kasan_module_free() ) more simple. Such alignment guarantees that each shadow page backing modules address space correspond to only one module_alloc() allocation.

Andrey Ryabinin committed 11 years ago

Commit bebf56a1 parent 630193912 files · +132 −4Browse files

Unified · Split

12 files
  1. Documentation/kasan.txt +1 −1
  2. arch/x86/kernel/module.c +11 −1
  3. arch/x86/mm/kasan_init_64.c +1 −1
  4. include/linux/compiler-gcc4.h +4 −0
  5. include/linux/compiler-gcc5.h +2 −0
  6. include/linux/kasan.h +10 −0
  7. kernel/module.c +2 −0
  8. lib/Kconfig.kasan +1 −0
  9. mm/kasan/kasan.c +52 −0
  10. mm/kasan/kasan.h +25 −0
  11. mm/kasan/report.c +22 −0
  12. scripts/Makefile.kasan +1 −1
Documentation/kasan.txt+1−1
@@ -9,7 +9,7 @@ a fast and comprehensive solution for finding use-after-free and out-of-bounds · 8 unmodified lines
99 bugs.
1010
1111 KASan uses compile-time instrumentation for checking every memory access,
12−therefore you will need a certain version of GCC >= 4.9.2
12+therefore you will need a certain version of GCC > 4.9.2
1313
1414 Currently KASan is supported only for x86_64 architecture and requires that the
1515 kernel be built with the SLUB allocator.
arch/x86/kernel/module.c+11−1
@@ -24,6 +24,7 @@ · 23 unmodified lines
2424 #include <linux/fs.h>
2525 #include <linux/string.h>
2626 #include <linux/kernel.h>
27+#include <linux/kasan.h>
2728 #include <linux/bug.h>
2829 #include <linux/mm.h>
2930 #include <linux/gfp.h>
@@ -83,13 +84,22 @@ static unsigned long int get_module_load_offset(void) · 53 unmodified lines
8384
8485 void *module_alloc(unsigned long size)
8586 {
87+ void *p;
88+
8689 if (PAGE_ALIGN(size) > MODULES_LEN)
8790 return NULL;
88− return __vmalloc_node_range(size, 1,
91+
92+ p = __vmalloc_node_range(size, MODULE_ALIGN,
8993 MODULES_VADDR + get_module_load_offset(),
9094 MODULES_END, GFP_KERNEL | __GFP_HIGHMEM,
9195 PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE,
9296 __builtin_return_address(0));
97+ if (p && (kasan_module_alloc(p, size) < 0)) {
98+ vfree(p);
99+ return NULL;
100+ }
101+
102+ return p;
93103 }
94104
95105 #ifdef CONFIG_X86_32
arch/x86/mm/kasan_init_64.c+1−1
@@ -196,7 +196,7 @@ void __init kasan_init(void) · 195 unmodified lines
196196 (unsigned long)kasan_mem_to_shadow(_end),
197197 NUMA_NO_NODE);
198198
199− populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_VADDR),
199+ populate_zero_shadow(kasan_mem_to_shadow((void *)MODULES_END),
200200 (void *)KASAN_SHADOW_END);
201201
202202 memset(kasan_zero_page, 0, PAGE_SIZE);
include/linux/compiler-gcc4.h+4−0
@@ -85,3 +85,7 @@ · 84 unmodified lines
8585 #define __HAVE_BUILTIN_BSWAP16__
8686 #endif
8787 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
88+
89+#if GCC_VERSION >= 40902
90+#define KASAN_ABI_VERSION 3
91+#endif
include/linux/compiler-gcc5.h+2−0
@@ -63,3 +63,5 @@ · 62 unmodified lines
6363 #define __HAVE_BUILTIN_BSWAP64__
6464 #define __HAVE_BUILTIN_BSWAP16__
6565 #endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
66+
67+#define KASAN_ABI_VERSION 4
include/linux/kasan.h+10−0
@@ -49,8 +49,15 @@ void kasan_krealloc(const void *object, size_t new_size); · 48 unmodified lines
4949 void kasan_slab_alloc(struct kmem_cache *s, void *object);
5050 void kasan_slab_free(struct kmem_cache *s, void *object);
5151
52+#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT)
53+
54+int kasan_module_alloc(void *addr, size_t size);
55+void kasan_module_free(void *addr);
56+
5257 #else /* CONFIG_KASAN */
5358
59+#define MODULE_ALIGN 1
60+
5461 static inline void kasan_unpoison_shadow(const void *address, size_t size) {}
5562
5663 static inline void kasan_enable_current(void) {}
@@ -74,6 +81,9 @@ static inline void kasan_krealloc(const void *object, size_t new_size) {} · 17 unmodified lines
7481 static inline void kasan_slab_alloc(struct kmem_cache *s, void *object) {}
7582 static inline void kasan_slab_free(struct kmem_cache *s, void *object) {}
7683
84+static inline int kasan_module_alloc(void *addr, size_t size) { return 0; }
85+static inline void kasan_module_free(void *addr) {}
86+
7787 #endif /* CONFIG_KASAN */
7888
7989 #endif /* LINUX_KASAN_H */
kernel/module.c+2−0
@@ -56,6 +56,7 @@ · 55 unmodified lines
5656 #include <linux/async.h>
5757 #include <linux/percpu.h>
5858 #include <linux/kmemleak.h>
59+#include <linux/kasan.h>
5960 #include <linux/jump_label.h>
6061 #include <linux/pfn.h>
6162 #include <linux/bsearch.h>
@@ -1813,6 +1814,7 @@ static void unset_module_init_ro_nx(struct module *mod) { } · 1751 unmodified lines
18131814 void __weak module_memfree(void *module_region)
18141815 {
18151816 vfree(module_region);
1817+ kasan_module_free(module_region);
18161818 }
18171819
18181820 void __weak module_arch_cleanup(struct module *mod)
lib/Kconfig.kasan+1−0
@@ -6,6 +6,7 @@ if HAVE_ARCH_KASAN · 5 unmodified lines
66 config KASAN
77 bool "KASan: runtime memory debugger"
88 depends on SLUB_DEBUG
9+ select CONSTRUCTORS
910 help
1011 Enables kernel address sanitizer - runtime memory debugger,
1112 designed to find out-of-bounds accesses and use-after-free bugs.
mm/kasan/kasan.c+52−0
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <linux/memblock.h>
2323 #include <linux/memory.h>
2424 #include <linux/mm.h>
25+#include <linux/module.h>
2526 #include <linux/printk.h>
2627 #include <linux/sched.h>
2728 #include <linux/slab.h>
@@ -395,6 +396,57 @@ void kasan_kfree_large(const void *ptr) · 367 unmodified lines
395396 KASAN_FREE_PAGE);
396397 }
397398
399+int kasan_module_alloc(void *addr, size_t size)
400+{
401+ void *ret;
402+ size_t shadow_size;
403+ unsigned long shadow_start;
404+
405+ shadow_start = (unsigned long)kasan_mem_to_shadow(addr);
406+ shadow_size = round_up(size >> KASAN_SHADOW_SCALE_SHIFT,
407+ PAGE_SIZE);
408+
409+ if (WARN_ON(!PAGE_ALIGNED(shadow_start)))
410+ return -EINVAL;
411+
412+ ret = __vmalloc_node_range(shadow_size, 1, shadow_start,
413+ shadow_start + shadow_size,
414+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
415+ PAGE_KERNEL, VM_NO_GUARD, NUMA_NO_NODE,
416+ __builtin_return_address(0));
417+ return ret ? 0 : -ENOMEM;
418+}
419+
420+void kasan_module_free(void *addr)
421+{
422+ vfree(kasan_mem_to_shadow(addr));
423+}
424+
425+static void register_global(struct kasan_global *global)
426+{
427+ size_t aligned_size = round_up(global->size, KASAN_SHADOW_SCALE_SIZE);
428+
429+ kasan_unpoison_shadow(global->beg, global->size);
430+
431+ kasan_poison_shadow(global->beg + aligned_size,
432+ global->size_with_redzone - aligned_size,
433+ KASAN_GLOBAL_REDZONE);
434+}
435+
436+void __asan_register_globals(struct kasan_global *globals, size_t size)
437+{
438+ int i;
439+
440+ for (i = 0; i < size; i++)
441+ register_global(&globals[i]);
442+}
443+EXPORT_SYMBOL(__asan_register_globals);
444+
445+void __asan_unregister_globals(struct kasan_global *globals, size_t size)
446+{
447+}
448+EXPORT_SYMBOL(__asan_unregister_globals);
449+
398450 #define DEFINE_ASAN_LOAD_STORE(size) \
399451 void __asan_load##size(unsigned long addr) \
400452 { \
mm/kasan/kasan.h+25−0
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #define KASAN_PAGE_REDZONE 0xFE /* redzone for kmalloc_large allocations */
1212 #define KASAN_KMALLOC_REDZONE 0xFC /* redzone inside slub object */
1313 #define KASAN_KMALLOC_FREE 0xFB /* object was freed (kmem_cache_free/kfree) */
14+#define KASAN_GLOBAL_REDZONE 0xFA /* redzone for global variable */
1415
1516 /*
1617 * Stack redzone shadow values
@@ -21,6 +22,10 @@ · 4 unmodified lines
2122 #define KASAN_STACK_RIGHT 0xF3
2223 #define KASAN_STACK_PARTIAL 0xF4
2324
25+/* Don't break randconfig/all*config builds */
26+#ifndef KASAN_ABI_VERSION
27+#define KASAN_ABI_VERSION 1
28+#endif
2429
2530 struct kasan_access_info {
2631 const void *access_addr;
@@ -30,6 +35,26 @@ struct kasan_access_info { · 3 unmodified lines
3035 unsigned long ip;
3136 };
3237
38+/* The layout of struct dictated by compiler */
39+struct kasan_source_location {
40+ const char *filename;
41+ int line_no;
42+ int column_no;
43+};
44+
45+/* The layout of struct dictated by compiler */
46+struct kasan_global {
47+ const void *beg; /* Address of the beginning of the global variable. */
48+ size_t size; /* Size of the global variable. */
49+ size_t size_with_redzone; /* Size of the variable + size of the red zone. 32 bytes aligned */
50+ const void *name;
51+ const void *module_name; /* Name of the module where the global variable is declared. */
52+ unsigned long has_dynamic_init; /* This needed for C++ */
53+#if KASAN_ABI_VERSION >= 4
54+ struct kasan_source_location *location;
55+#endif
56+};
57+
3358 void kasan_report_error(struct kasan_access_info *info);
3459 void kasan_report_user_access(struct kasan_access_info *info);
3560
mm/kasan/report.c+22−0
@@ -23,6 +23,8 @@ · 22 unmodified lines
2323 #include <linux/types.h>
2424 #include <linux/kasan.h>
2525
26+#include <asm/sections.h>
27+
2628 #include "kasan.h"
2729 #include "../slab.h"
2830
@@ -61,6 +63,7 @@ static void print_error_description(struct kasan_access_info *info) · 32 unmodified lines
6163 break;
6264 case KASAN_PAGE_REDZONE:
6365 case KASAN_KMALLOC_REDZONE:
66+ case KASAN_GLOBAL_REDZONE:
6467 case 0 ... KASAN_SHADOW_SCALE_SIZE - 1:
6568 bug_type = "out of bounds access";
6669 break;
@@ -80,6 +83,20 @@ static void print_error_description(struct kasan_access_info *info) · 13 unmodified lines
8083 info->access_size, current->comm, task_pid_nr(current));
8184 }
8285
86+static inline bool kernel_or_module_addr(const void *addr)
87+{
88+ return (addr >= (void *)_stext && addr < (void *)_end)
89+ || (addr >= (void *)MODULES_VADDR
90+ && addr < (void *)MODULES_END);
91+}
92+
93+static inline bool init_task_stack_addr(const void *addr)
94+{
95+ return addr >= (void *)&init_thread_union.stack &&
96+ (addr <= (void *)&init_thread_union.stack +
97+ sizeof(init_thread_union.stack));
98+}
99+
83100 static void print_address_description(struct kasan_access_info *info)
84101 {
85102 const void *addr = info->access_addr;
@@ -107,6 +124,11 @@ static void print_address_description(struct kasan_access_info *info) · 21 unmodified lines
107124 dump_page(page, "kasan: bad access detected");
108125 }
109126
127+ if (kernel_or_module_addr(addr)) {
128+ if (!init_task_stack_addr(addr))
129+ pr_err("Address belongs to variable %pS\n", addr);
130+ }
131+
110132 dump_stack();
111133 }
112134
scripts/Makefile.kasan+1−1
@@ -9,7 +9,7 @@ CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address · 8 unmodified lines
99
1010 CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \
1111 -fasan-shadow-offset=$(CONFIG_KASAN_SHADOW_OFFSET) \
12− --param asan-stack=1 \
12+ --param asan-stack=1 --param asan-globals=1 \
1313 --param asan-instrumentation-with-call-threshold=$(call_threshold))
1414
1515 ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t