18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file contains some kasan initialization code. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015 Samsung Electronics Co., Ltd. 68c2ecf20Sopenharmony_ci * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 98c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as 108c2ecf20Sopenharmony_ci * published by the Free Software Foundation. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/memblock.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/kasan.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/pfn.h> 208c2ecf20Sopenharmony_ci#include <linux/slab.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/page.h> 238c2ecf20Sopenharmony_ci#include <asm/pgalloc.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "kasan.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * This page serves two purposes: 298c2ecf20Sopenharmony_ci * - It used as early shadow memory. The entire shadow region populated 308c2ecf20Sopenharmony_ci * with this page, before we will be able to setup normal shadow memory. 318c2ecf20Sopenharmony_ci * - Latter it reused it as zero shadow to cover large ranges of memory 328c2ecf20Sopenharmony_ci * that allowed to access, but not handled by kasan (vmalloc/vmemmap ...). 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ciunsigned char kasan_early_shadow_page[PAGE_SIZE] __page_aligned_bss; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 4 378c2ecf20Sopenharmony_cip4d_t kasan_early_shadow_p4d[MAX_PTRS_PER_P4D] __page_aligned_bss; 388c2ecf20Sopenharmony_cistatic inline bool kasan_p4d_table(pgd_t pgd) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci return pgd_page(pgd) == virt_to_page(lm_alias(kasan_early_shadow_p4d)); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci#else 438c2ecf20Sopenharmony_cistatic inline bool kasan_p4d_table(pgd_t pgd) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci return false; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci#endif 488c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 3 498c2ecf20Sopenharmony_cipud_t kasan_early_shadow_pud[PTRS_PER_PUD] __page_aligned_bss; 508c2ecf20Sopenharmony_cistatic inline bool kasan_pud_table(p4d_t p4d) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return p4d_page(p4d) == virt_to_page(lm_alias(kasan_early_shadow_pud)); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci#else 558c2ecf20Sopenharmony_cistatic inline bool kasan_pud_table(p4d_t p4d) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci return false; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci#endif 608c2ecf20Sopenharmony_ci#if CONFIG_PGTABLE_LEVELS > 2 618c2ecf20Sopenharmony_cipmd_t kasan_early_shadow_pmd[PTRS_PER_PMD] __page_aligned_bss; 628c2ecf20Sopenharmony_cistatic inline bool kasan_pmd_table(pud_t pud) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return pud_page(pud) == virt_to_page(lm_alias(kasan_early_shadow_pmd)); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci#else 678c2ecf20Sopenharmony_cistatic inline bool kasan_pmd_table(pud_t pud) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci return false; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_cipte_t kasan_early_shadow_pte[PTRS_PER_PTE] __page_aligned_bss; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline bool kasan_pte_table(pmd_t pmd) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci return pmd_page(pmd) == virt_to_page(lm_alias(kasan_early_shadow_pte)); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic inline bool kasan_early_shadow_page_entry(pte_t pte) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci return pte_page(pte) == virt_to_page(lm_alias(kasan_early_shadow_page)); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic __init void *early_alloc(size_t size, int node) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci void *ptr = memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS), 878c2ecf20Sopenharmony_ci MEMBLOCK_ALLOC_ACCESSIBLE, node); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (!ptr) 908c2ecf20Sopenharmony_ci panic("%s: Failed to allocate %zu bytes align=%zx nid=%d from=%llx\n", 918c2ecf20Sopenharmony_ci __func__, size, size, node, (u64)__pa(MAX_DMA_ADDRESS)); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return ptr; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr, 978c2ecf20Sopenharmony_ci unsigned long end) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci pte_t *pte = pte_offset_kernel(pmd, addr); 1008c2ecf20Sopenharmony_ci pte_t zero_pte; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci zero_pte = pfn_pte(PFN_DOWN(__pa_symbol(kasan_early_shadow_page)), 1038c2ecf20Sopenharmony_ci PAGE_KERNEL); 1048c2ecf20Sopenharmony_ci zero_pte = pte_wrprotect(zero_pte); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci while (addr + PAGE_SIZE <= end) { 1078c2ecf20Sopenharmony_ci set_pte_at(&init_mm, addr, pte, zero_pte); 1088c2ecf20Sopenharmony_ci addr += PAGE_SIZE; 1098c2ecf20Sopenharmony_ci pte = pte_offset_kernel(pmd, addr); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, 1148c2ecf20Sopenharmony_ci unsigned long end) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci pmd_t *pmd = pmd_offset(pud, addr); 1178c2ecf20Sopenharmony_ci unsigned long next; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci do { 1208c2ecf20Sopenharmony_ci next = pmd_addr_end(addr, end); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { 1238c2ecf20Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, 1248c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pte)); 1258c2ecf20Sopenharmony_ci continue; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (pmd_none(*pmd)) { 1298c2ecf20Sopenharmony_ci pte_t *p; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (slab_is_available()) 1328c2ecf20Sopenharmony_ci p = pte_alloc_one_kernel(&init_mm); 1338c2ecf20Sopenharmony_ci else 1348c2ecf20Sopenharmony_ci p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 1358c2ecf20Sopenharmony_ci if (!p) 1368c2ecf20Sopenharmony_ci return -ENOMEM; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, p); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci zero_pte_populate(pmd, addr, next); 1418c2ecf20Sopenharmony_ci } while (pmd++, addr = next, addr != end); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, 1478c2ecf20Sopenharmony_ci unsigned long end) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci pud_t *pud = pud_offset(p4d, addr); 1508c2ecf20Sopenharmony_ci unsigned long next; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci do { 1538c2ecf20Sopenharmony_ci next = pud_addr_end(addr, end); 1548c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { 1558c2ecf20Sopenharmony_ci pmd_t *pmd; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci pud_populate(&init_mm, pud, 1588c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pmd)); 1598c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 1608c2ecf20Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, 1618c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pte)); 1628c2ecf20Sopenharmony_ci continue; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (pud_none(*pud)) { 1668c2ecf20Sopenharmony_ci pmd_t *p; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (slab_is_available()) { 1698c2ecf20Sopenharmony_ci p = pmd_alloc(&init_mm, pud, addr); 1708c2ecf20Sopenharmony_ci if (!p) 1718c2ecf20Sopenharmony_ci return -ENOMEM; 1728c2ecf20Sopenharmony_ci } else { 1738c2ecf20Sopenharmony_ci p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 1748c2ecf20Sopenharmony_ci#ifdef CONFIG_LOONGARCH 1758c2ecf20Sopenharmony_ci pmd_init((unsigned long)p, (unsigned long)invalid_pte_table); 1768c2ecf20Sopenharmony_ci#endif 1778c2ecf20Sopenharmony_ci pud_populate(&init_mm, pud, p); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci zero_pmd_populate(pud, addr, next); 1818c2ecf20Sopenharmony_ci } while (pud++, addr = next, addr != end); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, 1878c2ecf20Sopenharmony_ci unsigned long end) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci p4d_t *p4d = p4d_offset(pgd, addr); 1908c2ecf20Sopenharmony_ci unsigned long next; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci do { 1938c2ecf20Sopenharmony_ci next = p4d_addr_end(addr, end); 1948c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { 1958c2ecf20Sopenharmony_ci pud_t *pud; 1968c2ecf20Sopenharmony_ci pmd_t *pmd; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci p4d_populate(&init_mm, p4d, 1998c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pud)); 2008c2ecf20Sopenharmony_ci pud = pud_offset(p4d, addr); 2018c2ecf20Sopenharmony_ci pud_populate(&init_mm, pud, 2028c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pmd)); 2038c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 2048c2ecf20Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, 2058c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pte)); 2068c2ecf20Sopenharmony_ci continue; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (p4d_none(*p4d)) { 2108c2ecf20Sopenharmony_ci pud_t *p; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (slab_is_available()) { 2138c2ecf20Sopenharmony_ci p = pud_alloc(&init_mm, p4d, addr); 2148c2ecf20Sopenharmony_ci if (!p) 2158c2ecf20Sopenharmony_ci return -ENOMEM; 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 2188c2ecf20Sopenharmony_ci#ifdef CONFIG_LOONGARCH 2198c2ecf20Sopenharmony_ci pud_init((unsigned long)p, (unsigned long)invalid_pmd_table); 2208c2ecf20Sopenharmony_ci#endif 2218c2ecf20Sopenharmony_ci p4d_populate(&init_mm, p4d, p); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci zero_pud_populate(p4d, addr, next); 2258c2ecf20Sopenharmony_ci } while (p4d++, addr = next, addr != end); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/** 2318c2ecf20Sopenharmony_ci * kasan_populate_early_shadow - populate shadow memory region with 2328c2ecf20Sopenharmony_ci * kasan_early_shadow_page 2338c2ecf20Sopenharmony_ci * @shadow_start - start of the memory range to populate 2348c2ecf20Sopenharmony_ci * @shadow_end - end of the memory range to populate 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ciint __ref kasan_populate_early_shadow(const void *shadow_start, 2378c2ecf20Sopenharmony_ci const void *shadow_end) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)shadow_start; 2408c2ecf20Sopenharmony_ci unsigned long end = (unsigned long)shadow_end; 2418c2ecf20Sopenharmony_ci pgd_t *pgd = pgd_offset_k(addr); 2428c2ecf20Sopenharmony_ci unsigned long next; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci do { 2458c2ecf20Sopenharmony_ci next = pgd_addr_end(addr, end); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { 2488c2ecf20Sopenharmony_ci p4d_t *p4d; 2498c2ecf20Sopenharmony_ci pud_t *pud; 2508c2ecf20Sopenharmony_ci pmd_t *pmd; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * kasan_early_shadow_pud should be populated with pmds 2548c2ecf20Sopenharmony_ci * at this moment. 2558c2ecf20Sopenharmony_ci * [pud,pmd]_populate*() below needed only for 2568c2ecf20Sopenharmony_ci * 3,2 - level page tables where we don't have 2578c2ecf20Sopenharmony_ci * puds,pmds, so pgd_populate(), pud_populate() 2588c2ecf20Sopenharmony_ci * is noops. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci pgd_populate(&init_mm, pgd, 2618c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_p4d)); 2628c2ecf20Sopenharmony_ci p4d = p4d_offset(pgd, addr); 2638c2ecf20Sopenharmony_ci p4d_populate(&init_mm, p4d, 2648c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pud)); 2658c2ecf20Sopenharmony_ci pud = pud_offset(p4d, addr); 2668c2ecf20Sopenharmony_ci pud_populate(&init_mm, pud, 2678c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pmd)); 2688c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 2698c2ecf20Sopenharmony_ci pmd_populate_kernel(&init_mm, pmd, 2708c2ecf20Sopenharmony_ci lm_alias(kasan_early_shadow_pte)); 2718c2ecf20Sopenharmony_ci continue; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (pgd_none(*pgd)) { 2758c2ecf20Sopenharmony_ci p4d_t *p; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (slab_is_available()) { 2788c2ecf20Sopenharmony_ci p = p4d_alloc(&init_mm, pgd, addr); 2798c2ecf20Sopenharmony_ci if (!p) 2808c2ecf20Sopenharmony_ci return -ENOMEM; 2818c2ecf20Sopenharmony_ci } else { 2828c2ecf20Sopenharmony_ci pgd_populate(&init_mm, pgd, 2838c2ecf20Sopenharmony_ci early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci zero_p4d_populate(pgd, addr, next); 2878c2ecf20Sopenharmony_ci } while (pgd++, addr = next, addr != end); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic void kasan_free_pte(pte_t *pte_start, pmd_t *pmd) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci pte_t *pte; 2958c2ecf20Sopenharmony_ci int i; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_PTE; i++) { 2988c2ecf20Sopenharmony_ci pte = pte_start + i; 2998c2ecf20Sopenharmony_ci if (!pte_none(*pte)) 3008c2ecf20Sopenharmony_ci return; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci pte_free_kernel(&init_mm, (pte_t *)page_to_virt(pmd_page(*pmd))); 3048c2ecf20Sopenharmony_ci pmd_clear(pmd); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void kasan_free_pmd(pmd_t *pmd_start, pud_t *pud) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci pmd_t *pmd; 3108c2ecf20Sopenharmony_ci int i; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_PMD; i++) { 3138c2ecf20Sopenharmony_ci pmd = pmd_start + i; 3148c2ecf20Sopenharmony_ci if (!pmd_none(*pmd)) 3158c2ecf20Sopenharmony_ci return; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci pmd_free(&init_mm, (pmd_t *)page_to_virt(pud_page(*pud))); 3198c2ecf20Sopenharmony_ci pud_clear(pud); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void kasan_free_pud(pud_t *pud_start, p4d_t *p4d) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci pud_t *pud; 3258c2ecf20Sopenharmony_ci int i; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_PUD; i++) { 3288c2ecf20Sopenharmony_ci pud = pud_start + i; 3298c2ecf20Sopenharmony_ci if (!pud_none(*pud)) 3308c2ecf20Sopenharmony_ci return; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci pud_free(&init_mm, (pud_t *)page_to_virt(p4d_page(*p4d))); 3348c2ecf20Sopenharmony_ci p4d_clear(p4d); 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void kasan_free_p4d(p4d_t *p4d_start, pgd_t *pgd) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci p4d_t *p4d; 3408c2ecf20Sopenharmony_ci int i; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci for (i = 0; i < PTRS_PER_P4D; i++) { 3438c2ecf20Sopenharmony_ci p4d = p4d_start + i; 3448c2ecf20Sopenharmony_ci if (!p4d_none(*p4d)) 3458c2ecf20Sopenharmony_ci return; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci p4d_free(&init_mm, (p4d_t *)page_to_virt(pgd_page(*pgd))); 3498c2ecf20Sopenharmony_ci pgd_clear(pgd); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void kasan_remove_pte_table(pte_t *pte, unsigned long addr, 3538c2ecf20Sopenharmony_ci unsigned long end) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci unsigned long next; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci for (; addr < end; addr = next, pte++) { 3588c2ecf20Sopenharmony_ci next = (addr + PAGE_SIZE) & PAGE_MASK; 3598c2ecf20Sopenharmony_ci if (next > end) 3608c2ecf20Sopenharmony_ci next = end; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (!pte_present(*pte)) 3638c2ecf20Sopenharmony_ci continue; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (WARN_ON(!kasan_early_shadow_page_entry(*pte))) 3668c2ecf20Sopenharmony_ci continue; 3678c2ecf20Sopenharmony_ci pte_clear(&init_mm, addr, pte); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr, 3728c2ecf20Sopenharmony_ci unsigned long end) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci unsigned long next; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (; addr < end; addr = next, pmd++) { 3778c2ecf20Sopenharmony_ci pte_t *pte; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci next = pmd_addr_end(addr, end); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!pmd_present(*pmd)) 3828c2ecf20Sopenharmony_ci continue; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (kasan_pte_table(*pmd)) { 3858c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PMD_SIZE) && 3868c2ecf20Sopenharmony_ci IS_ALIGNED(next, PMD_SIZE)) { 3878c2ecf20Sopenharmony_ci pmd_clear(pmd); 3888c2ecf20Sopenharmony_ci continue; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci pte = pte_offset_kernel(pmd, addr); 3928c2ecf20Sopenharmony_ci kasan_remove_pte_table(pte, addr, next); 3938c2ecf20Sopenharmony_ci kasan_free_pte(pte_offset_kernel(pmd, 0), pmd); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic void kasan_remove_pud_table(pud_t *pud, unsigned long addr, 3988c2ecf20Sopenharmony_ci unsigned long end) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci unsigned long next; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (; addr < end; addr = next, pud++) { 4038c2ecf20Sopenharmony_ci pmd_t *pmd, *pmd_base; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci next = pud_addr_end(addr, end); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!pud_present(*pud)) 4088c2ecf20Sopenharmony_ci continue; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (kasan_pmd_table(*pud)) { 4118c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PUD_SIZE) && 4128c2ecf20Sopenharmony_ci IS_ALIGNED(next, PUD_SIZE)) { 4138c2ecf20Sopenharmony_ci pud_clear(pud); 4148c2ecf20Sopenharmony_ci continue; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 4188c2ecf20Sopenharmony_ci pmd_base = pmd_offset(pud, 0); 4198c2ecf20Sopenharmony_ci kasan_remove_pmd_table(pmd, addr, next); 4208c2ecf20Sopenharmony_ci kasan_free_pmd(pmd_base, pud); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr, 4258c2ecf20Sopenharmony_ci unsigned long end) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci unsigned long next; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci for (; addr < end; addr = next, p4d++) { 4308c2ecf20Sopenharmony_ci pud_t *pud; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci next = p4d_addr_end(addr, end); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!p4d_present(*p4d)) 4358c2ecf20Sopenharmony_ci continue; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (kasan_pud_table(*p4d)) { 4388c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, P4D_SIZE) && 4398c2ecf20Sopenharmony_ci IS_ALIGNED(next, P4D_SIZE)) { 4408c2ecf20Sopenharmony_ci p4d_clear(p4d); 4418c2ecf20Sopenharmony_ci continue; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci pud = pud_offset(p4d, addr); 4458c2ecf20Sopenharmony_ci kasan_remove_pud_table(pud, addr, next); 4468c2ecf20Sopenharmony_ci kasan_free_pud(pud_offset(p4d, 0), p4d); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid kasan_remove_zero_shadow(void *start, unsigned long size) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci unsigned long addr, end, next; 4538c2ecf20Sopenharmony_ci pgd_t *pgd; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci addr = (unsigned long)kasan_mem_to_shadow(start); 4568c2ecf20Sopenharmony_ci end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (WARN_ON((unsigned long)start % 4598c2ecf20Sopenharmony_ci (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE)) || 4608c2ecf20Sopenharmony_ci WARN_ON(size % (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE))) 4618c2ecf20Sopenharmony_ci return; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci for (; addr < end; addr = next) { 4648c2ecf20Sopenharmony_ci p4d_t *p4d; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci next = pgd_addr_end(addr, end); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci pgd = pgd_offset_k(addr); 4698c2ecf20Sopenharmony_ci if (!pgd_present(*pgd)) 4708c2ecf20Sopenharmony_ci continue; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (kasan_p4d_table(*pgd)) { 4738c2ecf20Sopenharmony_ci if (IS_ALIGNED(addr, PGDIR_SIZE) && 4748c2ecf20Sopenharmony_ci IS_ALIGNED(next, PGDIR_SIZE)) { 4758c2ecf20Sopenharmony_ci pgd_clear(pgd); 4768c2ecf20Sopenharmony_ci continue; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci p4d = p4d_offset(pgd, addr); 4818c2ecf20Sopenharmony_ci kasan_remove_p4d_table(p4d, addr, next); 4828c2ecf20Sopenharmony_ci kasan_free_p4d(p4d_offset(pgd, 0), pgd); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ciint kasan_add_zero_shadow(void *start, unsigned long size) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci int ret; 4898c2ecf20Sopenharmony_ci void *shadow_start, *shadow_end; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci shadow_start = kasan_mem_to_shadow(start); 4928c2ecf20Sopenharmony_ci shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (WARN_ON((unsigned long)start % 4958c2ecf20Sopenharmony_ci (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE)) || 4968c2ecf20Sopenharmony_ci WARN_ON(size % (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE))) 4978c2ecf20Sopenharmony_ci return -EINVAL; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ret = kasan_populate_early_shadow(shadow_start, shadow_end); 5008c2ecf20Sopenharmony_ci if (ret) 5018c2ecf20Sopenharmony_ci kasan_remove_zero_shadow(start, size); 5028c2ecf20Sopenharmony_ci return ret; 5038c2ecf20Sopenharmony_ci} 504