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 679577dd74SAndrey Konovalov pte_t kasan_early_shadow_pte[PTRS_PER_PTE] __page_aligned_bss; 68b938fcf4SAndrey Konovalov 69b938fcf4SAndrey Konovalov static inline bool kasan_pte_table(pmd_t pmd) 70b938fcf4SAndrey Konovalov { 719577dd74SAndrey Konovalov return pmd_page(pmd) == virt_to_page(lm_alias(kasan_early_shadow_pte)); 72b938fcf4SAndrey Konovalov } 73b938fcf4SAndrey Konovalov 749577dd74SAndrey Konovalov static inline bool kasan_early_shadow_page_entry(pte_t pte) 75b938fcf4SAndrey Konovalov { 769577dd74SAndrey Konovalov return pte_page(pte) == virt_to_page(lm_alias(kasan_early_shadow_page)); 77b938fcf4SAndrey Konovalov } 78b938fcf4SAndrey Konovalov 79b938fcf4SAndrey Konovalov static __init void *early_alloc(size_t size, int node) 80b938fcf4SAndrey Konovalov { 818a7f97b9SMike Rapoport void *ptr = memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS), 82b938fcf4SAndrey Konovalov MEMBLOCK_ALLOC_ACCESSIBLE, node); 838a7f97b9SMike Rapoport 848a7f97b9SMike Rapoport if (!ptr) 858a7f97b9SMike Rapoport panic("%s: Failed to allocate %zu bytes align=%zx nid=%d from=%llx\n", 868a7f97b9SMike Rapoport __func__, size, size, node, (u64)__pa(MAX_DMA_ADDRESS)); 878a7f97b9SMike Rapoport 888a7f97b9SMike Rapoport return ptr; 89b938fcf4SAndrey Konovalov } 90b938fcf4SAndrey Konovalov 91b938fcf4SAndrey Konovalov static void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr, 92b938fcf4SAndrey Konovalov unsigned long end) 93b938fcf4SAndrey Konovalov { 94b938fcf4SAndrey Konovalov pte_t *pte = pte_offset_kernel(pmd, addr); 95b938fcf4SAndrey Konovalov pte_t zero_pte; 96b938fcf4SAndrey Konovalov 979577dd74SAndrey Konovalov zero_pte = pfn_pte(PFN_DOWN(__pa_symbol(kasan_early_shadow_page)), 989577dd74SAndrey Konovalov PAGE_KERNEL); 99b938fcf4SAndrey Konovalov zero_pte = pte_wrprotect(zero_pte); 100b938fcf4SAndrey Konovalov 101b938fcf4SAndrey Konovalov while (addr + PAGE_SIZE <= end) { 102b938fcf4SAndrey Konovalov set_pte_at(&init_mm, addr, pte, zero_pte); 103b938fcf4SAndrey Konovalov addr += PAGE_SIZE; 104b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 105b938fcf4SAndrey Konovalov } 106b938fcf4SAndrey Konovalov } 107b938fcf4SAndrey Konovalov 108b938fcf4SAndrey Konovalov static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, 109b938fcf4SAndrey Konovalov unsigned long end) 110b938fcf4SAndrey Konovalov { 111b938fcf4SAndrey Konovalov pmd_t *pmd = pmd_offset(pud, addr); 112b938fcf4SAndrey Konovalov unsigned long next; 113b938fcf4SAndrey Konovalov 114b938fcf4SAndrey Konovalov do { 115b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 116b938fcf4SAndrey Konovalov 117b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { 1189577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1199577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 120b938fcf4SAndrey Konovalov continue; 121b938fcf4SAndrey Konovalov } 122b938fcf4SAndrey Konovalov 123b938fcf4SAndrey Konovalov if (pmd_none(*pmd)) { 124b938fcf4SAndrey Konovalov pte_t *p; 125b938fcf4SAndrey Konovalov 126b938fcf4SAndrey Konovalov if (slab_is_available()) 1274cf58924SJoel Fernandes (Google) p = pte_alloc_one_kernel(&init_mm); 128b938fcf4SAndrey Konovalov else 129b938fcf4SAndrey Konovalov p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 130b938fcf4SAndrey Konovalov if (!p) 131b938fcf4SAndrey Konovalov return -ENOMEM; 132b938fcf4SAndrey Konovalov 133b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, p); 134b938fcf4SAndrey Konovalov } 135b938fcf4SAndrey Konovalov zero_pte_populate(pmd, addr, next); 136b938fcf4SAndrey Konovalov } while (pmd++, addr = next, addr != end); 137b938fcf4SAndrey Konovalov 138b938fcf4SAndrey Konovalov return 0; 139b938fcf4SAndrey Konovalov } 140b938fcf4SAndrey Konovalov 141b938fcf4SAndrey Konovalov static int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, 142b938fcf4SAndrey Konovalov unsigned long end) 143b938fcf4SAndrey Konovalov { 144b938fcf4SAndrey Konovalov pud_t *pud = pud_offset(p4d, addr); 145b938fcf4SAndrey Konovalov unsigned long next; 146b938fcf4SAndrey Konovalov 147b938fcf4SAndrey Konovalov do { 148b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 149b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { 150b938fcf4SAndrey Konovalov pmd_t *pmd; 151b938fcf4SAndrey Konovalov 1529577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1539577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 154b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 1559577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1569577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 157b938fcf4SAndrey Konovalov continue; 158b938fcf4SAndrey Konovalov } 159b938fcf4SAndrey Konovalov 160b938fcf4SAndrey Konovalov if (pud_none(*pud)) { 161b938fcf4SAndrey Konovalov pmd_t *p; 162b938fcf4SAndrey Konovalov 163b938fcf4SAndrey Konovalov if (slab_is_available()) { 164b938fcf4SAndrey Konovalov p = pmd_alloc(&init_mm, pud, addr); 165b938fcf4SAndrey Konovalov if (!p) 166b938fcf4SAndrey Konovalov return -ENOMEM; 167b938fcf4SAndrey Konovalov } else { 168b938fcf4SAndrey Konovalov pud_populate(&init_mm, pud, 169b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 170b938fcf4SAndrey Konovalov } 171b938fcf4SAndrey Konovalov } 172b938fcf4SAndrey Konovalov zero_pmd_populate(pud, addr, next); 173b938fcf4SAndrey Konovalov } while (pud++, addr = next, addr != end); 174b938fcf4SAndrey Konovalov 175b938fcf4SAndrey Konovalov return 0; 176b938fcf4SAndrey Konovalov } 177b938fcf4SAndrey Konovalov 178b938fcf4SAndrey Konovalov static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, 179b938fcf4SAndrey Konovalov unsigned long end) 180b938fcf4SAndrey Konovalov { 181b938fcf4SAndrey Konovalov p4d_t *p4d = p4d_offset(pgd, addr); 182b938fcf4SAndrey Konovalov unsigned long next; 183b938fcf4SAndrey Konovalov 184b938fcf4SAndrey Konovalov do { 185b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 186b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { 187b938fcf4SAndrey Konovalov pud_t *pud; 188b938fcf4SAndrey Konovalov pmd_t *pmd; 189b938fcf4SAndrey Konovalov 1909577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 1919577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 192b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 1939577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1949577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 195b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 196b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1979577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 198b938fcf4SAndrey Konovalov continue; 199b938fcf4SAndrey Konovalov } 200b938fcf4SAndrey Konovalov 201b938fcf4SAndrey Konovalov if (p4d_none(*p4d)) { 202b938fcf4SAndrey Konovalov pud_t *p; 203b938fcf4SAndrey Konovalov 204b938fcf4SAndrey Konovalov if (slab_is_available()) { 205b938fcf4SAndrey Konovalov p = pud_alloc(&init_mm, p4d, addr); 206b938fcf4SAndrey Konovalov if (!p) 207b938fcf4SAndrey Konovalov return -ENOMEM; 208b938fcf4SAndrey Konovalov } else { 209b938fcf4SAndrey Konovalov p4d_populate(&init_mm, p4d, 210b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 211b938fcf4SAndrey Konovalov } 212b938fcf4SAndrey Konovalov } 213b938fcf4SAndrey Konovalov zero_pud_populate(p4d, addr, next); 214b938fcf4SAndrey Konovalov } while (p4d++, addr = next, addr != end); 215b938fcf4SAndrey Konovalov 216b938fcf4SAndrey Konovalov return 0; 217b938fcf4SAndrey Konovalov } 218b938fcf4SAndrey Konovalov 219b938fcf4SAndrey Konovalov /** 2209577dd74SAndrey Konovalov * kasan_populate_early_shadow - populate shadow memory region with 2219577dd74SAndrey Konovalov * kasan_early_shadow_page 222b938fcf4SAndrey Konovalov * @shadow_start - start of the memory range to populate 223b938fcf4SAndrey Konovalov * @shadow_end - end of the memory range to populate 224b938fcf4SAndrey Konovalov */ 2259577dd74SAndrey Konovalov int __ref kasan_populate_early_shadow(const void *shadow_start, 226b938fcf4SAndrey Konovalov const void *shadow_end) 227b938fcf4SAndrey Konovalov { 228b938fcf4SAndrey Konovalov unsigned long addr = (unsigned long)shadow_start; 229b938fcf4SAndrey Konovalov unsigned long end = (unsigned long)shadow_end; 230b938fcf4SAndrey Konovalov pgd_t *pgd = pgd_offset_k(addr); 231b938fcf4SAndrey Konovalov unsigned long next; 232b938fcf4SAndrey Konovalov 233b938fcf4SAndrey Konovalov do { 234b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 235b938fcf4SAndrey Konovalov 236b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { 237b938fcf4SAndrey Konovalov p4d_t *p4d; 238b938fcf4SAndrey Konovalov pud_t *pud; 239b938fcf4SAndrey Konovalov pmd_t *pmd; 240b938fcf4SAndrey Konovalov 241b938fcf4SAndrey Konovalov /* 2429577dd74SAndrey Konovalov * kasan_early_shadow_pud should be populated with pmds 243b938fcf4SAndrey Konovalov * at this moment. 244b938fcf4SAndrey Konovalov * [pud,pmd]_populate*() below needed only for 245b938fcf4SAndrey Konovalov * 3,2 - level page tables where we don't have 246b938fcf4SAndrey Konovalov * puds,pmds, so pgd_populate(), pud_populate() 247b938fcf4SAndrey Konovalov * is noops. 248b938fcf4SAndrey Konovalov */ 2499577dd74SAndrey Konovalov pgd_populate(&init_mm, pgd, 2509577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_p4d)); 251b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 2529577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 2539577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 254b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 2559577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 2569577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 257b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 2589577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 2599577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 260b938fcf4SAndrey Konovalov continue; 261b938fcf4SAndrey Konovalov } 262b938fcf4SAndrey Konovalov 263b938fcf4SAndrey Konovalov if (pgd_none(*pgd)) { 264b938fcf4SAndrey Konovalov p4d_t *p; 265b938fcf4SAndrey Konovalov 266b938fcf4SAndrey Konovalov if (slab_is_available()) { 267b938fcf4SAndrey Konovalov p = p4d_alloc(&init_mm, pgd, addr); 268b938fcf4SAndrey Konovalov if (!p) 269b938fcf4SAndrey Konovalov return -ENOMEM; 270b938fcf4SAndrey Konovalov } else { 271b938fcf4SAndrey Konovalov pgd_populate(&init_mm, pgd, 272b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 273b938fcf4SAndrey Konovalov } 274b938fcf4SAndrey Konovalov } 275b938fcf4SAndrey Konovalov zero_p4d_populate(pgd, addr, next); 276b938fcf4SAndrey Konovalov } while (pgd++, addr = next, addr != end); 277b938fcf4SAndrey Konovalov 278b938fcf4SAndrey Konovalov return 0; 279b938fcf4SAndrey Konovalov } 280b938fcf4SAndrey Konovalov 281b938fcf4SAndrey Konovalov static void kasan_free_pte(pte_t *pte_start, pmd_t *pmd) 282b938fcf4SAndrey Konovalov { 283b938fcf4SAndrey Konovalov pte_t *pte; 284b938fcf4SAndrey Konovalov int i; 285b938fcf4SAndrey Konovalov 286b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PTE; i++) { 287b938fcf4SAndrey Konovalov pte = pte_start + i; 288b938fcf4SAndrey Konovalov if (!pte_none(*pte)) 289b938fcf4SAndrey Konovalov return; 290b938fcf4SAndrey Konovalov } 291b938fcf4SAndrey Konovalov 292b938fcf4SAndrey Konovalov pte_free_kernel(&init_mm, (pte_t *)page_to_virt(pmd_page(*pmd))); 293b938fcf4SAndrey Konovalov pmd_clear(pmd); 294b938fcf4SAndrey Konovalov } 295b938fcf4SAndrey Konovalov 296b938fcf4SAndrey Konovalov static void kasan_free_pmd(pmd_t *pmd_start, pud_t *pud) 297b938fcf4SAndrey Konovalov { 298b938fcf4SAndrey Konovalov pmd_t *pmd; 299b938fcf4SAndrey Konovalov int i; 300b938fcf4SAndrey Konovalov 301b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PMD; i++) { 302b938fcf4SAndrey Konovalov pmd = pmd_start + i; 303b938fcf4SAndrey Konovalov if (!pmd_none(*pmd)) 304b938fcf4SAndrey Konovalov return; 305b938fcf4SAndrey Konovalov } 306b938fcf4SAndrey Konovalov 307b938fcf4SAndrey Konovalov pmd_free(&init_mm, (pmd_t *)page_to_virt(pud_page(*pud))); 308b938fcf4SAndrey Konovalov pud_clear(pud); 309b938fcf4SAndrey Konovalov } 310b938fcf4SAndrey Konovalov 311b938fcf4SAndrey Konovalov static void kasan_free_pud(pud_t *pud_start, p4d_t *p4d) 312b938fcf4SAndrey Konovalov { 313b938fcf4SAndrey Konovalov pud_t *pud; 314b938fcf4SAndrey Konovalov int i; 315b938fcf4SAndrey Konovalov 316b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PUD; i++) { 317b938fcf4SAndrey Konovalov pud = pud_start + i; 318b938fcf4SAndrey Konovalov if (!pud_none(*pud)) 319b938fcf4SAndrey Konovalov return; 320b938fcf4SAndrey Konovalov } 321b938fcf4SAndrey Konovalov 322b938fcf4SAndrey Konovalov pud_free(&init_mm, (pud_t *)page_to_virt(p4d_page(*p4d))); 323b938fcf4SAndrey Konovalov p4d_clear(p4d); 324b938fcf4SAndrey Konovalov } 325b938fcf4SAndrey Konovalov 326b938fcf4SAndrey Konovalov static void kasan_free_p4d(p4d_t *p4d_start, pgd_t *pgd) 327b938fcf4SAndrey Konovalov { 328b938fcf4SAndrey Konovalov p4d_t *p4d; 329b938fcf4SAndrey Konovalov int i; 330b938fcf4SAndrey Konovalov 331b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_P4D; i++) { 332b938fcf4SAndrey Konovalov p4d = p4d_start + i; 333b938fcf4SAndrey Konovalov if (!p4d_none(*p4d)) 334b938fcf4SAndrey Konovalov return; 335b938fcf4SAndrey Konovalov } 336b938fcf4SAndrey Konovalov 337b938fcf4SAndrey Konovalov p4d_free(&init_mm, (p4d_t *)page_to_virt(pgd_page(*pgd))); 338b938fcf4SAndrey Konovalov pgd_clear(pgd); 339b938fcf4SAndrey Konovalov } 340b938fcf4SAndrey Konovalov 341b938fcf4SAndrey Konovalov static void kasan_remove_pte_table(pte_t *pte, unsigned long addr, 342b938fcf4SAndrey Konovalov unsigned long end) 343b938fcf4SAndrey Konovalov { 344b938fcf4SAndrey Konovalov unsigned long next; 345b938fcf4SAndrey Konovalov 346b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pte++) { 347b938fcf4SAndrey Konovalov next = (addr + PAGE_SIZE) & PAGE_MASK; 348b938fcf4SAndrey Konovalov if (next > end) 349b938fcf4SAndrey Konovalov next = end; 350b938fcf4SAndrey Konovalov 351b938fcf4SAndrey Konovalov if (!pte_present(*pte)) 352b938fcf4SAndrey Konovalov continue; 353b938fcf4SAndrey Konovalov 3549577dd74SAndrey Konovalov if (WARN_ON(!kasan_early_shadow_page_entry(*pte))) 355b938fcf4SAndrey Konovalov continue; 356b938fcf4SAndrey Konovalov pte_clear(&init_mm, addr, pte); 357b938fcf4SAndrey Konovalov } 358b938fcf4SAndrey Konovalov } 359b938fcf4SAndrey Konovalov 360b938fcf4SAndrey Konovalov static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr, 361b938fcf4SAndrey Konovalov unsigned long end) 362b938fcf4SAndrey Konovalov { 363b938fcf4SAndrey Konovalov unsigned long next; 364b938fcf4SAndrey Konovalov 365b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pmd++) { 366b938fcf4SAndrey Konovalov pte_t *pte; 367b938fcf4SAndrey Konovalov 368b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 369b938fcf4SAndrey Konovalov 370b938fcf4SAndrey Konovalov if (!pmd_present(*pmd)) 371b938fcf4SAndrey Konovalov continue; 372b938fcf4SAndrey Konovalov 373b938fcf4SAndrey Konovalov if (kasan_pte_table(*pmd)) { 374b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && 375b938fcf4SAndrey Konovalov IS_ALIGNED(next, PMD_SIZE)) 376b938fcf4SAndrey Konovalov pmd_clear(pmd); 377b938fcf4SAndrey Konovalov continue; 378b938fcf4SAndrey Konovalov } 379b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 380b938fcf4SAndrey Konovalov kasan_remove_pte_table(pte, addr, next); 381b938fcf4SAndrey Konovalov kasan_free_pte(pte_offset_kernel(pmd, 0), pmd); 382b938fcf4SAndrey Konovalov } 383b938fcf4SAndrey Konovalov } 384b938fcf4SAndrey Konovalov 385b938fcf4SAndrey Konovalov static void kasan_remove_pud_table(pud_t *pud, unsigned long addr, 386b938fcf4SAndrey Konovalov unsigned long end) 387b938fcf4SAndrey Konovalov { 388b938fcf4SAndrey Konovalov unsigned long next; 389b938fcf4SAndrey Konovalov 390b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pud++) { 391b938fcf4SAndrey Konovalov pmd_t *pmd, *pmd_base; 392b938fcf4SAndrey Konovalov 393b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 394b938fcf4SAndrey Konovalov 395b938fcf4SAndrey Konovalov if (!pud_present(*pud)) 396b938fcf4SAndrey Konovalov continue; 397b938fcf4SAndrey Konovalov 398b938fcf4SAndrey Konovalov if (kasan_pmd_table(*pud)) { 399b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && 400b938fcf4SAndrey Konovalov IS_ALIGNED(next, PUD_SIZE)) 401b938fcf4SAndrey Konovalov pud_clear(pud); 402b938fcf4SAndrey Konovalov continue; 403b938fcf4SAndrey Konovalov } 404b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 405b938fcf4SAndrey Konovalov pmd_base = pmd_offset(pud, 0); 406b938fcf4SAndrey Konovalov kasan_remove_pmd_table(pmd, addr, next); 407b938fcf4SAndrey Konovalov kasan_free_pmd(pmd_base, pud); 408b938fcf4SAndrey Konovalov } 409b938fcf4SAndrey Konovalov } 410b938fcf4SAndrey Konovalov 411b938fcf4SAndrey Konovalov static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr, 412b938fcf4SAndrey Konovalov unsigned long end) 413b938fcf4SAndrey Konovalov { 414b938fcf4SAndrey Konovalov unsigned long next; 415b938fcf4SAndrey Konovalov 416b938fcf4SAndrey Konovalov for (; addr < end; addr = next, p4d++) { 417b938fcf4SAndrey Konovalov pud_t *pud; 418b938fcf4SAndrey Konovalov 419b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 420b938fcf4SAndrey Konovalov 421b938fcf4SAndrey Konovalov if (!p4d_present(*p4d)) 422b938fcf4SAndrey Konovalov continue; 423b938fcf4SAndrey Konovalov 424b938fcf4SAndrey Konovalov if (kasan_pud_table(*p4d)) { 425b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && 426b938fcf4SAndrey Konovalov IS_ALIGNED(next, P4D_SIZE)) 427b938fcf4SAndrey Konovalov p4d_clear(p4d); 428b938fcf4SAndrey Konovalov continue; 429b938fcf4SAndrey Konovalov } 430b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 431b938fcf4SAndrey Konovalov kasan_remove_pud_table(pud, addr, next); 432b938fcf4SAndrey Konovalov kasan_free_pud(pud_offset(p4d, 0), p4d); 433b938fcf4SAndrey Konovalov } 434b938fcf4SAndrey Konovalov } 435b938fcf4SAndrey Konovalov 436b938fcf4SAndrey Konovalov void kasan_remove_zero_shadow(void *start, unsigned long size) 437b938fcf4SAndrey Konovalov { 438b938fcf4SAndrey Konovalov unsigned long addr, end, next; 439b938fcf4SAndrey Konovalov pgd_t *pgd; 440b938fcf4SAndrey Konovalov 441b938fcf4SAndrey Konovalov addr = (unsigned long)kasan_mem_to_shadow(start); 442b938fcf4SAndrey Konovalov end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT); 443b938fcf4SAndrey Konovalov 444*affc3f07SAndrey Konovalov if (WARN_ON((unsigned long)start % KASAN_MEMORY_PER_SHADOW_PAGE) || 445*affc3f07SAndrey Konovalov WARN_ON(size % KASAN_MEMORY_PER_SHADOW_PAGE)) 446b938fcf4SAndrey Konovalov return; 447b938fcf4SAndrey Konovalov 448b938fcf4SAndrey Konovalov for (; addr < end; addr = next) { 449b938fcf4SAndrey Konovalov p4d_t *p4d; 450b938fcf4SAndrey Konovalov 451b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 452b938fcf4SAndrey Konovalov 453b938fcf4SAndrey Konovalov pgd = pgd_offset_k(addr); 454b938fcf4SAndrey Konovalov if (!pgd_present(*pgd)) 455b938fcf4SAndrey Konovalov continue; 456b938fcf4SAndrey Konovalov 457b938fcf4SAndrey Konovalov if (kasan_p4d_table(*pgd)) { 458b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && 459b938fcf4SAndrey Konovalov IS_ALIGNED(next, PGDIR_SIZE)) 460b938fcf4SAndrey Konovalov pgd_clear(pgd); 461b938fcf4SAndrey Konovalov continue; 462b938fcf4SAndrey Konovalov } 463b938fcf4SAndrey Konovalov 464b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 465b938fcf4SAndrey Konovalov kasan_remove_p4d_table(p4d, addr, next); 466b938fcf4SAndrey Konovalov kasan_free_p4d(p4d_offset(pgd, 0), pgd); 467b938fcf4SAndrey Konovalov } 468b938fcf4SAndrey Konovalov } 469b938fcf4SAndrey Konovalov 470b938fcf4SAndrey Konovalov int kasan_add_zero_shadow(void *start, unsigned long size) 471b938fcf4SAndrey Konovalov { 472b938fcf4SAndrey Konovalov int ret; 473b938fcf4SAndrey Konovalov void *shadow_start, *shadow_end; 474b938fcf4SAndrey Konovalov 475b938fcf4SAndrey Konovalov shadow_start = kasan_mem_to_shadow(start); 476b938fcf4SAndrey Konovalov shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT); 477b938fcf4SAndrey Konovalov 478*affc3f07SAndrey Konovalov if (WARN_ON((unsigned long)start % KASAN_MEMORY_PER_SHADOW_PAGE) || 479*affc3f07SAndrey Konovalov WARN_ON(size % KASAN_MEMORY_PER_SHADOW_PAGE)) 480b938fcf4SAndrey Konovalov return -EINVAL; 481b938fcf4SAndrey Konovalov 4829577dd74SAndrey Konovalov ret = kasan_populate_early_shadow(shadow_start, shadow_end); 483b938fcf4SAndrey Konovalov if (ret) 484b938fcf4SAndrey Konovalov kasan_remove_zero_shadow(shadow_start, 485b938fcf4SAndrey Konovalov size >> KASAN_SHADOW_SCALE_SHIFT); 486b938fcf4SAndrey Konovalov return ret; 487b938fcf4SAndrey Konovalov } 488