Skip to content

Commit 2edb16e

Browse files
chleroympe
authored andcommitted
powerpc/32: Add KASAN support
This patch adds KASAN support for PPC32. The following patch will add an early activation of hash table for book3s. Until then, a warning will be raised if trying to use KASAN on an hash 6xx. To support KASAN, this patch initialises that MMU mapings for accessing to the KASAN shadow area defined in a previous patch. An early mapping is set as soon as the kernel code has been relocated at its definitive place. Then the definitive mapping is set once paging is initialised. For modules, the shadow area is allocated at module_alloc(). Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent f072015 commit 2edb16e

File tree

11 files changed

+188
-0
lines changed

11 files changed

+188
-0
lines changed

arch/powerpc/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ config PPC
173173
select GENERIC_TIME_VSYSCALL
174174
select HAVE_ARCH_AUDITSYSCALL
175175
select HAVE_ARCH_JUMP_LABEL
176+
select HAVE_ARCH_KASAN if PPC32
176177
select HAVE_ARCH_KGDB
177178
select HAVE_ARCH_MMAP_RND_BITS
178179
select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT

arch/powerpc/include/asm/kasan.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,14 @@
2727

2828
#define KASAN_SHADOW_SIZE (KASAN_SHADOW_END - KASAN_SHADOW_START)
2929

30+
#ifdef CONFIG_KASAN
31+
void kasan_early_init(void);
32+
void kasan_mmu_init(void);
33+
void kasan_init(void);
34+
#else
35+
static inline void kasan_init(void) { }
36+
static inline void kasan_mmu_init(void) { }
37+
#endif
38+
3039
#endif /* __ASSEMBLY */
3140
#endif

arch/powerpc/kernel/head_32.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,9 @@ start_here:
969969
* Do early platform-specific initialization,
970970
* and set up the MMU.
971971
*/
972+
#ifdef CONFIG_KASAN
973+
bl kasan_early_init
974+
#endif
972975
li r3,0
973976
mr r4,r31
974977
bl machine_init

arch/powerpc/kernel/head_40x.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,9 @@ start_here:
848848
/*
849849
* Decide what sort of machine this is and initialize the MMU.
850850
*/
851+
#ifdef CONFIG_KASAN
852+
bl kasan_early_init
853+
#endif
851854
li r3,0
852855
mr r4,r31
853856
bl machine_init

arch/powerpc/kernel/head_44x.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@ _ENTRY(_start);
203203
/*
204204
* Decide what sort of machine this is and initialize the MMU.
205205
*/
206+
#ifdef CONFIG_KASAN
207+
bl kasan_early_init
208+
#endif
206209
li r3,0
207210
mr r4,r31
208211
bl machine_init

arch/powerpc/kernel/head_8xx.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,9 @@ start_here:
853853
/*
854854
* Decide what sort of machine this is and initialize the MMU.
855855
*/
856+
#ifdef CONFIG_KASAN
857+
bl kasan_early_init
858+
#endif
856859
li r3,0
857860
mr r4,r31
858861
bl machine_init

arch/powerpc/kernel/head_fsl_booke.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ set_ivor:
268268
/*
269269
* Decide what sort of machine this is and initialize the MMU.
270270
*/
271+
#ifdef CONFIG_KASAN
272+
bl kasan_early_init
273+
#endif
271274
mr r3,r30
272275
mr r4,r31
273276
bl machine_init

arch/powerpc/kernel/setup-common.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
#include <asm/livepatch.h>
6868
#include <asm/mmu_context.h>
6969
#include <asm/cpu_has_feature.h>
70+
#include <asm/kasan.h>
7071

7172
#include "setup.h"
7273

@@ -871,6 +872,8 @@ static void smp_setup_pacas(void)
871872
*/
872873
void __init setup_arch(char **cmdline_p)
873874
{
875+
kasan_init();
876+
874877
*cmdline_p = boot_command_line;
875878

876879
/* Set a half-reasonable default so udelay does something sensible */

arch/powerpc/mm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,4 @@ obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
2626
obj-$(CONFIG_HIGHMEM) += highmem.o
2727
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
2828
obj-$(CONFIG_PPC_PTDUMP) += ptdump/
29+
obj-$(CONFIG_KASAN) += kasan/

arch/powerpc/mm/init_32.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include <asm/sections.h>
4747
#include <asm/hugetlb.h>
4848
#include <asm/kup.h>
49+
#include <asm/kasan.h>
4950

5051
#include <mm/mmu_decl.h>
5152

@@ -179,6 +180,8 @@ void __init MMU_init(void)
179180
btext_unmap();
180181
#endif
181182

183+
kasan_mmu_init();
184+
182185
setup_kup();
183186

184187
/* Shortly after that, the entire linear mapping will be available */

arch/powerpc/mm/kasan/kasan_init_32.c

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define DISABLE_BRANCH_PROFILING
4+
5+
#include <linux/kasan.h>
6+
#include <linux/printk.h>
7+
#include <linux/memblock.h>
8+
#include <linux/sched/task.h>
9+
#include <linux/vmalloc.h>
10+
#include <asm/pgalloc.h>
11+
#include <asm/code-patching.h>
12+
#include <mm/mmu_decl.h>
13+
14+
static void kasan_populate_pte(pte_t *ptep, pgprot_t prot)
15+
{
16+
unsigned long va = (unsigned long)kasan_early_shadow_page;
17+
phys_addr_t pa = __pa(kasan_early_shadow_page);
18+
int i;
19+
20+
for (i = 0; i < PTRS_PER_PTE; i++, ptep++)
21+
__set_pte_at(&init_mm, va, ptep, pfn_pte(PHYS_PFN(pa), prot), 0);
22+
}
23+
24+
static int kasan_init_shadow_page_tables(unsigned long k_start, unsigned long k_end)
25+
{
26+
pmd_t *pmd;
27+
unsigned long k_cur, k_next;
28+
29+
pmd = pmd_offset(pud_offset(pgd_offset_k(k_start), k_start), k_start);
30+
31+
for (k_cur = k_start; k_cur != k_end; k_cur = k_next, pmd++) {
32+
pte_t *new;
33+
34+
k_next = pgd_addr_end(k_cur, k_end);
35+
if ((void *)pmd_page_vaddr(*pmd) != kasan_early_shadow_pte)
36+
continue;
37+
38+
new = pte_alloc_one_kernel(&init_mm);
39+
40+
if (!new)
41+
return -ENOMEM;
42+
kasan_populate_pte(new, PAGE_KERNEL_RO);
43+
pmd_populate_kernel(&init_mm, pmd, new);
44+
}
45+
return 0;
46+
}
47+
48+
static void __ref *kasan_get_one_page(void)
49+
{
50+
if (slab_is_available())
51+
return (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
52+
53+
return memblock_alloc(PAGE_SIZE, PAGE_SIZE);
54+
}
55+
56+
static int __ref kasan_init_region(void *start, size_t size)
57+
{
58+
unsigned long k_start = (unsigned long)kasan_mem_to_shadow(start);
59+
unsigned long k_end = (unsigned long)kasan_mem_to_shadow(start + size);
60+
unsigned long k_cur;
61+
int ret;
62+
void *block = NULL;
63+
64+
ret = kasan_init_shadow_page_tables(k_start, k_end);
65+
if (ret)
66+
return ret;
67+
68+
if (!slab_is_available())
69+
block = memblock_alloc(k_end - k_start, PAGE_SIZE);
70+
71+
for (k_cur = k_start; k_cur < k_end; k_cur += PAGE_SIZE) {
72+
pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(k_cur), k_cur), k_cur);
73+
void *va = block ? block + k_cur - k_start : kasan_get_one_page();
74+
pte_t pte = pfn_pte(PHYS_PFN(__pa(va)), PAGE_KERNEL);
75+
76+
if (!va)
77+
return -ENOMEM;
78+
79+
__set_pte_at(&init_mm, k_cur, pte_offset_kernel(pmd, k_cur), pte, 0);
80+
}
81+
flush_tlb_kernel_range(k_start, k_end);
82+
return 0;
83+
}
84+
85+
static void __init kasan_remap_early_shadow_ro(void)
86+
{
87+
kasan_populate_pte(kasan_early_shadow_pte, PAGE_KERNEL_RO);
88+
89+
flush_tlb_kernel_range(KASAN_SHADOW_START, KASAN_SHADOW_END);
90+
}
91+
92+
void __init kasan_mmu_init(void)
93+
{
94+
int ret;
95+
struct memblock_region *reg;
96+
97+
for_each_memblock(memory, reg) {
98+
phys_addr_t base = reg->base;
99+
phys_addr_t top = min(base + reg->size, total_lowmem);
100+
101+
if (base >= top)
102+
continue;
103+
104+
ret = kasan_init_region(__va(base), top - base);
105+
if (ret)
106+
panic("kasan: kasan_init_region() failed");
107+
}
108+
}
109+
110+
void __init kasan_init(void)
111+
{
112+
kasan_remap_early_shadow_ro();
113+
114+
clear_page(kasan_early_shadow_page);
115+
116+
/* At this point kasan is fully initialized. Enable error messages */
117+
init_task.kasan_depth = 0;
118+
pr_info("KASAN init done\n");
119+
}
120+
121+
#ifdef CONFIG_MODULES
122+
void *module_alloc(unsigned long size)
123+
{
124+
void *base = vmalloc_exec(size);
125+
126+
if (!base)
127+
return NULL;
128+
129+
if (!kasan_init_region(base, size))
130+
return base;
131+
132+
vfree(base);
133+
134+
return NULL;
135+
}
136+
#endif
137+
138+
void __init kasan_early_init(void)
139+
{
140+
unsigned long addr = KASAN_SHADOW_START;
141+
unsigned long end = KASAN_SHADOW_END;
142+
unsigned long next;
143+
pmd_t *pmd = pmd_offset(pud_offset(pgd_offset_k(addr), addr), addr);
144+
145+
BUILD_BUG_ON(KASAN_SHADOW_START & ~PGDIR_MASK);
146+
147+
kasan_populate_pte(kasan_early_shadow_pte, PAGE_KERNEL);
148+
149+
do {
150+
next = pgd_addr_end(addr, end);
151+
pmd_populate_kernel(&init_mm, pmd, kasan_early_shadow_pte);
152+
} while (pmd++, addr = next, addr != end);
153+
154+
if (early_mmu_has_feature(MMU_FTR_HPTE_TABLE))
155+
WARN(true, "KASAN not supported on hash 6xx");
156+
}

0 commit comments

Comments
 (0)