diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2017-12-03 16:28:52 -0500 |
---|---|---|
committer | Max Filippov <jcmvbkbc@gmail.com> | 2017-12-17 01:37:12 -0500 |
commit | c633544a6154146a210cf158157a1ae7c55473b6 (patch) | |
tree | d670a9984373622d991c382126f341b6f32154cd /arch/xtensa/mm | |
parent | 1af1e8a39dc0fab5e50f10462c636da8c1e0cfbb (diff) |
xtensa: add support for KASAN
Cover kernel addresses above 0x90000000 by the shadow map. Enable
HAVE_ARCH_KASAN when MMU is enabled. Provide kasan_early_init that fills
shadow map with writable copies of kasan_zero_page. Call
kasan_early_init right after mmu initialization in the setup_arch.
Provide kasan_init that allocates proper shadow map pages from the
memblock and puts these pages into the shadow map for addresses from
VMALLOC area to the end of KSEG. Call kasan_init right after memblock
initialization. Don't use KASAN for the boot code, MMU and KASAN
initialization and page fault handler. Make kernel stack size 4 times
larger when KASAN is enabled to avoid stack overflows.
GCC 7.3, 8 or newer is required to build the xtensa kernel with KASAN.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Diffstat (limited to 'arch/xtensa/mm')
-rw-r--r-- | arch/xtensa/mm/Makefile | 5 | ||||
-rw-r--r-- | arch/xtensa/mm/init.c | 7 | ||||
-rw-r--r-- | arch/xtensa/mm/kasan_init.c | 95 |
3 files changed, 107 insertions, 0 deletions
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile index 0b3d296a016a..734888a00dc8 100644 --- a/arch/xtensa/mm/Makefile +++ b/arch/xtensa/mm/Makefile | |||
@@ -5,3 +5,8 @@ | |||
5 | obj-y := init.o misc.o | 5 | obj-y := init.o misc.o |
6 | obj-$(CONFIG_MMU) += cache.o fault.o ioremap.o mmu.o tlb.o | 6 | obj-$(CONFIG_MMU) += cache.o fault.o ioremap.o mmu.o tlb.o |
7 | obj-$(CONFIG_HIGHMEM) += highmem.o | 7 | obj-$(CONFIG_HIGHMEM) += highmem.o |
8 | obj-$(CONFIG_KASAN) += kasan_init.o | ||
9 | |||
10 | KASAN_SANITIZE_fault.o := n | ||
11 | KASAN_SANITIZE_kasan_init.o := n | ||
12 | KASAN_SANITIZE_mmu.o := n | ||
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 6fc1cb093fb3..0d980f05da82 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c | |||
@@ -100,6 +100,9 @@ void __init mem_init(void) | |||
100 | 100 | ||
101 | mem_init_print_info(NULL); | 101 | mem_init_print_info(NULL); |
102 | pr_info("virtual kernel memory layout:\n" | 102 | pr_info("virtual kernel memory layout:\n" |
103 | #ifdef CONFIG_KASAN | ||
104 | " kasan : 0x%08lx - 0x%08lx (%5lu MB)\n" | ||
105 | #endif | ||
103 | #ifdef CONFIG_MMU | 106 | #ifdef CONFIG_MMU |
104 | " vmalloc : 0x%08lx - 0x%08lx (%5lu MB)\n" | 107 | " vmalloc : 0x%08lx - 0x%08lx (%5lu MB)\n" |
105 | #endif | 108 | #endif |
@@ -108,6 +111,10 @@ void __init mem_init(void) | |||
108 | " fixmap : 0x%08lx - 0x%08lx (%5lu kB)\n" | 111 | " fixmap : 0x%08lx - 0x%08lx (%5lu kB)\n" |
109 | #endif | 112 | #endif |
110 | " lowmem : 0x%08lx - 0x%08lx (%5lu MB)\n", | 113 | " lowmem : 0x%08lx - 0x%08lx (%5lu MB)\n", |
114 | #ifdef CONFIG_KASAN | ||
115 | KASAN_SHADOW_START, KASAN_SHADOW_START + KASAN_SHADOW_SIZE, | ||
116 | KASAN_SHADOW_SIZE >> 20, | ||
117 | #endif | ||
111 | #ifdef CONFIG_MMU | 118 | #ifdef CONFIG_MMU |
112 | VMALLOC_START, VMALLOC_END, | 119 | VMALLOC_START, VMALLOC_END, |
113 | (VMALLOC_END - VMALLOC_START) >> 20, | 120 | (VMALLOC_END - VMALLOC_START) >> 20, |
diff --git a/arch/xtensa/mm/kasan_init.c b/arch/xtensa/mm/kasan_init.c new file mode 100644 index 000000000000..6b532b6bd785 --- /dev/null +++ b/arch/xtensa/mm/kasan_init.c | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * Xtensa KASAN shadow map initialization | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 2017 Cadence Design Systems Inc. | ||
9 | */ | ||
10 | |||
11 | #include <linux/bootmem.h> | ||
12 | #include <linux/init_task.h> | ||
13 | #include <linux/kasan.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/memblock.h> | ||
16 | #include <asm/initialize_mmu.h> | ||
17 | #include <asm/tlbflush.h> | ||
18 | #include <asm/traps.h> | ||
19 | |||
20 | void __init kasan_early_init(void) | ||
21 | { | ||
22 | unsigned long vaddr = KASAN_SHADOW_START; | ||
23 | pgd_t *pgd = pgd_offset_k(vaddr); | ||
24 | pmd_t *pmd = pmd_offset(pgd, vaddr); | ||
25 | int i; | ||
26 | |||
27 | for (i = 0; i < PTRS_PER_PTE; ++i) | ||
28 | set_pte(kasan_zero_pte + i, | ||
29 | mk_pte(virt_to_page(kasan_zero_page), PAGE_KERNEL)); | ||
30 | |||
31 | for (vaddr = 0; vaddr < KASAN_SHADOW_SIZE; vaddr += PMD_SIZE, ++pmd) { | ||
32 | BUG_ON(!pmd_none(*pmd)); | ||
33 | set_pmd(pmd, __pmd((unsigned long)kasan_zero_pte)); | ||
34 | } | ||
35 | early_trap_init(); | ||
36 | } | ||
37 | |||
38 | static void __init populate(void *start, void *end) | ||
39 | { | ||
40 | unsigned long n_pages = (end - start) / PAGE_SIZE; | ||
41 | unsigned long n_pmds = n_pages / PTRS_PER_PTE; | ||
42 | unsigned long i, j; | ||
43 | unsigned long vaddr = (unsigned long)start; | ||
44 | pgd_t *pgd = pgd_offset_k(vaddr); | ||
45 | pmd_t *pmd = pmd_offset(pgd, vaddr); | ||
46 | pte_t *pte = memblock_virt_alloc(n_pages * sizeof(pte_t), PAGE_SIZE); | ||
47 | |||
48 | pr_debug("%s: %p - %p\n", __func__, start, end); | ||
49 | |||
50 | for (i = j = 0; i < n_pmds; ++i) { | ||
51 | int k; | ||
52 | |||
53 | for (k = 0; k < PTRS_PER_PTE; ++k, ++j) { | ||
54 | phys_addr_t phys = | ||
55 | memblock_alloc_base(PAGE_SIZE, PAGE_SIZE, | ||
56 | MEMBLOCK_ALLOC_ANYWHERE); | ||
57 | |||
58 | set_pte(pte + j, pfn_pte(PHYS_PFN(phys), PAGE_KERNEL)); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | for (i = 0; i < n_pmds ; ++i, pte += PTRS_PER_PTE) | ||
63 | set_pmd(pmd + i, __pmd((unsigned long)pte)); | ||
64 | |||
65 | local_flush_tlb_all(); | ||
66 | memset(start, 0, end - start); | ||
67 | } | ||
68 | |||
69 | void __init kasan_init(void) | ||
70 | { | ||
71 | int i; | ||
72 | |||
73 | BUILD_BUG_ON(KASAN_SHADOW_OFFSET != KASAN_SHADOW_START - | ||
74 | (KASAN_START_VADDR >> KASAN_SHADOW_SCALE_SHIFT)); | ||
75 | BUILD_BUG_ON(VMALLOC_START < KASAN_START_VADDR); | ||
76 | |||
77 | /* | ||
78 | * Replace shadow map pages that cover addresses from VMALLOC area | ||
79 | * start to the end of KSEG with clean writable pages. | ||
80 | */ | ||
81 | populate(kasan_mem_to_shadow((void *)VMALLOC_START), | ||
82 | kasan_mem_to_shadow((void *)XCHAL_KSEG_BYPASS_VADDR)); | ||
83 | |||
84 | /* Write protect kasan_zero_page and zero-initialize it again. */ | ||
85 | for (i = 0; i < PTRS_PER_PTE; ++i) | ||
86 | set_pte(kasan_zero_pte + i, | ||
87 | mk_pte(virt_to_page(kasan_zero_page), PAGE_KERNEL_RO)); | ||
88 | |||
89 | local_flush_tlb_all(); | ||
90 | memset(kasan_zero_page, 0, PAGE_SIZE); | ||
91 | |||
92 | /* At this point kasan is fully initialized. Enable error messages. */ | ||
93 | current->kasan_depth = 0; | ||
94 | pr_info("KernelAddressSanitizer initialized\n"); | ||
95 | } | ||