1e886bf9dSAndrey Konovalov // SPDX-License-Identifier: GPL-2.0 2b938fcf4SAndrey Konovalov /* 3b266e8feSAndrey Konovalov * This file contains KASAN shadow initialization code. 4b938fcf4SAndrey Konovalov * 5b938fcf4SAndrey Konovalov * Copyright (c) 2015 Samsung Electronics Co., Ltd. 6b938fcf4SAndrey Konovalov * Author: Andrey Ryabinin <ryabinin.a.a@gmail.com> 7b938fcf4SAndrey Konovalov */ 8b938fcf4SAndrey Konovalov 9b938fcf4SAndrey Konovalov #include <linux/memblock.h> 10b938fcf4SAndrey Konovalov #include <linux/init.h> 11b938fcf4SAndrey Konovalov #include <linux/kasan.h> 12b938fcf4SAndrey Konovalov #include <linux/kernel.h> 13b938fcf4SAndrey Konovalov #include <linux/mm.h> 14b938fcf4SAndrey Konovalov #include <linux/pfn.h> 15b938fcf4SAndrey Konovalov #include <linux/slab.h> 16b938fcf4SAndrey Konovalov 17b938fcf4SAndrey Konovalov #include <asm/page.h> 18b938fcf4SAndrey Konovalov #include <asm/pgalloc.h> 19b938fcf4SAndrey Konovalov 20b938fcf4SAndrey Konovalov #include "kasan.h" 21b938fcf4SAndrey Konovalov 22b938fcf4SAndrey Konovalov /* 23b938fcf4SAndrey Konovalov * This page serves two purposes: 24b938fcf4SAndrey Konovalov * - It used as early shadow memory. The entire shadow region populated 25b938fcf4SAndrey Konovalov * with this page, before we will be able to setup normal shadow memory. 26b938fcf4SAndrey Konovalov * - Latter it reused it as zero shadow to cover large ranges of memory 27b938fcf4SAndrey Konovalov * that allowed to access, but not handled by kasan (vmalloc/vmemmap ...). 28b938fcf4SAndrey Konovalov */ 299577dd74SAndrey Konovalov unsigned char kasan_early_shadow_page[PAGE_SIZE] __page_aligned_bss; 30b938fcf4SAndrey Konovalov 31b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 4 329577dd74SAndrey Konovalov p4d_t kasan_early_shadow_p4d[MAX_PTRS_PER_P4D] __page_aligned_bss; 33b938fcf4SAndrey Konovalov static inline bool kasan_p4d_table(pgd_t pgd) 34b938fcf4SAndrey Konovalov { 359577dd74SAndrey Konovalov return pgd_page(pgd) == virt_to_page(lm_alias(kasan_early_shadow_p4d)); 36b938fcf4SAndrey Konovalov } 37b938fcf4SAndrey Konovalov #else 38b938fcf4SAndrey Konovalov static inline bool kasan_p4d_table(pgd_t pgd) 39b938fcf4SAndrey Konovalov { 405c0198b6SAndrey Konovalov return false; 41b938fcf4SAndrey Konovalov } 42b938fcf4SAndrey Konovalov #endif 43b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 3 449577dd74SAndrey Konovalov pud_t kasan_early_shadow_pud[PTRS_PER_PUD] __page_aligned_bss; 45b938fcf4SAndrey Konovalov static inline bool kasan_pud_table(p4d_t p4d) 46b938fcf4SAndrey Konovalov { 479577dd74SAndrey Konovalov return p4d_page(p4d) == virt_to_page(lm_alias(kasan_early_shadow_pud)); 48b938fcf4SAndrey Konovalov } 49b938fcf4SAndrey Konovalov #else 50b938fcf4SAndrey Konovalov static inline bool kasan_pud_table(p4d_t p4d) 51b938fcf4SAndrey Konovalov { 525c0198b6SAndrey Konovalov return false; 53b938fcf4SAndrey Konovalov } 54b938fcf4SAndrey Konovalov #endif 55b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 2 569577dd74SAndrey Konovalov pmd_t kasan_early_shadow_pmd[PTRS_PER_PMD] __page_aligned_bss; 57b938fcf4SAndrey Konovalov static inline bool kasan_pmd_table(pud_t pud) 58b938fcf4SAndrey Konovalov { 599577dd74SAndrey Konovalov return pud_page(pud) == virt_to_page(lm_alias(kasan_early_shadow_pmd)); 60b938fcf4SAndrey Konovalov } 61b938fcf4SAndrey Konovalov #else 62b938fcf4SAndrey Konovalov static inline bool kasan_pmd_table(pud_t pud) 63b938fcf4SAndrey Konovalov { 645c0198b6SAndrey Konovalov return false; 65b938fcf4SAndrey Konovalov } 66b938fcf4SAndrey Konovalov #endif 6729970dc2SHailong Liu pte_t kasan_early_shadow_pte[PTRS_PER_PTE + PTE_HWTABLE_PTRS] 6829970dc2SHailong Liu __page_aligned_bss; 69b938fcf4SAndrey Konovalov 70b938fcf4SAndrey Konovalov static inline bool kasan_pte_table(pmd_t pmd) 71b938fcf4SAndrey Konovalov { 729577dd74SAndrey Konovalov return pmd_page(pmd) == virt_to_page(lm_alias(kasan_early_shadow_pte)); 73b938fcf4SAndrey Konovalov } 74b938fcf4SAndrey Konovalov 759577dd74SAndrey Konovalov static inline bool kasan_early_shadow_page_entry(pte_t pte) 76b938fcf4SAndrey Konovalov { 779577dd74SAndrey Konovalov return pte_page(pte) == virt_to_page(lm_alias(kasan_early_shadow_page)); 78b938fcf4SAndrey Konovalov } 79b938fcf4SAndrey Konovalov 80b938fcf4SAndrey Konovalov static __init void *early_alloc(size_t size, int node) 81b938fcf4SAndrey Konovalov { 828a7f97b9SMike Rapoport void *ptr = memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS), 83b938fcf4SAndrey Konovalov MEMBLOCK_ALLOC_ACCESSIBLE, node); 848a7f97b9SMike Rapoport 858a7f97b9SMike Rapoport if (!ptr) 868a7f97b9SMike Rapoport panic("%s: Failed to allocate %zu bytes align=%zx nid=%d from=%llx\n", 878a7f97b9SMike Rapoport __func__, size, size, node, (u64)__pa(MAX_DMA_ADDRESS)); 888a7f97b9SMike Rapoport 898a7f97b9SMike Rapoport return ptr; 90b938fcf4SAndrey Konovalov } 91b938fcf4SAndrey Konovalov 92b938fcf4SAndrey Konovalov static void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr, 93b938fcf4SAndrey Konovalov unsigned long end) 94b938fcf4SAndrey Konovalov { 95b938fcf4SAndrey Konovalov pte_t *pte = pte_offset_kernel(pmd, addr); 96b938fcf4SAndrey Konovalov pte_t zero_pte; 97b938fcf4SAndrey Konovalov 989577dd74SAndrey Konovalov zero_pte = pfn_pte(PFN_DOWN(__pa_symbol(kasan_early_shadow_page)), 999577dd74SAndrey Konovalov PAGE_KERNEL); 100b938fcf4SAndrey Konovalov zero_pte = pte_wrprotect(zero_pte); 101b938fcf4SAndrey Konovalov 102b938fcf4SAndrey Konovalov while (addr + PAGE_SIZE <= end) { 103b938fcf4SAndrey Konovalov set_pte_at(&init_mm, addr, pte, zero_pte); 104b938fcf4SAndrey Konovalov addr += PAGE_SIZE; 105b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 106b938fcf4SAndrey Konovalov } 107b938fcf4SAndrey Konovalov } 108b938fcf4SAndrey Konovalov 109b938fcf4SAndrey Konovalov static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, 110b938fcf4SAndrey Konovalov unsigned long end) 111b938fcf4SAndrey Konovalov { 112b938fcf4SAndrey Konovalov pmd_t *pmd = pmd_offset(pud, addr); 113b938fcf4SAndrey Konovalov unsigned long next; 114b938fcf4SAndrey Konovalov 115b938fcf4SAndrey Konovalov do { 116b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 117b938fcf4SAndrey Konovalov 118b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { 1199577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1209577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 121b938fcf4SAndrey Konovalov continue; 122b938fcf4SAndrey Konovalov } 123b938fcf4SAndrey Konovalov 124b938fcf4SAndrey Konovalov if (pmd_none(*pmd)) { 125b938fcf4SAndrey Konovalov pte_t *p; 126b938fcf4SAndrey Konovalov 127b938fcf4SAndrey Konovalov if (slab_is_available()) 1284cf58924SJoel Fernandes (Google) p = pte_alloc_one_kernel(&init_mm); 129b938fcf4SAndrey Konovalov else 130b938fcf4SAndrey Konovalov p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 131b938fcf4SAndrey Konovalov if (!p) 132b938fcf4SAndrey Konovalov return -ENOMEM; 133b938fcf4SAndrey Konovalov 134b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, p); 135b938fcf4SAndrey Konovalov } 136b938fcf4SAndrey Konovalov zero_pte_populate(pmd, addr, next); 137b938fcf4SAndrey Konovalov } while (pmd++, addr = next, addr != end); 138b938fcf4SAndrey Konovalov 139b938fcf4SAndrey Konovalov return 0; 140b938fcf4SAndrey Konovalov } 141b938fcf4SAndrey Konovalov 142b938fcf4SAndrey Konovalov static int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, 143b938fcf4SAndrey Konovalov unsigned long end) 144b938fcf4SAndrey Konovalov { 145b938fcf4SAndrey Konovalov pud_t *pud = pud_offset(p4d, addr); 146b938fcf4SAndrey Konovalov unsigned long next; 147b938fcf4SAndrey Konovalov 148b938fcf4SAndrey Konovalov do { 149b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 150b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { 151b938fcf4SAndrey Konovalov pmd_t *pmd; 152b938fcf4SAndrey Konovalov 1539577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1549577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 155b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 1569577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1579577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 158b938fcf4SAndrey Konovalov continue; 159b938fcf4SAndrey Konovalov } 160b938fcf4SAndrey Konovalov 161b938fcf4SAndrey Konovalov if (pud_none(*pud)) { 162b938fcf4SAndrey Konovalov pmd_t *p; 163b938fcf4SAndrey Konovalov 164b938fcf4SAndrey Konovalov if (slab_is_available()) { 165b938fcf4SAndrey Konovalov p = pmd_alloc(&init_mm, pud, addr); 166b938fcf4SAndrey Konovalov if (!p) 167b938fcf4SAndrey Konovalov return -ENOMEM; 168b938fcf4SAndrey Konovalov } else { 169b938fcf4SAndrey Konovalov pud_populate(&init_mm, pud, 170b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 171b938fcf4SAndrey Konovalov } 172b938fcf4SAndrey Konovalov } 173b938fcf4SAndrey Konovalov zero_pmd_populate(pud, addr, next); 174b938fcf4SAndrey Konovalov } while (pud++, addr = next, addr != end); 175b938fcf4SAndrey Konovalov 176b938fcf4SAndrey Konovalov return 0; 177b938fcf4SAndrey Konovalov } 178b938fcf4SAndrey Konovalov 179b938fcf4SAndrey Konovalov static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, 180b938fcf4SAndrey Konovalov unsigned long end) 181b938fcf4SAndrey Konovalov { 182b938fcf4SAndrey Konovalov p4d_t *p4d = p4d_offset(pgd, addr); 183b938fcf4SAndrey Konovalov unsigned long next; 184b938fcf4SAndrey Konovalov 185b938fcf4SAndrey Konovalov do { 186b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 187b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { 188b938fcf4SAndrey Konovalov pud_t *pud; 189b938fcf4SAndrey Konovalov pmd_t *pmd; 190b938fcf4SAndrey Konovalov 1919577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 1929577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 193b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 1949577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1959577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 196b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 197b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1989577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 199b938fcf4SAndrey Konovalov continue; 200b938fcf4SAndrey Konovalov } 201b938fcf4SAndrey Konovalov 202b938fcf4SAndrey Konovalov if (p4d_none(*p4d)) { 203b938fcf4SAndrey Konovalov pud_t *p; 204b938fcf4SAndrey Konovalov 205b938fcf4SAndrey Konovalov if (slab_is_available()) { 206b938fcf4SAndrey Konovalov p = pud_alloc(&init_mm, p4d, addr); 207b938fcf4SAndrey Konovalov if (!p) 208b938fcf4SAndrey Konovalov return -ENOMEM; 209b938fcf4SAndrey Konovalov } else { 210b938fcf4SAndrey Konovalov p4d_populate(&init_mm, p4d, 211b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 212b938fcf4SAndrey Konovalov } 213b938fcf4SAndrey Konovalov } 214b938fcf4SAndrey Konovalov zero_pud_populate(p4d, addr, next); 215b938fcf4SAndrey Konovalov } while (p4d++, addr = next, addr != end); 216b938fcf4SAndrey Konovalov 217b938fcf4SAndrey Konovalov return 0; 218b938fcf4SAndrey Konovalov } 219b938fcf4SAndrey Konovalov 220b938fcf4SAndrey Konovalov /** 2219577dd74SAndrey Konovalov * kasan_populate_early_shadow - populate shadow memory region with 2229577dd74SAndrey Konovalov * kasan_early_shadow_page 223b938fcf4SAndrey Konovalov * @shadow_start - start of the memory range to populate 224b938fcf4SAndrey Konovalov * @shadow_end - end of the memory range to populate 225b938fcf4SAndrey Konovalov */ 2269577dd74SAndrey Konovalov int __ref kasan_populate_early_shadow(const void *shadow_start, 227b938fcf4SAndrey Konovalov const void *shadow_end) 228b938fcf4SAndrey Konovalov { 229b938fcf4SAndrey Konovalov unsigned long addr = (unsigned long)shadow_start; 230b938fcf4SAndrey Konovalov unsigned long end = (unsigned long)shadow_end; 231b938fcf4SAndrey Konovalov pgd_t *pgd = pgd_offset_k(addr); 232b938fcf4SAndrey Konovalov unsigned long next; 233b938fcf4SAndrey Konovalov 234b938fcf4SAndrey Konovalov do { 235b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 236b938fcf4SAndrey Konovalov 237b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { 238b938fcf4SAndrey Konovalov p4d_t *p4d; 239b938fcf4SAndrey Konovalov pud_t *pud; 240b938fcf4SAndrey Konovalov pmd_t *pmd; 241b938fcf4SAndrey Konovalov 242b938fcf4SAndrey Konovalov /* 2439577dd74SAndrey Konovalov * kasan_early_shadow_pud should be populated with pmds 244b938fcf4SAndrey Konovalov * at this moment. 245b938fcf4SAndrey Konovalov * [pud,pmd]_populate*() below needed only for 246b938fcf4SAndrey Konovalov * 3,2 - level page tables where we don't have 247b938fcf4SAndrey Konovalov * puds,pmds, so pgd_populate(), pud_populate() 248b938fcf4SAndrey Konovalov * is noops. 249b938fcf4SAndrey Konovalov */ 2509577dd74SAndrey Konovalov pgd_populate(&init_mm, pgd, 2519577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_p4d)); 252b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 2539577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 2549577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 255b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 2569577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 2579577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 258b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 2599577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 2609577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 261b938fcf4SAndrey Konovalov continue; 262b938fcf4SAndrey Konovalov } 263b938fcf4SAndrey Konovalov 264b938fcf4SAndrey Konovalov if (pgd_none(*pgd)) { 265b938fcf4SAndrey Konovalov p4d_t *p; 266b938fcf4SAndrey Konovalov 267b938fcf4SAndrey Konovalov if (slab_is_available()) { 268b938fcf4SAndrey Konovalov p = p4d_alloc(&init_mm, pgd, addr); 269b938fcf4SAndrey Konovalov if (!p) 270b938fcf4SAndrey Konovalov return -ENOMEM; 271b938fcf4SAndrey Konovalov } else { 272b938fcf4SAndrey Konovalov pgd_populate(&init_mm, pgd, 273b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 274b938fcf4SAndrey Konovalov } 275b938fcf4SAndrey Konovalov } 276b938fcf4SAndrey Konovalov zero_p4d_populate(pgd, addr, next); 277b938fcf4SAndrey Konovalov } while (pgd++, addr = next, addr != end); 278b938fcf4SAndrey Konovalov 279b938fcf4SAndrey Konovalov return 0; 280b938fcf4SAndrey Konovalov } 281b938fcf4SAndrey Konovalov 282b938fcf4SAndrey Konovalov static void kasan_free_pte(pte_t *pte_start, pmd_t *pmd) 283b938fcf4SAndrey Konovalov { 284b938fcf4SAndrey Konovalov pte_t *pte; 285b938fcf4SAndrey Konovalov int i; 286b938fcf4SAndrey Konovalov 287b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PTE; i++) { 288b938fcf4SAndrey Konovalov pte = pte_start + i; 289b938fcf4SAndrey Konovalov if (!pte_none(*pte)) 290b938fcf4SAndrey Konovalov return; 291b938fcf4SAndrey Konovalov } 292b938fcf4SAndrey Konovalov 293b938fcf4SAndrey Konovalov pte_free_kernel(&init_mm, (pte_t *)page_to_virt(pmd_page(*pmd))); 294b938fcf4SAndrey Konovalov pmd_clear(pmd); 295b938fcf4SAndrey Konovalov } 296b938fcf4SAndrey Konovalov 297b938fcf4SAndrey Konovalov static void kasan_free_pmd(pmd_t *pmd_start, pud_t *pud) 298b938fcf4SAndrey Konovalov { 299b938fcf4SAndrey Konovalov pmd_t *pmd; 300b938fcf4SAndrey Konovalov int i; 301b938fcf4SAndrey Konovalov 302b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PMD; i++) { 303b938fcf4SAndrey Konovalov pmd = pmd_start + i; 304b938fcf4SAndrey Konovalov if (!pmd_none(*pmd)) 305b938fcf4SAndrey Konovalov return; 306b938fcf4SAndrey Konovalov } 307b938fcf4SAndrey Konovalov 308b938fcf4SAndrey Konovalov pmd_free(&init_mm, (pmd_t *)page_to_virt(pud_page(*pud))); 309b938fcf4SAndrey Konovalov pud_clear(pud); 310b938fcf4SAndrey Konovalov } 311b938fcf4SAndrey Konovalov 312b938fcf4SAndrey Konovalov static void kasan_free_pud(pud_t *pud_start, p4d_t *p4d) 313b938fcf4SAndrey Konovalov { 314b938fcf4SAndrey Konovalov pud_t *pud; 315b938fcf4SAndrey Konovalov int i; 316b938fcf4SAndrey Konovalov 317b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PUD; i++) { 318b938fcf4SAndrey Konovalov pud = pud_start + i; 319b938fcf4SAndrey Konovalov if (!pud_none(*pud)) 320b938fcf4SAndrey Konovalov return; 321b938fcf4SAndrey Konovalov } 322b938fcf4SAndrey Konovalov 323b938fcf4SAndrey Konovalov pud_free(&init_mm, (pud_t *)page_to_virt(p4d_page(*p4d))); 324b938fcf4SAndrey Konovalov p4d_clear(p4d); 325b938fcf4SAndrey Konovalov } 326b938fcf4SAndrey Konovalov 327b938fcf4SAndrey Konovalov static void kasan_free_p4d(p4d_t *p4d_start, pgd_t *pgd) 328b938fcf4SAndrey Konovalov { 329b938fcf4SAndrey Konovalov p4d_t *p4d; 330b938fcf4SAndrey Konovalov int i; 331b938fcf4SAndrey Konovalov 332b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_P4D; i++) { 333b938fcf4SAndrey Konovalov p4d = p4d_start + i; 334b938fcf4SAndrey Konovalov if (!p4d_none(*p4d)) 335b938fcf4SAndrey Konovalov return; 336b938fcf4SAndrey Konovalov } 337b938fcf4SAndrey Konovalov 338b938fcf4SAndrey Konovalov p4d_free(&init_mm, (p4d_t *)page_to_virt(pgd_page(*pgd))); 339b938fcf4SAndrey Konovalov pgd_clear(pgd); 340b938fcf4SAndrey Konovalov } 341b938fcf4SAndrey Konovalov 342b938fcf4SAndrey Konovalov static void kasan_remove_pte_table(pte_t *pte, unsigned long addr, 343b938fcf4SAndrey Konovalov unsigned long end) 344b938fcf4SAndrey Konovalov { 345b938fcf4SAndrey Konovalov unsigned long next; 346b938fcf4SAndrey Konovalov 347b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pte++) { 348b938fcf4SAndrey Konovalov next = (addr + PAGE_SIZE) & PAGE_MASK; 349b938fcf4SAndrey Konovalov if (next > end) 350b938fcf4SAndrey Konovalov next = end; 351b938fcf4SAndrey Konovalov 352b938fcf4SAndrey Konovalov if (!pte_present(*pte)) 353b938fcf4SAndrey Konovalov continue; 354b938fcf4SAndrey Konovalov 3559577dd74SAndrey Konovalov if (WARN_ON(!kasan_early_shadow_page_entry(*pte))) 356b938fcf4SAndrey Konovalov continue; 357b938fcf4SAndrey Konovalov pte_clear(&init_mm, addr, pte); 358b938fcf4SAndrey Konovalov } 359b938fcf4SAndrey Konovalov } 360b938fcf4SAndrey Konovalov 361b938fcf4SAndrey Konovalov static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr, 362b938fcf4SAndrey Konovalov unsigned long end) 363b938fcf4SAndrey Konovalov { 364b938fcf4SAndrey Konovalov unsigned long next; 365b938fcf4SAndrey Konovalov 366b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pmd++) { 367b938fcf4SAndrey Konovalov pte_t *pte; 368b938fcf4SAndrey Konovalov 369b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 370b938fcf4SAndrey Konovalov 371b938fcf4SAndrey Konovalov if (!pmd_present(*pmd)) 372b938fcf4SAndrey Konovalov continue; 373b938fcf4SAndrey Konovalov 374b938fcf4SAndrey Konovalov if (kasan_pte_table(*pmd)) { 375b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && 376*a11a496eSLecopzer Chen IS_ALIGNED(next, PMD_SIZE)) { 377b938fcf4SAndrey Konovalov pmd_clear(pmd); 378b938fcf4SAndrey Konovalov continue; 379b938fcf4SAndrey Konovalov } 380*a11a496eSLecopzer Chen } 381b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 382b938fcf4SAndrey Konovalov kasan_remove_pte_table(pte, addr, next); 383b938fcf4SAndrey Konovalov kasan_free_pte(pte_offset_kernel(pmd, 0), pmd); 384b938fcf4SAndrey Konovalov } 385b938fcf4SAndrey Konovalov } 386b938fcf4SAndrey Konovalov 387b938fcf4SAndrey Konovalov static void kasan_remove_pud_table(pud_t *pud, unsigned long addr, 388b938fcf4SAndrey Konovalov unsigned long end) 389b938fcf4SAndrey Konovalov { 390b938fcf4SAndrey Konovalov unsigned long next; 391b938fcf4SAndrey Konovalov 392b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pud++) { 393b938fcf4SAndrey Konovalov pmd_t *pmd, *pmd_base; 394b938fcf4SAndrey Konovalov 395b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 396b938fcf4SAndrey Konovalov 397b938fcf4SAndrey Konovalov if (!pud_present(*pud)) 398b938fcf4SAndrey Konovalov continue; 399b938fcf4SAndrey Konovalov 400b938fcf4SAndrey Konovalov if (kasan_pmd_table(*pud)) { 401b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && 402*a11a496eSLecopzer Chen IS_ALIGNED(next, PUD_SIZE)) { 403b938fcf4SAndrey Konovalov pud_clear(pud); 404b938fcf4SAndrey Konovalov continue; 405b938fcf4SAndrey Konovalov } 406*a11a496eSLecopzer Chen } 407b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 408b938fcf4SAndrey Konovalov pmd_base = pmd_offset(pud, 0); 409b938fcf4SAndrey Konovalov kasan_remove_pmd_table(pmd, addr, next); 410b938fcf4SAndrey Konovalov kasan_free_pmd(pmd_base, pud); 411b938fcf4SAndrey Konovalov } 412b938fcf4SAndrey Konovalov } 413b938fcf4SAndrey Konovalov 414b938fcf4SAndrey Konovalov static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr, 415b938fcf4SAndrey Konovalov unsigned long end) 416b938fcf4SAndrey Konovalov { 417b938fcf4SAndrey Konovalov unsigned long next; 418b938fcf4SAndrey Konovalov 419b938fcf4SAndrey Konovalov for (; addr < end; addr = next, p4d++) { 420b938fcf4SAndrey Konovalov pud_t *pud; 421b938fcf4SAndrey Konovalov 422b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 423b938fcf4SAndrey Konovalov 424b938fcf4SAndrey Konovalov if (!p4d_present(*p4d)) 425b938fcf4SAndrey Konovalov continue; 426b938fcf4SAndrey Konovalov 427b938fcf4SAndrey Konovalov if (kasan_pud_table(*p4d)) { 428b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && 429*a11a496eSLecopzer Chen IS_ALIGNED(next, P4D_SIZE)) { 430b938fcf4SAndrey Konovalov p4d_clear(p4d); 431b938fcf4SAndrey Konovalov continue; 432b938fcf4SAndrey Konovalov } 433*a11a496eSLecopzer Chen } 434b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 435b938fcf4SAndrey Konovalov kasan_remove_pud_table(pud, addr, next); 436b938fcf4SAndrey Konovalov kasan_free_pud(pud_offset(p4d, 0), p4d); 437b938fcf4SAndrey Konovalov } 438b938fcf4SAndrey Konovalov } 439b938fcf4SAndrey Konovalov 440b938fcf4SAndrey Konovalov void kasan_remove_zero_shadow(void *start, unsigned long size) 441b938fcf4SAndrey Konovalov { 442b938fcf4SAndrey Konovalov unsigned long addr, end, next; 443b938fcf4SAndrey Konovalov pgd_t *pgd; 444b938fcf4SAndrey Konovalov 445b938fcf4SAndrey Konovalov addr = (unsigned long)kasan_mem_to_shadow(start); 446b938fcf4SAndrey Konovalov end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT); 447b938fcf4SAndrey Konovalov 448affc3f07SAndrey Konovalov if (WARN_ON((unsigned long)start % KASAN_MEMORY_PER_SHADOW_PAGE) || 449affc3f07SAndrey Konovalov WARN_ON(size % KASAN_MEMORY_PER_SHADOW_PAGE)) 450b938fcf4SAndrey Konovalov return; 451b938fcf4SAndrey Konovalov 452b938fcf4SAndrey Konovalov for (; addr < end; addr = next) { 453b938fcf4SAndrey Konovalov p4d_t *p4d; 454b938fcf4SAndrey Konovalov 455b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 456b938fcf4SAndrey Konovalov 457b938fcf4SAndrey Konovalov pgd = pgd_offset_k(addr); 458b938fcf4SAndrey Konovalov if (!pgd_present(*pgd)) 459b938fcf4SAndrey Konovalov continue; 460b938fcf4SAndrey Konovalov 461b938fcf4SAndrey Konovalov if (kasan_p4d_table(*pgd)) { 462b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && 463*a11a496eSLecopzer Chen IS_ALIGNED(next, PGDIR_SIZE)) { 464b938fcf4SAndrey Konovalov pgd_clear(pgd); 465b938fcf4SAndrey Konovalov continue; 466b938fcf4SAndrey Konovalov } 467*a11a496eSLecopzer Chen } 468b938fcf4SAndrey Konovalov 469b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 470b938fcf4SAndrey Konovalov kasan_remove_p4d_table(p4d, addr, next); 471b938fcf4SAndrey Konovalov kasan_free_p4d(p4d_offset(pgd, 0), pgd); 472b938fcf4SAndrey Konovalov } 473b938fcf4SAndrey Konovalov } 474b938fcf4SAndrey Konovalov 475b938fcf4SAndrey Konovalov int kasan_add_zero_shadow(void *start, unsigned long size) 476b938fcf4SAndrey Konovalov { 477b938fcf4SAndrey Konovalov int ret; 478b938fcf4SAndrey Konovalov void *shadow_start, *shadow_end; 479b938fcf4SAndrey Konovalov 480b938fcf4SAndrey Konovalov shadow_start = kasan_mem_to_shadow(start); 481b938fcf4SAndrey Konovalov shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT); 482b938fcf4SAndrey Konovalov 483affc3f07SAndrey Konovalov if (WARN_ON((unsigned long)start % KASAN_MEMORY_PER_SHADOW_PAGE) || 484affc3f07SAndrey Konovalov WARN_ON(size % KASAN_MEMORY_PER_SHADOW_PAGE)) 485b938fcf4SAndrey Konovalov return -EINVAL; 486b938fcf4SAndrey Konovalov 4879577dd74SAndrey Konovalov ret = kasan_populate_early_shadow(shadow_start, shadow_end); 488b938fcf4SAndrey Konovalov if (ret) 489b938fcf4SAndrey Konovalov kasan_remove_zero_shadow(shadow_start, 490b938fcf4SAndrey Konovalov size >> KASAN_SHADOW_SCALE_SHIFT); 491b938fcf4SAndrey Konovalov return ret; 492b938fcf4SAndrey Konovalov } 493