1*e886bf9dSAndrey Konovalov // SPDX-License-Identifier: GPL-2.0 2b938fcf4SAndrey Konovalov /* 3b938fcf4SAndrey Konovalov * This file contains some kasan 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 * This program is free software; you can redistribute it and/or modify 9b938fcf4SAndrey Konovalov * it under the terms of the GNU General Public License version 2 as 10b938fcf4SAndrey Konovalov * published by the Free Software Foundation. 11b938fcf4SAndrey Konovalov * 12b938fcf4SAndrey Konovalov */ 13b938fcf4SAndrey Konovalov 14b938fcf4SAndrey Konovalov #include <linux/memblock.h> 15b938fcf4SAndrey Konovalov #include <linux/init.h> 16b938fcf4SAndrey Konovalov #include <linux/kasan.h> 17b938fcf4SAndrey Konovalov #include <linux/kernel.h> 18b938fcf4SAndrey Konovalov #include <linux/mm.h> 19b938fcf4SAndrey Konovalov #include <linux/pfn.h> 20b938fcf4SAndrey Konovalov #include <linux/slab.h> 21b938fcf4SAndrey Konovalov 22b938fcf4SAndrey Konovalov #include <asm/page.h> 23b938fcf4SAndrey Konovalov #include <asm/pgalloc.h> 24b938fcf4SAndrey Konovalov 25b938fcf4SAndrey Konovalov #include "kasan.h" 26b938fcf4SAndrey Konovalov 27b938fcf4SAndrey Konovalov /* 28b938fcf4SAndrey Konovalov * This page serves two purposes: 29b938fcf4SAndrey Konovalov * - It used as early shadow memory. The entire shadow region populated 30b938fcf4SAndrey Konovalov * with this page, before we will be able to setup normal shadow memory. 31b938fcf4SAndrey Konovalov * - Latter it reused it as zero shadow to cover large ranges of memory 32b938fcf4SAndrey Konovalov * that allowed to access, but not handled by kasan (vmalloc/vmemmap ...). 33b938fcf4SAndrey Konovalov */ 349577dd74SAndrey Konovalov unsigned char kasan_early_shadow_page[PAGE_SIZE] __page_aligned_bss; 35b938fcf4SAndrey Konovalov 36b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 4 379577dd74SAndrey Konovalov p4d_t kasan_early_shadow_p4d[MAX_PTRS_PER_P4D] __page_aligned_bss; 38b938fcf4SAndrey Konovalov static inline bool kasan_p4d_table(pgd_t pgd) 39b938fcf4SAndrey Konovalov { 409577dd74SAndrey Konovalov return pgd_page(pgd) == virt_to_page(lm_alias(kasan_early_shadow_p4d)); 41b938fcf4SAndrey Konovalov } 42b938fcf4SAndrey Konovalov #else 43b938fcf4SAndrey Konovalov static inline bool kasan_p4d_table(pgd_t pgd) 44b938fcf4SAndrey Konovalov { 45b938fcf4SAndrey Konovalov return 0; 46b938fcf4SAndrey Konovalov } 47b938fcf4SAndrey Konovalov #endif 48b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 3 499577dd74SAndrey Konovalov pud_t kasan_early_shadow_pud[PTRS_PER_PUD] __page_aligned_bss; 50b938fcf4SAndrey Konovalov static inline bool kasan_pud_table(p4d_t p4d) 51b938fcf4SAndrey Konovalov { 529577dd74SAndrey Konovalov return p4d_page(p4d) == virt_to_page(lm_alias(kasan_early_shadow_pud)); 53b938fcf4SAndrey Konovalov } 54b938fcf4SAndrey Konovalov #else 55b938fcf4SAndrey Konovalov static inline bool kasan_pud_table(p4d_t p4d) 56b938fcf4SAndrey Konovalov { 57b938fcf4SAndrey Konovalov return 0; 58b938fcf4SAndrey Konovalov } 59b938fcf4SAndrey Konovalov #endif 60b938fcf4SAndrey Konovalov #if CONFIG_PGTABLE_LEVELS > 2 619577dd74SAndrey Konovalov pmd_t kasan_early_shadow_pmd[PTRS_PER_PMD] __page_aligned_bss; 62b938fcf4SAndrey Konovalov static inline bool kasan_pmd_table(pud_t pud) 63b938fcf4SAndrey Konovalov { 649577dd74SAndrey Konovalov return pud_page(pud) == virt_to_page(lm_alias(kasan_early_shadow_pmd)); 65b938fcf4SAndrey Konovalov } 66b938fcf4SAndrey Konovalov #else 67b938fcf4SAndrey Konovalov static inline bool kasan_pmd_table(pud_t pud) 68b938fcf4SAndrey Konovalov { 69b938fcf4SAndrey Konovalov return 0; 70b938fcf4SAndrey Konovalov } 71b938fcf4SAndrey Konovalov #endif 729577dd74SAndrey Konovalov pte_t kasan_early_shadow_pte[PTRS_PER_PTE] __page_aligned_bss; 73b938fcf4SAndrey Konovalov 74b938fcf4SAndrey Konovalov static inline bool kasan_pte_table(pmd_t pmd) 75b938fcf4SAndrey Konovalov { 769577dd74SAndrey Konovalov return pmd_page(pmd) == virt_to_page(lm_alias(kasan_early_shadow_pte)); 77b938fcf4SAndrey Konovalov } 78b938fcf4SAndrey Konovalov 799577dd74SAndrey Konovalov static inline bool kasan_early_shadow_page_entry(pte_t pte) 80b938fcf4SAndrey Konovalov { 819577dd74SAndrey Konovalov return pte_page(pte) == virt_to_page(lm_alias(kasan_early_shadow_page)); 82b938fcf4SAndrey Konovalov } 83b938fcf4SAndrey Konovalov 84b938fcf4SAndrey Konovalov static __init void *early_alloc(size_t size, int node) 85b938fcf4SAndrey Konovalov { 86b938fcf4SAndrey Konovalov return memblock_alloc_try_nid(size, size, __pa(MAX_DMA_ADDRESS), 87b938fcf4SAndrey Konovalov MEMBLOCK_ALLOC_ACCESSIBLE, node); 88b938fcf4SAndrey Konovalov } 89b938fcf4SAndrey Konovalov 90b938fcf4SAndrey Konovalov static void __ref zero_pte_populate(pmd_t *pmd, unsigned long addr, 91b938fcf4SAndrey Konovalov unsigned long end) 92b938fcf4SAndrey Konovalov { 93b938fcf4SAndrey Konovalov pte_t *pte = pte_offset_kernel(pmd, addr); 94b938fcf4SAndrey Konovalov pte_t zero_pte; 95b938fcf4SAndrey Konovalov 969577dd74SAndrey Konovalov zero_pte = pfn_pte(PFN_DOWN(__pa_symbol(kasan_early_shadow_page)), 979577dd74SAndrey Konovalov PAGE_KERNEL); 98b938fcf4SAndrey Konovalov zero_pte = pte_wrprotect(zero_pte); 99b938fcf4SAndrey Konovalov 100b938fcf4SAndrey Konovalov while (addr + PAGE_SIZE <= end) { 101b938fcf4SAndrey Konovalov set_pte_at(&init_mm, addr, pte, zero_pte); 102b938fcf4SAndrey Konovalov addr += PAGE_SIZE; 103b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 104b938fcf4SAndrey Konovalov } 105b938fcf4SAndrey Konovalov } 106b938fcf4SAndrey Konovalov 107b938fcf4SAndrey Konovalov static int __ref zero_pmd_populate(pud_t *pud, unsigned long addr, 108b938fcf4SAndrey Konovalov unsigned long end) 109b938fcf4SAndrey Konovalov { 110b938fcf4SAndrey Konovalov pmd_t *pmd = pmd_offset(pud, addr); 111b938fcf4SAndrey Konovalov unsigned long next; 112b938fcf4SAndrey Konovalov 113b938fcf4SAndrey Konovalov do { 114b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 115b938fcf4SAndrey Konovalov 116b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && end - addr >= PMD_SIZE) { 1179577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1189577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 119b938fcf4SAndrey Konovalov continue; 120b938fcf4SAndrey Konovalov } 121b938fcf4SAndrey Konovalov 122b938fcf4SAndrey Konovalov if (pmd_none(*pmd)) { 123b938fcf4SAndrey Konovalov pte_t *p; 124b938fcf4SAndrey Konovalov 125b938fcf4SAndrey Konovalov if (slab_is_available()) 126b938fcf4SAndrey Konovalov p = pte_alloc_one_kernel(&init_mm, addr); 127b938fcf4SAndrey Konovalov else 128b938fcf4SAndrey Konovalov p = early_alloc(PAGE_SIZE, NUMA_NO_NODE); 129b938fcf4SAndrey Konovalov if (!p) 130b938fcf4SAndrey Konovalov return -ENOMEM; 131b938fcf4SAndrey Konovalov 132b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, p); 133b938fcf4SAndrey Konovalov } 134b938fcf4SAndrey Konovalov zero_pte_populate(pmd, addr, next); 135b938fcf4SAndrey Konovalov } while (pmd++, addr = next, addr != end); 136b938fcf4SAndrey Konovalov 137b938fcf4SAndrey Konovalov return 0; 138b938fcf4SAndrey Konovalov } 139b938fcf4SAndrey Konovalov 140b938fcf4SAndrey Konovalov static int __ref zero_pud_populate(p4d_t *p4d, unsigned long addr, 141b938fcf4SAndrey Konovalov unsigned long end) 142b938fcf4SAndrey Konovalov { 143b938fcf4SAndrey Konovalov pud_t *pud = pud_offset(p4d, addr); 144b938fcf4SAndrey Konovalov unsigned long next; 145b938fcf4SAndrey Konovalov 146b938fcf4SAndrey Konovalov do { 147b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 148b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && end - addr >= PUD_SIZE) { 149b938fcf4SAndrey Konovalov pmd_t *pmd; 150b938fcf4SAndrey Konovalov 1519577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1529577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 153b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 1549577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1559577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 156b938fcf4SAndrey Konovalov continue; 157b938fcf4SAndrey Konovalov } 158b938fcf4SAndrey Konovalov 159b938fcf4SAndrey Konovalov if (pud_none(*pud)) { 160b938fcf4SAndrey Konovalov pmd_t *p; 161b938fcf4SAndrey Konovalov 162b938fcf4SAndrey Konovalov if (slab_is_available()) { 163b938fcf4SAndrey Konovalov p = pmd_alloc(&init_mm, pud, addr); 164b938fcf4SAndrey Konovalov if (!p) 165b938fcf4SAndrey Konovalov return -ENOMEM; 166b938fcf4SAndrey Konovalov } else { 167b938fcf4SAndrey Konovalov pud_populate(&init_mm, pud, 168b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 169b938fcf4SAndrey Konovalov } 170b938fcf4SAndrey Konovalov } 171b938fcf4SAndrey Konovalov zero_pmd_populate(pud, addr, next); 172b938fcf4SAndrey Konovalov } while (pud++, addr = next, addr != end); 173b938fcf4SAndrey Konovalov 174b938fcf4SAndrey Konovalov return 0; 175b938fcf4SAndrey Konovalov } 176b938fcf4SAndrey Konovalov 177b938fcf4SAndrey Konovalov static int __ref zero_p4d_populate(pgd_t *pgd, unsigned long addr, 178b938fcf4SAndrey Konovalov unsigned long end) 179b938fcf4SAndrey Konovalov { 180b938fcf4SAndrey Konovalov p4d_t *p4d = p4d_offset(pgd, addr); 181b938fcf4SAndrey Konovalov unsigned long next; 182b938fcf4SAndrey Konovalov 183b938fcf4SAndrey Konovalov do { 184b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 185b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && end - addr >= P4D_SIZE) { 186b938fcf4SAndrey Konovalov pud_t *pud; 187b938fcf4SAndrey Konovalov pmd_t *pmd; 188b938fcf4SAndrey Konovalov 1899577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 1909577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 191b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 1929577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 1939577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 194b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 195b938fcf4SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 1969577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 197b938fcf4SAndrey Konovalov continue; 198b938fcf4SAndrey Konovalov } 199b938fcf4SAndrey Konovalov 200b938fcf4SAndrey Konovalov if (p4d_none(*p4d)) { 201b938fcf4SAndrey Konovalov pud_t *p; 202b938fcf4SAndrey Konovalov 203b938fcf4SAndrey Konovalov if (slab_is_available()) { 204b938fcf4SAndrey Konovalov p = pud_alloc(&init_mm, p4d, addr); 205b938fcf4SAndrey Konovalov if (!p) 206b938fcf4SAndrey Konovalov return -ENOMEM; 207b938fcf4SAndrey Konovalov } else { 208b938fcf4SAndrey Konovalov p4d_populate(&init_mm, p4d, 209b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 210b938fcf4SAndrey Konovalov } 211b938fcf4SAndrey Konovalov } 212b938fcf4SAndrey Konovalov zero_pud_populate(p4d, addr, next); 213b938fcf4SAndrey Konovalov } while (p4d++, addr = next, addr != end); 214b938fcf4SAndrey Konovalov 215b938fcf4SAndrey Konovalov return 0; 216b938fcf4SAndrey Konovalov } 217b938fcf4SAndrey Konovalov 218b938fcf4SAndrey Konovalov /** 2199577dd74SAndrey Konovalov * kasan_populate_early_shadow - populate shadow memory region with 2209577dd74SAndrey Konovalov * kasan_early_shadow_page 221b938fcf4SAndrey Konovalov * @shadow_start - start of the memory range to populate 222b938fcf4SAndrey Konovalov * @shadow_end - end of the memory range to populate 223b938fcf4SAndrey Konovalov */ 2249577dd74SAndrey Konovalov int __ref kasan_populate_early_shadow(const void *shadow_start, 225b938fcf4SAndrey Konovalov const void *shadow_end) 226b938fcf4SAndrey Konovalov { 227b938fcf4SAndrey Konovalov unsigned long addr = (unsigned long)shadow_start; 228b938fcf4SAndrey Konovalov unsigned long end = (unsigned long)shadow_end; 229b938fcf4SAndrey Konovalov pgd_t *pgd = pgd_offset_k(addr); 230b938fcf4SAndrey Konovalov unsigned long next; 231b938fcf4SAndrey Konovalov 232b938fcf4SAndrey Konovalov do { 233b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 234b938fcf4SAndrey Konovalov 235b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && end - addr >= PGDIR_SIZE) { 236b938fcf4SAndrey Konovalov p4d_t *p4d; 237b938fcf4SAndrey Konovalov pud_t *pud; 238b938fcf4SAndrey Konovalov pmd_t *pmd; 239b938fcf4SAndrey Konovalov 240b938fcf4SAndrey Konovalov /* 2419577dd74SAndrey Konovalov * kasan_early_shadow_pud should be populated with pmds 242b938fcf4SAndrey Konovalov * at this moment. 243b938fcf4SAndrey Konovalov * [pud,pmd]_populate*() below needed only for 244b938fcf4SAndrey Konovalov * 3,2 - level page tables where we don't have 245b938fcf4SAndrey Konovalov * puds,pmds, so pgd_populate(), pud_populate() 246b938fcf4SAndrey Konovalov * is noops. 247b938fcf4SAndrey Konovalov * 248b938fcf4SAndrey Konovalov * The ifndef is required to avoid build breakage. 249b938fcf4SAndrey Konovalov * 250b938fcf4SAndrey Konovalov * With 5level-fixup.h, pgd_populate() is not nop and 2519577dd74SAndrey Konovalov * we reference kasan_early_shadow_p4d. It's not defined 252b938fcf4SAndrey Konovalov * unless 5-level paging enabled. 253b938fcf4SAndrey Konovalov * 254b938fcf4SAndrey Konovalov * The ifndef can be dropped once all KASAN-enabled 255b938fcf4SAndrey Konovalov * architectures will switch to pgtable-nop4d.h. 256b938fcf4SAndrey Konovalov */ 257b938fcf4SAndrey Konovalov #ifndef __ARCH_HAS_5LEVEL_HACK 2589577dd74SAndrey Konovalov pgd_populate(&init_mm, pgd, 2599577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_p4d)); 260b938fcf4SAndrey Konovalov #endif 261b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 2629577dd74SAndrey Konovalov p4d_populate(&init_mm, p4d, 2639577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pud)); 264b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 2659577dd74SAndrey Konovalov pud_populate(&init_mm, pud, 2669577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pmd)); 267b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 2689577dd74SAndrey Konovalov pmd_populate_kernel(&init_mm, pmd, 2699577dd74SAndrey Konovalov lm_alias(kasan_early_shadow_pte)); 270b938fcf4SAndrey Konovalov continue; 271b938fcf4SAndrey Konovalov } 272b938fcf4SAndrey Konovalov 273b938fcf4SAndrey Konovalov if (pgd_none(*pgd)) { 274b938fcf4SAndrey Konovalov p4d_t *p; 275b938fcf4SAndrey Konovalov 276b938fcf4SAndrey Konovalov if (slab_is_available()) { 277b938fcf4SAndrey Konovalov p = p4d_alloc(&init_mm, pgd, addr); 278b938fcf4SAndrey Konovalov if (!p) 279b938fcf4SAndrey Konovalov return -ENOMEM; 280b938fcf4SAndrey Konovalov } else { 281b938fcf4SAndrey Konovalov pgd_populate(&init_mm, pgd, 282b938fcf4SAndrey Konovalov early_alloc(PAGE_SIZE, NUMA_NO_NODE)); 283b938fcf4SAndrey Konovalov } 284b938fcf4SAndrey Konovalov } 285b938fcf4SAndrey Konovalov zero_p4d_populate(pgd, addr, next); 286b938fcf4SAndrey Konovalov } while (pgd++, addr = next, addr != end); 287b938fcf4SAndrey Konovalov 288b938fcf4SAndrey Konovalov return 0; 289b938fcf4SAndrey Konovalov } 290b938fcf4SAndrey Konovalov 291b938fcf4SAndrey Konovalov static void kasan_free_pte(pte_t *pte_start, pmd_t *pmd) 292b938fcf4SAndrey Konovalov { 293b938fcf4SAndrey Konovalov pte_t *pte; 294b938fcf4SAndrey Konovalov int i; 295b938fcf4SAndrey Konovalov 296b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PTE; i++) { 297b938fcf4SAndrey Konovalov pte = pte_start + i; 298b938fcf4SAndrey Konovalov if (!pte_none(*pte)) 299b938fcf4SAndrey Konovalov return; 300b938fcf4SAndrey Konovalov } 301b938fcf4SAndrey Konovalov 302b938fcf4SAndrey Konovalov pte_free_kernel(&init_mm, (pte_t *)page_to_virt(pmd_page(*pmd))); 303b938fcf4SAndrey Konovalov pmd_clear(pmd); 304b938fcf4SAndrey Konovalov } 305b938fcf4SAndrey Konovalov 306b938fcf4SAndrey Konovalov static void kasan_free_pmd(pmd_t *pmd_start, pud_t *pud) 307b938fcf4SAndrey Konovalov { 308b938fcf4SAndrey Konovalov pmd_t *pmd; 309b938fcf4SAndrey Konovalov int i; 310b938fcf4SAndrey Konovalov 311b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PMD; i++) { 312b938fcf4SAndrey Konovalov pmd = pmd_start + i; 313b938fcf4SAndrey Konovalov if (!pmd_none(*pmd)) 314b938fcf4SAndrey Konovalov return; 315b938fcf4SAndrey Konovalov } 316b938fcf4SAndrey Konovalov 317b938fcf4SAndrey Konovalov pmd_free(&init_mm, (pmd_t *)page_to_virt(pud_page(*pud))); 318b938fcf4SAndrey Konovalov pud_clear(pud); 319b938fcf4SAndrey Konovalov } 320b938fcf4SAndrey Konovalov 321b938fcf4SAndrey Konovalov static void kasan_free_pud(pud_t *pud_start, p4d_t *p4d) 322b938fcf4SAndrey Konovalov { 323b938fcf4SAndrey Konovalov pud_t *pud; 324b938fcf4SAndrey Konovalov int i; 325b938fcf4SAndrey Konovalov 326b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_PUD; i++) { 327b938fcf4SAndrey Konovalov pud = pud_start + i; 328b938fcf4SAndrey Konovalov if (!pud_none(*pud)) 329b938fcf4SAndrey Konovalov return; 330b938fcf4SAndrey Konovalov } 331b938fcf4SAndrey Konovalov 332b938fcf4SAndrey Konovalov pud_free(&init_mm, (pud_t *)page_to_virt(p4d_page(*p4d))); 333b938fcf4SAndrey Konovalov p4d_clear(p4d); 334b938fcf4SAndrey Konovalov } 335b938fcf4SAndrey Konovalov 336b938fcf4SAndrey Konovalov static void kasan_free_p4d(p4d_t *p4d_start, pgd_t *pgd) 337b938fcf4SAndrey Konovalov { 338b938fcf4SAndrey Konovalov p4d_t *p4d; 339b938fcf4SAndrey Konovalov int i; 340b938fcf4SAndrey Konovalov 341b938fcf4SAndrey Konovalov for (i = 0; i < PTRS_PER_P4D; i++) { 342b938fcf4SAndrey Konovalov p4d = p4d_start + i; 343b938fcf4SAndrey Konovalov if (!p4d_none(*p4d)) 344b938fcf4SAndrey Konovalov return; 345b938fcf4SAndrey Konovalov } 346b938fcf4SAndrey Konovalov 347b938fcf4SAndrey Konovalov p4d_free(&init_mm, (p4d_t *)page_to_virt(pgd_page(*pgd))); 348b938fcf4SAndrey Konovalov pgd_clear(pgd); 349b938fcf4SAndrey Konovalov } 350b938fcf4SAndrey Konovalov 351b938fcf4SAndrey Konovalov static void kasan_remove_pte_table(pte_t *pte, unsigned long addr, 352b938fcf4SAndrey Konovalov unsigned long end) 353b938fcf4SAndrey Konovalov { 354b938fcf4SAndrey Konovalov unsigned long next; 355b938fcf4SAndrey Konovalov 356b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pte++) { 357b938fcf4SAndrey Konovalov next = (addr + PAGE_SIZE) & PAGE_MASK; 358b938fcf4SAndrey Konovalov if (next > end) 359b938fcf4SAndrey Konovalov next = end; 360b938fcf4SAndrey Konovalov 361b938fcf4SAndrey Konovalov if (!pte_present(*pte)) 362b938fcf4SAndrey Konovalov continue; 363b938fcf4SAndrey Konovalov 3649577dd74SAndrey Konovalov if (WARN_ON(!kasan_early_shadow_page_entry(*pte))) 365b938fcf4SAndrey Konovalov continue; 366b938fcf4SAndrey Konovalov pte_clear(&init_mm, addr, pte); 367b938fcf4SAndrey Konovalov } 368b938fcf4SAndrey Konovalov } 369b938fcf4SAndrey Konovalov 370b938fcf4SAndrey Konovalov static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr, 371b938fcf4SAndrey Konovalov unsigned long end) 372b938fcf4SAndrey Konovalov { 373b938fcf4SAndrey Konovalov unsigned long next; 374b938fcf4SAndrey Konovalov 375b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pmd++) { 376b938fcf4SAndrey Konovalov pte_t *pte; 377b938fcf4SAndrey Konovalov 378b938fcf4SAndrey Konovalov next = pmd_addr_end(addr, end); 379b938fcf4SAndrey Konovalov 380b938fcf4SAndrey Konovalov if (!pmd_present(*pmd)) 381b938fcf4SAndrey Konovalov continue; 382b938fcf4SAndrey Konovalov 383b938fcf4SAndrey Konovalov if (kasan_pte_table(*pmd)) { 384b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PMD_SIZE) && 385b938fcf4SAndrey Konovalov IS_ALIGNED(next, PMD_SIZE)) 386b938fcf4SAndrey Konovalov pmd_clear(pmd); 387b938fcf4SAndrey Konovalov continue; 388b938fcf4SAndrey Konovalov } 389b938fcf4SAndrey Konovalov pte = pte_offset_kernel(pmd, addr); 390b938fcf4SAndrey Konovalov kasan_remove_pte_table(pte, addr, next); 391b938fcf4SAndrey Konovalov kasan_free_pte(pte_offset_kernel(pmd, 0), pmd); 392b938fcf4SAndrey Konovalov } 393b938fcf4SAndrey Konovalov } 394b938fcf4SAndrey Konovalov 395b938fcf4SAndrey Konovalov static void kasan_remove_pud_table(pud_t *pud, unsigned long addr, 396b938fcf4SAndrey Konovalov unsigned long end) 397b938fcf4SAndrey Konovalov { 398b938fcf4SAndrey Konovalov unsigned long next; 399b938fcf4SAndrey Konovalov 400b938fcf4SAndrey Konovalov for (; addr < end; addr = next, pud++) { 401b938fcf4SAndrey Konovalov pmd_t *pmd, *pmd_base; 402b938fcf4SAndrey Konovalov 403b938fcf4SAndrey Konovalov next = pud_addr_end(addr, end); 404b938fcf4SAndrey Konovalov 405b938fcf4SAndrey Konovalov if (!pud_present(*pud)) 406b938fcf4SAndrey Konovalov continue; 407b938fcf4SAndrey Konovalov 408b938fcf4SAndrey Konovalov if (kasan_pmd_table(*pud)) { 409b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PUD_SIZE) && 410b938fcf4SAndrey Konovalov IS_ALIGNED(next, PUD_SIZE)) 411b938fcf4SAndrey Konovalov pud_clear(pud); 412b938fcf4SAndrey Konovalov continue; 413b938fcf4SAndrey Konovalov } 414b938fcf4SAndrey Konovalov pmd = pmd_offset(pud, addr); 415b938fcf4SAndrey Konovalov pmd_base = pmd_offset(pud, 0); 416b938fcf4SAndrey Konovalov kasan_remove_pmd_table(pmd, addr, next); 417b938fcf4SAndrey Konovalov kasan_free_pmd(pmd_base, pud); 418b938fcf4SAndrey Konovalov } 419b938fcf4SAndrey Konovalov } 420b938fcf4SAndrey Konovalov 421b938fcf4SAndrey Konovalov static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr, 422b938fcf4SAndrey Konovalov unsigned long end) 423b938fcf4SAndrey Konovalov { 424b938fcf4SAndrey Konovalov unsigned long next; 425b938fcf4SAndrey Konovalov 426b938fcf4SAndrey Konovalov for (; addr < end; addr = next, p4d++) { 427b938fcf4SAndrey Konovalov pud_t *pud; 428b938fcf4SAndrey Konovalov 429b938fcf4SAndrey Konovalov next = p4d_addr_end(addr, end); 430b938fcf4SAndrey Konovalov 431b938fcf4SAndrey Konovalov if (!p4d_present(*p4d)) 432b938fcf4SAndrey Konovalov continue; 433b938fcf4SAndrey Konovalov 434b938fcf4SAndrey Konovalov if (kasan_pud_table(*p4d)) { 435b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, P4D_SIZE) && 436b938fcf4SAndrey Konovalov IS_ALIGNED(next, P4D_SIZE)) 437b938fcf4SAndrey Konovalov p4d_clear(p4d); 438b938fcf4SAndrey Konovalov continue; 439b938fcf4SAndrey Konovalov } 440b938fcf4SAndrey Konovalov pud = pud_offset(p4d, addr); 441b938fcf4SAndrey Konovalov kasan_remove_pud_table(pud, addr, next); 442b938fcf4SAndrey Konovalov kasan_free_pud(pud_offset(p4d, 0), p4d); 443b938fcf4SAndrey Konovalov } 444b938fcf4SAndrey Konovalov } 445b938fcf4SAndrey Konovalov 446b938fcf4SAndrey Konovalov void kasan_remove_zero_shadow(void *start, unsigned long size) 447b938fcf4SAndrey Konovalov { 448b938fcf4SAndrey Konovalov unsigned long addr, end, next; 449b938fcf4SAndrey Konovalov pgd_t *pgd; 450b938fcf4SAndrey Konovalov 451b938fcf4SAndrey Konovalov addr = (unsigned long)kasan_mem_to_shadow(start); 452b938fcf4SAndrey Konovalov end = addr + (size >> KASAN_SHADOW_SCALE_SHIFT); 453b938fcf4SAndrey Konovalov 454b938fcf4SAndrey Konovalov if (WARN_ON((unsigned long)start % 455b938fcf4SAndrey Konovalov (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE)) || 456b938fcf4SAndrey Konovalov WARN_ON(size % (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE))) 457b938fcf4SAndrey Konovalov return; 458b938fcf4SAndrey Konovalov 459b938fcf4SAndrey Konovalov for (; addr < end; addr = next) { 460b938fcf4SAndrey Konovalov p4d_t *p4d; 461b938fcf4SAndrey Konovalov 462b938fcf4SAndrey Konovalov next = pgd_addr_end(addr, end); 463b938fcf4SAndrey Konovalov 464b938fcf4SAndrey Konovalov pgd = pgd_offset_k(addr); 465b938fcf4SAndrey Konovalov if (!pgd_present(*pgd)) 466b938fcf4SAndrey Konovalov continue; 467b938fcf4SAndrey Konovalov 468b938fcf4SAndrey Konovalov if (kasan_p4d_table(*pgd)) { 469b938fcf4SAndrey Konovalov if (IS_ALIGNED(addr, PGDIR_SIZE) && 470b938fcf4SAndrey Konovalov IS_ALIGNED(next, PGDIR_SIZE)) 471b938fcf4SAndrey Konovalov pgd_clear(pgd); 472b938fcf4SAndrey Konovalov continue; 473b938fcf4SAndrey Konovalov } 474b938fcf4SAndrey Konovalov 475b938fcf4SAndrey Konovalov p4d = p4d_offset(pgd, addr); 476b938fcf4SAndrey Konovalov kasan_remove_p4d_table(p4d, addr, next); 477b938fcf4SAndrey Konovalov kasan_free_p4d(p4d_offset(pgd, 0), pgd); 478b938fcf4SAndrey Konovalov } 479b938fcf4SAndrey Konovalov } 480b938fcf4SAndrey Konovalov 481b938fcf4SAndrey Konovalov int kasan_add_zero_shadow(void *start, unsigned long size) 482b938fcf4SAndrey Konovalov { 483b938fcf4SAndrey Konovalov int ret; 484b938fcf4SAndrey Konovalov void *shadow_start, *shadow_end; 485b938fcf4SAndrey Konovalov 486b938fcf4SAndrey Konovalov shadow_start = kasan_mem_to_shadow(start); 487b938fcf4SAndrey Konovalov shadow_end = shadow_start + (size >> KASAN_SHADOW_SCALE_SHIFT); 488b938fcf4SAndrey Konovalov 489b938fcf4SAndrey Konovalov if (WARN_ON((unsigned long)start % 490b938fcf4SAndrey Konovalov (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE)) || 491b938fcf4SAndrey Konovalov WARN_ON(size % (KASAN_SHADOW_SCALE_SIZE * PAGE_SIZE))) 492b938fcf4SAndrey Konovalov return -EINVAL; 493b938fcf4SAndrey Konovalov 4949577dd74SAndrey Konovalov ret = kasan_populate_early_shadow(shadow_start, shadow_end); 495b938fcf4SAndrey Konovalov if (ret) 496b938fcf4SAndrey Konovalov kasan_remove_zero_shadow(shadow_start, 497b938fcf4SAndrey Konovalov size >> KASAN_SHADOW_SCALE_SHIFT); 498b938fcf4SAndrey Konovalov return ret; 499b938fcf4SAndrey Konovalov } 500