1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
239d114ddSAndrey Ryabinin /*
339d114ddSAndrey Ryabinin * This file contains kasan initialization code for ARM64.
439d114ddSAndrey Ryabinin *
539d114ddSAndrey Ryabinin * Copyright (c) 2015 Samsung Electronics Co., Ltd.
639d114ddSAndrey Ryabinin * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com>
739d114ddSAndrey Ryabinin */
839d114ddSAndrey Ryabinin
939d114ddSAndrey Ryabinin #define pr_fmt(fmt) "kasan: " fmt
1039d114ddSAndrey Ryabinin #include <linux/kasan.h>
1139d114ddSAndrey Ryabinin #include <linux/kernel.h>
129164bb4aSIngo Molnar #include <linux/sched/task.h>
1339d114ddSAndrey Ryabinin #include <linux/memblock.h>
1439d114ddSAndrey Ryabinin #include <linux/start_kernel.h>
152077be67SLaura Abbott #include <linux/mm.h>
1639d114ddSAndrey Ryabinin
17c1a88e91SMark Rutland #include <asm/mmu_context.h>
18f9040773SArd Biesheuvel #include <asm/kernel-pgtable.h>
1939d114ddSAndrey Ryabinin #include <asm/page.h>
2039d114ddSAndrey Ryabinin #include <asm/pgalloc.h>
21f9040773SArd Biesheuvel #include <asm/sections.h>
2239d114ddSAndrey Ryabinin #include <asm/tlbflush.h>
2339d114ddSAndrey Ryabinin
24afe6ef80SAndrey Konovalov #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
25afe6ef80SAndrey Konovalov
2639d114ddSAndrey Ryabinin static pgd_t tmp_pg_dir[PTRS_PER_PGD] __initdata __aligned(PGD_SIZE);
2739d114ddSAndrey Ryabinin
282077be67SLaura Abbott /*
292077be67SLaura Abbott * The p*d_populate functions call virt_to_phys implicitly so they can't be used
302077be67SLaura Abbott * directly on kernel symbols (bm_p*d). All the early functions are called too
312077be67SLaura Abbott * early to use lm_alias so __p*d_populate functions must be used to populate
322077be67SLaura Abbott * with the physical address from __pa_symbol.
332077be67SLaura Abbott */
342077be67SLaura Abbott
kasan_alloc_zeroed_page(int node)35e17d8025SWill Deacon static phys_addr_t __init kasan_alloc_zeroed_page(int node)
3639d114ddSAndrey Ryabinin {
37eb31d559SMike Rapoport void *p = memblock_alloc_try_nid(PAGE_SIZE, PAGE_SIZE,
38e17d8025SWill Deacon __pa(MAX_DMA_ADDRESS),
39c6975d7cSQian Cai MEMBLOCK_ALLOC_NOLEAKTRACE, node);
408a7f97b9SMike Rapoport if (!p)
418a7f97b9SMike Rapoport panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%llx\n",
428a7f97b9SMike Rapoport __func__, PAGE_SIZE, PAGE_SIZE, node,
438a7f97b9SMike Rapoport __pa(MAX_DMA_ADDRESS));
448a7f97b9SMike Rapoport
45e17d8025SWill Deacon return __pa(p);
46e17d8025SWill Deacon }
47e17d8025SWill Deacon
kasan_alloc_raw_page(int node)48080eb83fSAndrey Konovalov static phys_addr_t __init kasan_alloc_raw_page(int node)
49080eb83fSAndrey Konovalov {
50080eb83fSAndrey Konovalov void *p = memblock_alloc_try_nid_raw(PAGE_SIZE, PAGE_SIZE,
51080eb83fSAndrey Konovalov __pa(MAX_DMA_ADDRESS),
52c6975d7cSQian Cai MEMBLOCK_ALLOC_NOLEAKTRACE,
53c6975d7cSQian Cai node);
548a7f97b9SMike Rapoport if (!p)
558a7f97b9SMike Rapoport panic("%s: Failed to allocate %lu bytes align=0x%lx nid=%d from=%llx\n",
568a7f97b9SMike Rapoport __func__, PAGE_SIZE, PAGE_SIZE, node,
578a7f97b9SMike Rapoport __pa(MAX_DMA_ADDRESS));
588a7f97b9SMike Rapoport
59080eb83fSAndrey Konovalov return __pa(p);
60080eb83fSAndrey Konovalov }
61080eb83fSAndrey Konovalov
kasan_pte_offset(pmd_t * pmdp,unsigned long addr,int node,bool early)6220a004e7SWill Deacon static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,
63e17d8025SWill Deacon bool early)
64e17d8025SWill Deacon {
6520a004e7SWill Deacon if (pmd_none(READ_ONCE(*pmdp))) {
669577dd74SAndrey Konovalov phys_addr_t pte_phys = early ?
679577dd74SAndrey Konovalov __pa_symbol(kasan_early_shadow_pte)
68e17d8025SWill Deacon : kasan_alloc_zeroed_page(node);
6920a004e7SWill Deacon __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE);
70e17d8025SWill Deacon }
71e17d8025SWill Deacon
7220a004e7SWill Deacon return early ? pte_offset_kimg(pmdp, addr)
7320a004e7SWill Deacon : pte_offset_kernel(pmdp, addr);
74e17d8025SWill Deacon }
75e17d8025SWill Deacon
kasan_pmd_offset(pud_t * pudp,unsigned long addr,int node,bool early)7620a004e7SWill Deacon static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,
77e17d8025SWill Deacon bool early)
78e17d8025SWill Deacon {
7920a004e7SWill Deacon if (pud_none(READ_ONCE(*pudp))) {
809577dd74SAndrey Konovalov phys_addr_t pmd_phys = early ?
819577dd74SAndrey Konovalov __pa_symbol(kasan_early_shadow_pmd)
82e17d8025SWill Deacon : kasan_alloc_zeroed_page(node);
83c1fd78a7SArd Biesheuvel __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE);
84e17d8025SWill Deacon }
85e17d8025SWill Deacon
8620a004e7SWill Deacon return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr);
87e17d8025SWill Deacon }
88e17d8025SWill Deacon
kasan_pud_offset(p4d_t * p4dp,unsigned long addr,int node,bool early)89e9f63768SMike Rapoport static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node,
90e17d8025SWill Deacon bool early)
91e17d8025SWill Deacon {
92e9f63768SMike Rapoport if (p4d_none(READ_ONCE(*p4dp))) {
939577dd74SAndrey Konovalov phys_addr_t pud_phys = early ?
949577dd74SAndrey Konovalov __pa_symbol(kasan_early_shadow_pud)
95e17d8025SWill Deacon : kasan_alloc_zeroed_page(node);
96c1fd78a7SArd Biesheuvel __p4d_populate(p4dp, pud_phys, P4D_TYPE_TABLE);
97e17d8025SWill Deacon }
98e17d8025SWill Deacon
99e9f63768SMike Rapoport return early ? pud_offset_kimg(p4dp, addr) : pud_offset(p4dp, addr);
100e17d8025SWill Deacon }
101e17d8025SWill Deacon
kasan_pte_populate(pmd_t * pmdp,unsigned long addr,unsigned long end,int node,bool early)10220a004e7SWill Deacon static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
103e17d8025SWill Deacon unsigned long end, int node, bool early)
104e17d8025SWill Deacon {
10539d114ddSAndrey Ryabinin unsigned long next;
10620a004e7SWill Deacon pte_t *ptep = kasan_pte_offset(pmdp, addr, node, early);
10739d114ddSAndrey Ryabinin
10839d114ddSAndrey Ryabinin do {
1099577dd74SAndrey Konovalov phys_addr_t page_phys = early ?
1109577dd74SAndrey Konovalov __pa_symbol(kasan_early_shadow_page)
111080eb83fSAndrey Konovalov : kasan_alloc_raw_page(node);
112080eb83fSAndrey Konovalov if (!early)
113080eb83fSAndrey Konovalov memset(__va(page_phys), KASAN_SHADOW_INIT, PAGE_SIZE);
11439d114ddSAndrey Ryabinin next = addr + PAGE_SIZE;
11520a004e7SWill Deacon set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL));
11620a004e7SWill Deacon } while (ptep++, addr = next, addr != end && pte_none(READ_ONCE(*ptep)));
11739d114ddSAndrey Ryabinin }
11839d114ddSAndrey Ryabinin
kasan_pmd_populate(pud_t * pudp,unsigned long addr,unsigned long end,int node,bool early)11920a004e7SWill Deacon static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
120e17d8025SWill Deacon unsigned long end, int node, bool early)
12139d114ddSAndrey Ryabinin {
12239d114ddSAndrey Ryabinin unsigned long next;
12320a004e7SWill Deacon pmd_t *pmdp = kasan_pmd_offset(pudp, addr, node, early);
12439d114ddSAndrey Ryabinin
12539d114ddSAndrey Ryabinin do {
12639d114ddSAndrey Ryabinin next = pmd_addr_end(addr, end);
12720a004e7SWill Deacon kasan_pte_populate(pmdp, addr, next, node, early);
12820a004e7SWill Deacon } while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp)));
12939d114ddSAndrey Ryabinin }
13039d114ddSAndrey Ryabinin
kasan_pud_populate(p4d_t * p4dp,unsigned long addr,unsigned long end,int node,bool early)131e9f63768SMike Rapoport static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
132e17d8025SWill Deacon unsigned long end, int node, bool early)
13339d114ddSAndrey Ryabinin {
13439d114ddSAndrey Ryabinin unsigned long next;
135e9f63768SMike Rapoport pud_t *pudp = kasan_pud_offset(p4dp, addr, node, early);
13639d114ddSAndrey Ryabinin
13739d114ddSAndrey Ryabinin do {
13839d114ddSAndrey Ryabinin next = pud_addr_end(addr, end);
13920a004e7SWill Deacon kasan_pmd_populate(pudp, addr, next, node, early);
14020a004e7SWill Deacon } while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp)));
14139d114ddSAndrey Ryabinin }
14239d114ddSAndrey Ryabinin
kasan_p4d_populate(pgd_t * pgdp,unsigned long addr,unsigned long end,int node,bool early)143e9f63768SMike Rapoport static void __init kasan_p4d_populate(pgd_t *pgdp, unsigned long addr,
144e9f63768SMike Rapoport unsigned long end, int node, bool early)
145e9f63768SMike Rapoport {
146e9f63768SMike Rapoport unsigned long next;
147e9f63768SMike Rapoport p4d_t *p4dp = p4d_offset(pgdp, addr);
148e9f63768SMike Rapoport
149e9f63768SMike Rapoport do {
150e9f63768SMike Rapoport next = p4d_addr_end(addr, end);
151e9f63768SMike Rapoport kasan_pud_populate(p4dp, addr, next, node, early);
152e9f63768SMike Rapoport } while (p4dp++, addr = next, addr != end);
153e9f63768SMike Rapoport }
154e9f63768SMike Rapoport
kasan_pgd_populate(unsigned long addr,unsigned long end,int node,bool early)155e17d8025SWill Deacon static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
156e17d8025SWill Deacon int node, bool early)
15739d114ddSAndrey Ryabinin {
15839d114ddSAndrey Ryabinin unsigned long next;
15920a004e7SWill Deacon pgd_t *pgdp;
16039d114ddSAndrey Ryabinin
16120a004e7SWill Deacon pgdp = pgd_offset_k(addr);
16239d114ddSAndrey Ryabinin do {
16339d114ddSAndrey Ryabinin next = pgd_addr_end(addr, end);
164e9f63768SMike Rapoport kasan_p4d_populate(pgdp, addr, next, node, early);
16520a004e7SWill Deacon } while (pgdp++, addr = next, addr != end);
16639d114ddSAndrey Ryabinin }
16739d114ddSAndrey Ryabinin
168e17d8025SWill Deacon /* The early shadow maps everything to a single page of zeroes */
kasan_early_init(void)16983040123SWill Deacon asmlinkage void __init kasan_early_init(void)
17039d114ddSAndrey Ryabinin {
171917538e2SAndrey Konovalov BUILD_BUG_ON(KASAN_SHADOW_OFFSET !=
172917538e2SAndrey Konovalov KASAN_SHADOW_END - (1UL << (64 - KASAN_SHADOW_SCALE_SHIFT)));
17390ec95cdSSteve Capper BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS), PGDIR_SIZE));
17490ec95cdSSteve Capper BUILD_BUG_ON(!IS_ALIGNED(_KASAN_SHADOW_START(VA_BITS_MIN), PGDIR_SIZE));
17539d114ddSAndrey Ryabinin BUILD_BUG_ON(!IS_ALIGNED(KASAN_SHADOW_END, PGDIR_SIZE));
176e17d8025SWill Deacon kasan_pgd_populate(KASAN_SHADOW_START, KASAN_SHADOW_END, NUMA_NO_NODE,
177e17d8025SWill Deacon true);
178e17d8025SWill Deacon }
179e17d8025SWill Deacon
180e17d8025SWill Deacon /* Set up full kasan mappings, ensuring that the mapped pages are zeroed */
kasan_map_populate(unsigned long start,unsigned long end,int node)181e17d8025SWill Deacon static void __init kasan_map_populate(unsigned long start, unsigned long end,
182e17d8025SWill Deacon int node)
183e17d8025SWill Deacon {
184e17d8025SWill Deacon kasan_pgd_populate(start & PAGE_MASK, PAGE_ALIGN(end), node, false);
18539d114ddSAndrey Ryabinin }
18639d114ddSAndrey Ryabinin
187068a17a5SMark Rutland /*
188068a17a5SMark Rutland * Copy the current shadow region into a new pgdir.
189068a17a5SMark Rutland */
kasan_copy_shadow(pgd_t * pgdir)190068a17a5SMark Rutland void __init kasan_copy_shadow(pgd_t *pgdir)
191068a17a5SMark Rutland {
19220a004e7SWill Deacon pgd_t *pgdp, *pgdp_new, *pgdp_end;
193068a17a5SMark Rutland
19420a004e7SWill Deacon pgdp = pgd_offset_k(KASAN_SHADOW_START);
19520a004e7SWill Deacon pgdp_end = pgd_offset_k(KASAN_SHADOW_END);
196974b9b2cSMike Rapoport pgdp_new = pgd_offset_pgd(pgdir, KASAN_SHADOW_START);
197068a17a5SMark Rutland do {
19820a004e7SWill Deacon set_pgd(pgdp_new, READ_ONCE(*pgdp));
19920a004e7SWill Deacon } while (pgdp++, pgdp_new++, pgdp != pgdp_end);
200068a17a5SMark Rutland }
201068a17a5SMark Rutland
clear_pgds(unsigned long start,unsigned long end)20239d114ddSAndrey Ryabinin static void __init clear_pgds(unsigned long start,
20339d114ddSAndrey Ryabinin unsigned long end)
20439d114ddSAndrey Ryabinin {
20539d114ddSAndrey Ryabinin /*
20639d114ddSAndrey Ryabinin * Remove references to kasan page tables from
20739d114ddSAndrey Ryabinin * swapper_pg_dir. pgd_clear() can't be used
20839d114ddSAndrey Ryabinin * here because it's nop on 2,3-level pagetable setups
20939d114ddSAndrey Ryabinin */
21039d114ddSAndrey Ryabinin for (; start < end; start += PGDIR_SIZE)
21139d114ddSAndrey Ryabinin set_pgd(pgd_offset_k(start), __pgd(0));
21239d114ddSAndrey Ryabinin }
21339d114ddSAndrey Ryabinin
kasan_init_shadow(void)214afe6ef80SAndrey Konovalov static void __init kasan_init_shadow(void)
21539d114ddSAndrey Ryabinin {
216f9040773SArd Biesheuvel u64 kimg_shadow_start, kimg_shadow_end;
217*55123affSMark Rutland u64 mod_shadow_start;
2189a0732efSLecopzer Chen u64 vmalloc_shadow_end;
219b10d6bcaSMike Rapoport phys_addr_t pa_start, pa_end;
220b10d6bcaSMike Rapoport u64 i;
22139d114ddSAndrey Ryabinin
2227d7b88ffSLecopzer Chen kimg_shadow_start = (u64)kasan_mem_to_shadow(KERNEL_START) & PAGE_MASK;
2237d7b88ffSLecopzer Chen kimg_shadow_end = PAGE_ALIGN((u64)kasan_mem_to_shadow(KERNEL_END));
224f9040773SArd Biesheuvel
225f80fb3a3SArd Biesheuvel mod_shadow_start = (u64)kasan_mem_to_shadow((void *)MODULES_VADDR);
226f80fb3a3SArd Biesheuvel
2279a0732efSLecopzer Chen vmalloc_shadow_end = (u64)kasan_mem_to_shadow((void *)VMALLOC_END);
2289a0732efSLecopzer Chen
22939d114ddSAndrey Ryabinin /*
23039d114ddSAndrey Ryabinin * We are going to perform proper setup of shadow memory.
2310293c8baSKyrylo Tkachov * At first we should unmap early shadow (clear_pgds() call below).
23239d114ddSAndrey Ryabinin * However, instrumented code couldn't execute without shadow memory.
23339d114ddSAndrey Ryabinin * tmp_pg_dir used to keep early shadow mapped until full shadow
23439d114ddSAndrey Ryabinin * setup will be finished.
23539d114ddSAndrey Ryabinin */
23639d114ddSAndrey Ryabinin memcpy(tmp_pg_dir, swapper_pg_dir, sizeof(tmp_pg_dir));
237c1a88e91SMark Rutland dsb(ishst);
2381682c45bSArd Biesheuvel cpu_replace_ttbr1(lm_alias(tmp_pg_dir), idmap_pg_dir);
23939d114ddSAndrey Ryabinin
24039d114ddSAndrey Ryabinin clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
24139d114ddSAndrey Ryabinin
242e17d8025SWill Deacon kasan_map_populate(kimg_shadow_start, kimg_shadow_end,
2437d7b88ffSLecopzer Chen early_pfn_to_nid(virt_to_pfn(lm_alias(KERNEL_START))));
244f9040773SArd Biesheuvel
24577ad4ce6SMark Rutland kasan_populate_early_shadow(kasan_mem_to_shadow((void *)PAGE_END),
246f80fb3a3SArd Biesheuvel (void *)mod_shadow_start);
2479a0732efSLecopzer Chen
2489a0732efSLecopzer Chen BUILD_BUG_ON(VMALLOC_START != MODULES_END);
2499a0732efSLecopzer Chen kasan_populate_early_shadow((void *)vmalloc_shadow_end,
2509a0732efSLecopzer Chen (void *)KASAN_SHADOW_END);
251f80fb3a3SArd Biesheuvel
252b10d6bcaSMike Rapoport for_each_mem_range(i, &pa_start, &pa_end) {
253b10d6bcaSMike Rapoport void *start = (void *)__phys_to_virt(pa_start);
254b10d6bcaSMike Rapoport void *end = (void *)__phys_to_virt(pa_end);
25539d114ddSAndrey Ryabinin
25639d114ddSAndrey Ryabinin if (start >= end)
25739d114ddSAndrey Ryabinin break;
25839d114ddSAndrey Ryabinin
259e17d8025SWill Deacon kasan_map_populate((unsigned long)kasan_mem_to_shadow(start),
2603f9ec80fSAndrey Ryabinin (unsigned long)kasan_mem_to_shadow(end),
261800cb2e5SMark Rutland early_pfn_to_nid(virt_to_pfn(start)));
26239d114ddSAndrey Ryabinin }
26339d114ddSAndrey Ryabinin
2647b1af979SArd Biesheuvel /*
2659577dd74SAndrey Konovalov * KAsan may reuse the contents of kasan_early_shadow_pte directly,
2669577dd74SAndrey Konovalov * so we should make sure that it maps the zero page read-only.
2677b1af979SArd Biesheuvel */
2687b1af979SArd Biesheuvel for (i = 0; i < PTRS_PER_PTE; i++)
2699577dd74SAndrey Konovalov set_pte(&kasan_early_shadow_pte[i],
2709577dd74SAndrey Konovalov pfn_pte(sym_to_pfn(kasan_early_shadow_page),
2719577dd74SAndrey Konovalov PAGE_KERNEL_RO));
2727b1af979SArd Biesheuvel
273080eb83fSAndrey Konovalov memset(kasan_early_shadow_page, KASAN_SHADOW_INIT, PAGE_SIZE);
2741682c45bSArd Biesheuvel cpu_replace_ttbr1(lm_alias(swapper_pg_dir), idmap_pg_dir);
275afe6ef80SAndrey Konovalov }
276afe6ef80SAndrey Konovalov
kasan_init_depth(void)277d73b4936SAndrey Konovalov static void __init kasan_init_depth(void)
278d73b4936SAndrey Konovalov {
279d73b4936SAndrey Konovalov init_task.kasan_depth = 0;
280d73b4936SAndrey Konovalov }
281d73b4936SAndrey Konovalov
2823252b1d8SKefeng Wang #ifdef CONFIG_KASAN_VMALLOC
kasan_populate_early_vm_area_shadow(void * start,unsigned long size)2833252b1d8SKefeng Wang void __init kasan_populate_early_vm_area_shadow(void *start, unsigned long size)
2843252b1d8SKefeng Wang {
2853252b1d8SKefeng Wang unsigned long shadow_start, shadow_end;
2863252b1d8SKefeng Wang
2873252b1d8SKefeng Wang if (!is_vmalloc_or_module_addr(start))
2883252b1d8SKefeng Wang return;
2893252b1d8SKefeng Wang
2903252b1d8SKefeng Wang shadow_start = (unsigned long)kasan_mem_to_shadow(start);
2913252b1d8SKefeng Wang shadow_start = ALIGN_DOWN(shadow_start, PAGE_SIZE);
2923252b1d8SKefeng Wang shadow_end = (unsigned long)kasan_mem_to_shadow(start + size);
2933252b1d8SKefeng Wang shadow_end = ALIGN(shadow_end, PAGE_SIZE);
2943252b1d8SKefeng Wang kasan_map_populate(shadow_start, shadow_end, NUMA_NO_NODE);
2953252b1d8SKefeng Wang }
2963252b1d8SKefeng Wang #endif
2973252b1d8SKefeng Wang
kasan_init(void)298afe6ef80SAndrey Konovalov void __init kasan_init(void)
299afe6ef80SAndrey Konovalov {
300afe6ef80SAndrey Konovalov kasan_init_shadow();
301d73b4936SAndrey Konovalov kasan_init_depth();
30228ab3584SAndrey Konovalov #if defined(CONFIG_KASAN_GENERIC)
30360a3a5feSAndrey Konovalov /* CONFIG_KASAN_SW_TAGS also requires kasan_init_sw_tags(). */
304b873e986SKuan-Ying Lee pr_info("KernelAddressSanitizer initialized (generic)\n");
30528ab3584SAndrey Konovalov #endif
30639d114ddSAndrey Ryabinin }
30728ab3584SAndrey Konovalov
30828ab3584SAndrey Konovalov #endif /* CONFIG_KASAN_GENERIC || CONFIG_KASAN_SW_TAGS */
309