18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2017 Intel Corporation. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This code is based in part on work published here: 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * https://github.com/IAIK/KAISER 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * The original work was written by and and signed off by for the Linux 108c2ecf20Sopenharmony_ci * kernel by: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Signed-off-by: Richard Fellner <richard.fellner@student.tugraz.at> 138c2ecf20Sopenharmony_ci * Signed-off-by: Moritz Lipp <moritz.lipp@iaik.tugraz.at> 148c2ecf20Sopenharmony_ci * Signed-off-by: Daniel Gruss <daniel.gruss@iaik.tugraz.at> 158c2ecf20Sopenharmony_ci * Signed-off-by: Michael Schwarz <michael.schwarz@iaik.tugraz.at> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Major changes to the original code by: Dave Hansen <dave.hansen@intel.com> 188c2ecf20Sopenharmony_ci * Mostly rewritten by Thomas Gleixner <tglx@linutronix.de> and 198c2ecf20Sopenharmony_ci * Andy Lutomirsky <luto@amacapital.net> 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/string.h> 248c2ecf20Sopenharmony_ci#include <linux/types.h> 258c2ecf20Sopenharmony_ci#include <linux/bug.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 288c2ecf20Sopenharmony_ci#include <linux/mm.h> 298c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 308c2ecf20Sopenharmony_ci#include <linux/cpu.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <asm/cpufeature.h> 338c2ecf20Sopenharmony_ci#include <asm/hypervisor.h> 348c2ecf20Sopenharmony_ci#include <asm/vsyscall.h> 358c2ecf20Sopenharmony_ci#include <asm/cmdline.h> 368c2ecf20Sopenharmony_ci#include <asm/pti.h> 378c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 388c2ecf20Sopenharmony_ci#include <asm/desc.h> 398c2ecf20Sopenharmony_ci#include <asm/sections.h> 408c2ecf20Sopenharmony_ci#include <asm/set_memory.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#undef pr_fmt 438c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "Kernel/User page tables isolation: " fmt 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Backporting helper */ 468c2ecf20Sopenharmony_ci#ifndef __GFP_NOTRACK 478c2ecf20Sopenharmony_ci#define __GFP_NOTRACK 0 488c2ecf20Sopenharmony_ci#endif 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * Define the page-table levels we clone for user-space on 32 528c2ecf20Sopenharmony_ci * and 64 bit. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 558c2ecf20Sopenharmony_ci#define PTI_LEVEL_KERNEL_IMAGE PTI_CLONE_PMD 568c2ecf20Sopenharmony_ci#else 578c2ecf20Sopenharmony_ci#define PTI_LEVEL_KERNEL_IMAGE PTI_CLONE_PTE 588c2ecf20Sopenharmony_ci#endif 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void __init pti_print_if_insecure(const char *reason) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci if (boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) 638c2ecf20Sopenharmony_ci pr_info("%s\n", reason); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic void __init pti_print_if_secure(const char *reason) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) 698c2ecf20Sopenharmony_ci pr_info("%s\n", reason); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic enum pti_mode { 738c2ecf20Sopenharmony_ci PTI_AUTO = 0, 748c2ecf20Sopenharmony_ci PTI_FORCE_OFF, 758c2ecf20Sopenharmony_ci PTI_FORCE_ON 768c2ecf20Sopenharmony_ci} pti_mode; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_civoid __init pti_check_boottime_disable(void) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci char arg[5]; 818c2ecf20Sopenharmony_ci int ret; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* Assume mode is auto unless overridden. */ 848c2ecf20Sopenharmony_ci pti_mode = PTI_AUTO; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (hypervisor_is_type(X86_HYPER_XEN_PV)) { 878c2ecf20Sopenharmony_ci pti_mode = PTI_FORCE_OFF; 888c2ecf20Sopenharmony_ci pti_print_if_insecure("disabled on XEN PV."); 898c2ecf20Sopenharmony_ci return; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci ret = cmdline_find_option(boot_command_line, "pti", arg, sizeof(arg)); 938c2ecf20Sopenharmony_ci if (ret > 0) { 948c2ecf20Sopenharmony_ci if (ret == 3 && !strncmp(arg, "off", 3)) { 958c2ecf20Sopenharmony_ci pti_mode = PTI_FORCE_OFF; 968c2ecf20Sopenharmony_ci pti_print_if_insecure("disabled on command line."); 978c2ecf20Sopenharmony_ci return; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci if (ret == 2 && !strncmp(arg, "on", 2)) { 1008c2ecf20Sopenharmony_ci pti_mode = PTI_FORCE_ON; 1018c2ecf20Sopenharmony_ci pti_print_if_secure("force enabled on command line."); 1028c2ecf20Sopenharmony_ci goto enable; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (ret == 4 && !strncmp(arg, "auto", 4)) { 1058c2ecf20Sopenharmony_ci pti_mode = PTI_AUTO; 1068c2ecf20Sopenharmony_ci goto autosel; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (cmdline_find_option_bool(boot_command_line, "nopti") || 1118c2ecf20Sopenharmony_ci cpu_mitigations_off()) { 1128c2ecf20Sopenharmony_ci pti_mode = PTI_FORCE_OFF; 1138c2ecf20Sopenharmony_ci pti_print_if_insecure("disabled on command line."); 1148c2ecf20Sopenharmony_ci return; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ciautosel: 1188c2ecf20Sopenharmony_ci if (!boot_cpu_has_bug(X86_BUG_CPU_MELTDOWN)) 1198c2ecf20Sopenharmony_ci return; 1208c2ecf20Sopenharmony_cienable: 1218c2ecf20Sopenharmony_ci setup_force_cpu_cap(X86_FEATURE_PTI); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cipgd_t __pti_set_user_pgtbl(pgd_t *pgdp, pgd_t pgd) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci /* 1278c2ecf20Sopenharmony_ci * Changes to the high (kernel) portion of the kernelmode page 1288c2ecf20Sopenharmony_ci * tables are not automatically propagated to the usermode tables. 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Users should keep in mind that, unlike the kernelmode tables, 1318c2ecf20Sopenharmony_ci * there is no vmalloc_fault equivalent for the usermode tables. 1328c2ecf20Sopenharmony_ci * Top-level entries added to init_mm's usermode pgd after boot 1338c2ecf20Sopenharmony_ci * will not be automatically propagated to other mms. 1348c2ecf20Sopenharmony_ci */ 1358c2ecf20Sopenharmony_ci if (!pgdp_maps_userspace(pgdp)) 1368c2ecf20Sopenharmony_ci return pgd; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * The user page tables get the full PGD, accessible from 1408c2ecf20Sopenharmony_ci * userspace: 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci kernel_to_user_pgdp(pgdp)->pgd = pgd.pgd; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* 1458c2ecf20Sopenharmony_ci * If this is normal user memory, make it NX in the kernel 1468c2ecf20Sopenharmony_ci * pagetables so that, if we somehow screw up and return to 1478c2ecf20Sopenharmony_ci * usermode with the kernel CR3 loaded, we'll get a page fault 1488c2ecf20Sopenharmony_ci * instead of allowing user code to execute with the wrong CR3. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * As exceptions, we don't set NX if: 1518c2ecf20Sopenharmony_ci * - _PAGE_USER is not set. This could be an executable 1528c2ecf20Sopenharmony_ci * EFI runtime mapping or something similar, and the kernel 1538c2ecf20Sopenharmony_ci * may execute from it 1548c2ecf20Sopenharmony_ci * - we don't have NX support 1558c2ecf20Sopenharmony_ci * - we're clearing the PGD (i.e. the new pgd is not present). 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_ci if ((pgd.pgd & (_PAGE_USER|_PAGE_PRESENT)) == (_PAGE_USER|_PAGE_PRESENT) && 1588c2ecf20Sopenharmony_ci (__supported_pte_mask & _PAGE_NX)) 1598c2ecf20Sopenharmony_ci pgd.pgd |= _PAGE_NX; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* return the copy of the PGD we want the kernel to use: */ 1628c2ecf20Sopenharmony_ci return pgd; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Walk the user copy of the page tables (optionally) trying to allocate 1678c2ecf20Sopenharmony_ci * page table pages on the way down. 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * Returns a pointer to a P4D on success, or NULL on failure. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_cistatic p4d_t *pti_user_pagetable_walk_p4d(unsigned long address) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci pgd_t *pgd = kernel_to_user_pgdp(pgd_offset_k(address)); 1748c2ecf20Sopenharmony_ci gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (address < PAGE_OFFSET) { 1778c2ecf20Sopenharmony_ci WARN_ONCE(1, "attempt to walk user address\n"); 1788c2ecf20Sopenharmony_ci return NULL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (pgd_none(*pgd)) { 1828c2ecf20Sopenharmony_ci unsigned long new_p4d_page = __get_free_page(gfp); 1838c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!new_p4d_page)) 1848c2ecf20Sopenharmony_ci return NULL; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci set_pgd(pgd, __pgd(_KERNPG_TABLE | __pa(new_p4d_page))); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci BUILD_BUG_ON(pgd_large(*pgd) != 0); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci return p4d_offset(pgd, address); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* 1948c2ecf20Sopenharmony_ci * Walk the user copy of the page tables (optionally) trying to allocate 1958c2ecf20Sopenharmony_ci * page table pages on the way down. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Returns a pointer to a PMD on success, or NULL on failure. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_cistatic pmd_t *pti_user_pagetable_walk_pmd(unsigned long address) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); 2028c2ecf20Sopenharmony_ci p4d_t *p4d; 2038c2ecf20Sopenharmony_ci pud_t *pud; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci p4d = pti_user_pagetable_walk_p4d(address); 2068c2ecf20Sopenharmony_ci if (!p4d) 2078c2ecf20Sopenharmony_ci return NULL; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci BUILD_BUG_ON(p4d_large(*p4d) != 0); 2108c2ecf20Sopenharmony_ci if (p4d_none(*p4d)) { 2118c2ecf20Sopenharmony_ci unsigned long new_pud_page = __get_free_page(gfp); 2128c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!new_pud_page)) 2138c2ecf20Sopenharmony_ci return NULL; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci set_p4d(p4d, __p4d(_KERNPG_TABLE | __pa(new_pud_page))); 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci pud = pud_offset(p4d, address); 2198c2ecf20Sopenharmony_ci /* The user page tables do not use large mappings: */ 2208c2ecf20Sopenharmony_ci if (pud_large(*pud)) { 2218c2ecf20Sopenharmony_ci WARN_ON(1); 2228c2ecf20Sopenharmony_ci return NULL; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci if (pud_none(*pud)) { 2258c2ecf20Sopenharmony_ci unsigned long new_pmd_page = __get_free_page(gfp); 2268c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!new_pmd_page)) 2278c2ecf20Sopenharmony_ci return NULL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci set_pud(pud, __pud(_KERNPG_TABLE | __pa(new_pmd_page))); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return pmd_offset(pud, address); 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* 2368c2ecf20Sopenharmony_ci * Walk the shadow copy of the page tables (optionally) trying to allocate 2378c2ecf20Sopenharmony_ci * page table pages on the way down. Does not support large pages. 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Note: this is only used when mapping *new* kernel data into the 2408c2ecf20Sopenharmony_ci * user/shadow page tables. It is never used for userspace data. 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Returns a pointer to a PTE on success, or NULL on failure. 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic pte_t *pti_user_pagetable_walk_pte(unsigned long address) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci gfp_t gfp = (GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO); 2478c2ecf20Sopenharmony_ci pmd_t *pmd; 2488c2ecf20Sopenharmony_ci pte_t *pte; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci pmd = pti_user_pagetable_walk_pmd(address); 2518c2ecf20Sopenharmony_ci if (!pmd) 2528c2ecf20Sopenharmony_ci return NULL; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* We can't do anything sensible if we hit a large mapping. */ 2558c2ecf20Sopenharmony_ci if (pmd_large(*pmd)) { 2568c2ecf20Sopenharmony_ci WARN_ON(1); 2578c2ecf20Sopenharmony_ci return NULL; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (pmd_none(*pmd)) { 2618c2ecf20Sopenharmony_ci unsigned long new_pte_page = __get_free_page(gfp); 2628c2ecf20Sopenharmony_ci if (!new_pte_page) 2638c2ecf20Sopenharmony_ci return NULL; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci set_pmd(pmd, __pmd(_KERNPG_TABLE | __pa(new_pte_page))); 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci pte = pte_offset_kernel(pmd, address); 2698c2ecf20Sopenharmony_ci if (pte_flags(*pte) & _PAGE_USER) { 2708c2ecf20Sopenharmony_ci WARN_ONCE(1, "attempt to walk to user pte\n"); 2718c2ecf20Sopenharmony_ci return NULL; 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci return pte; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_VSYSCALL_EMULATION 2778c2ecf20Sopenharmony_cistatic void __init pti_setup_vsyscall(void) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci pte_t *pte, *target_pte; 2808c2ecf20Sopenharmony_ci unsigned int level; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci pte = lookup_address(VSYSCALL_ADDR, &level); 2838c2ecf20Sopenharmony_ci if (!pte || WARN_ON(level != PG_LEVEL_4K) || pte_none(*pte)) 2848c2ecf20Sopenharmony_ci return; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci target_pte = pti_user_pagetable_walk_pte(VSYSCALL_ADDR); 2878c2ecf20Sopenharmony_ci if (WARN_ON(!target_pte)) 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci *target_pte = *pte; 2918c2ecf20Sopenharmony_ci set_vsyscall_pgtable_user_bits(kernel_to_user_pgdp(swapper_pg_dir)); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci#else 2948c2ecf20Sopenharmony_cistatic void __init pti_setup_vsyscall(void) { } 2958c2ecf20Sopenharmony_ci#endif 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cienum pti_clone_level { 2988c2ecf20Sopenharmony_ci PTI_CLONE_PMD, 2998c2ecf20Sopenharmony_ci PTI_CLONE_PTE, 3008c2ecf20Sopenharmony_ci}; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void 3038c2ecf20Sopenharmony_cipti_clone_pgtable(unsigned long start, unsigned long end, 3048c2ecf20Sopenharmony_ci enum pti_clone_level level) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci unsigned long addr; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* 3098c2ecf20Sopenharmony_ci * Clone the populated PMDs which cover start to end. These PMD areas 3108c2ecf20Sopenharmony_ci * can have holes. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_ci for (addr = start; addr < end;) { 3138c2ecf20Sopenharmony_ci pte_t *pte, *target_pte; 3148c2ecf20Sopenharmony_ci pmd_t *pmd, *target_pmd; 3158c2ecf20Sopenharmony_ci pgd_t *pgd; 3168c2ecf20Sopenharmony_ci p4d_t *p4d; 3178c2ecf20Sopenharmony_ci pud_t *pud; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Overflow check */ 3208c2ecf20Sopenharmony_ci if (addr < start) 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci pgd = pgd_offset_k(addr); 3248c2ecf20Sopenharmony_ci if (WARN_ON(pgd_none(*pgd))) 3258c2ecf20Sopenharmony_ci return; 3268c2ecf20Sopenharmony_ci p4d = p4d_offset(pgd, addr); 3278c2ecf20Sopenharmony_ci if (WARN_ON(p4d_none(*p4d))) 3288c2ecf20Sopenharmony_ci return; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci pud = pud_offset(p4d, addr); 3318c2ecf20Sopenharmony_ci if (pud_none(*pud)) { 3328c2ecf20Sopenharmony_ci WARN_ON_ONCE(addr & ~PUD_MASK); 3338c2ecf20Sopenharmony_ci addr = round_up(addr + 1, PUD_SIZE); 3348c2ecf20Sopenharmony_ci continue; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci pmd = pmd_offset(pud, addr); 3388c2ecf20Sopenharmony_ci if (pmd_none(*pmd)) { 3398c2ecf20Sopenharmony_ci WARN_ON_ONCE(addr & ~PMD_MASK); 3408c2ecf20Sopenharmony_ci addr = round_up(addr + 1, PMD_SIZE); 3418c2ecf20Sopenharmony_ci continue; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (pmd_large(*pmd) || level == PTI_CLONE_PMD) { 3458c2ecf20Sopenharmony_ci target_pmd = pti_user_pagetable_walk_pmd(addr); 3468c2ecf20Sopenharmony_ci if (WARN_ON(!target_pmd)) 3478c2ecf20Sopenharmony_ci return; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * Only clone present PMDs. This ensures only setting 3518c2ecf20Sopenharmony_ci * _PAGE_GLOBAL on present PMDs. This should only be 3528c2ecf20Sopenharmony_ci * called on well-known addresses anyway, so a non- 3538c2ecf20Sopenharmony_ci * present PMD would be a surprise. 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_ci if (WARN_ON(!(pmd_flags(*pmd) & _PAGE_PRESENT))) 3568c2ecf20Sopenharmony_ci return; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * Setting 'target_pmd' below creates a mapping in both 3608c2ecf20Sopenharmony_ci * the user and kernel page tables. It is effectively 3618c2ecf20Sopenharmony_ci * global, so set it as global in both copies. Note: 3628c2ecf20Sopenharmony_ci * the X86_FEATURE_PGE check is not _required_ because 3638c2ecf20Sopenharmony_ci * the CPU ignores _PAGE_GLOBAL when PGE is not 3648c2ecf20Sopenharmony_ci * supported. The check keeps consistentency with 3658c2ecf20Sopenharmony_ci * code that only set this bit when supported. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_PGE)) 3688c2ecf20Sopenharmony_ci *pmd = pmd_set_flags(*pmd, _PAGE_GLOBAL); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* 3718c2ecf20Sopenharmony_ci * Copy the PMD. That is, the kernelmode and usermode 3728c2ecf20Sopenharmony_ci * tables will share the last-level page tables of this 3738c2ecf20Sopenharmony_ci * address range 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_ci *target_pmd = *pmd; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci addr = round_up(addr + 1, PMD_SIZE); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci } else if (level == PTI_CLONE_PTE) { 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Walk the page-table down to the pte level */ 3828c2ecf20Sopenharmony_ci pte = pte_offset_kernel(pmd, addr); 3838c2ecf20Sopenharmony_ci if (pte_none(*pte)) { 3848c2ecf20Sopenharmony_ci addr = round_up(addr + 1, PAGE_SIZE); 3858c2ecf20Sopenharmony_ci continue; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* Only clone present PTEs */ 3898c2ecf20Sopenharmony_ci if (WARN_ON(!(pte_flags(*pte) & _PAGE_PRESENT))) 3908c2ecf20Sopenharmony_ci return; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* Allocate PTE in the user page-table */ 3938c2ecf20Sopenharmony_ci target_pte = pti_user_pagetable_walk_pte(addr); 3948c2ecf20Sopenharmony_ci if (WARN_ON(!target_pte)) 3958c2ecf20Sopenharmony_ci return; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Set GLOBAL bit in both PTEs */ 3988c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_PGE)) 3998c2ecf20Sopenharmony_ci *pte = pte_set_flags(*pte, _PAGE_GLOBAL); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Clone the PTE */ 4028c2ecf20Sopenharmony_ci *target_pte = *pte; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci addr = round_up(addr + 1, PAGE_SIZE); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci } else { 4078c2ecf20Sopenharmony_ci BUG(); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 4138c2ecf20Sopenharmony_ci/* 4148c2ecf20Sopenharmony_ci * Clone a single p4d (i.e. a top-level entry on 4-level systems and a 4158c2ecf20Sopenharmony_ci * next-level entry on 5-level systems. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_cistatic void __init pti_clone_p4d(unsigned long addr) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci p4d_t *kernel_p4d, *user_p4d; 4208c2ecf20Sopenharmony_ci pgd_t *kernel_pgd; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci user_p4d = pti_user_pagetable_walk_p4d(addr); 4238c2ecf20Sopenharmony_ci if (!user_p4d) 4248c2ecf20Sopenharmony_ci return; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci kernel_pgd = pgd_offset_k(addr); 4278c2ecf20Sopenharmony_ci kernel_p4d = p4d_offset(kernel_pgd, addr); 4288c2ecf20Sopenharmony_ci *user_p4d = *kernel_p4d; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* 4328c2ecf20Sopenharmony_ci * Clone the CPU_ENTRY_AREA and associated data into the user space visible 4338c2ecf20Sopenharmony_ci * page table. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_cistatic void __init pti_clone_user_shared(void) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci unsigned int cpu; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci pti_clone_p4d(CPU_ENTRY_AREA_BASE); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 4428c2ecf20Sopenharmony_ci /* 4438c2ecf20Sopenharmony_ci * The SYSCALL64 entry code needs to be able to find the 4448c2ecf20Sopenharmony_ci * thread stack and needs one word of scratch space in which 4458c2ecf20Sopenharmony_ci * to spill a register. All of this lives in the TSS, in 4468c2ecf20Sopenharmony_ci * the sp1 and sp2 slots. 4478c2ecf20Sopenharmony_ci * 4488c2ecf20Sopenharmony_ci * This is done for all possible CPUs during boot to ensure 4498c2ecf20Sopenharmony_ci * that it's propagated to all mms. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci unsigned long va = (unsigned long)&per_cpu(cpu_tss_rw, cpu); 4538c2ecf20Sopenharmony_ci phys_addr_t pa = per_cpu_ptr_to_phys((void *)va); 4548c2ecf20Sopenharmony_ci pte_t *target_pte; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci target_pte = pti_user_pagetable_walk_pte(va); 4578c2ecf20Sopenharmony_ci if (WARN_ON(!target_pte)) 4588c2ecf20Sopenharmony_ci return; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci *target_pte = pfn_pte(pa >> PAGE_SHIFT, PAGE_KERNEL); 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci#else /* CONFIG_X86_64 */ 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/* 4678c2ecf20Sopenharmony_ci * On 32 bit PAE systems with 1GB of Kernel address space there is only 4688c2ecf20Sopenharmony_ci * one pgd/p4d for the whole kernel. Cloning that would map the whole 4698c2ecf20Sopenharmony_ci * address space into the user page-tables, making PTI useless. So clone 4708c2ecf20Sopenharmony_ci * the page-table on the PMD level to prevent that. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_cistatic void __init pti_clone_user_shared(void) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci unsigned long start, end; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci start = CPU_ENTRY_AREA_BASE; 4778c2ecf20Sopenharmony_ci end = start + (PAGE_SIZE * CPU_ENTRY_AREA_PAGES); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci pti_clone_pgtable(start, end, PTI_CLONE_PMD); 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_64 */ 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/* 4848c2ecf20Sopenharmony_ci * Clone the ESPFIX P4D into the user space visible page table 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_cistatic void __init pti_setup_espfix64(void) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_ESPFIX64 4898c2ecf20Sopenharmony_ci pti_clone_p4d(ESPFIX_BASE_ADDR); 4908c2ecf20Sopenharmony_ci#endif 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci/* 4948c2ecf20Sopenharmony_ci * Clone the populated PMDs of the entry text and force it RO. 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_cistatic void pti_clone_entry_text(void) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci pti_clone_pgtable((unsigned long) __entry_text_start, 4998c2ecf20Sopenharmony_ci (unsigned long) __entry_text_end, 5008c2ecf20Sopenharmony_ci PTI_CLONE_PMD); 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/* 5048c2ecf20Sopenharmony_ci * Global pages and PCIDs are both ways to make kernel TLB entries 5058c2ecf20Sopenharmony_ci * live longer, reduce TLB misses and improve kernel performance. 5068c2ecf20Sopenharmony_ci * But, leaving all kernel text Global makes it potentially accessible 5078c2ecf20Sopenharmony_ci * to Meltdown-style attacks which make it trivial to find gadgets or 5088c2ecf20Sopenharmony_ci * defeat KASLR. 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * Only use global pages when it is really worth it. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic inline bool pti_kernel_image_global_ok(void) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci /* 5158c2ecf20Sopenharmony_ci * Systems with PCIDs get litlle benefit from global 5168c2ecf20Sopenharmony_ci * kernel text and are not worth the downsides. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci if (cpu_feature_enabled(X86_FEATURE_PCID)) 5198c2ecf20Sopenharmony_ci return false; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * Only do global kernel image for pti=auto. Do the most 5238c2ecf20Sopenharmony_ci * secure thing (not global) if pti=on specified. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci if (pti_mode != PTI_AUTO) 5268c2ecf20Sopenharmony_ci return false; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * K8 may not tolerate the cleared _PAGE_RW on the userspace 5308c2ecf20Sopenharmony_ci * global kernel image pages. Do the safe thing (disable 5318c2ecf20Sopenharmony_ci * global kernel image). This is unlikely to ever be 5328c2ecf20Sopenharmony_ci * noticed because PTI is disabled by default on AMD CPUs. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci if (boot_cpu_has(X86_FEATURE_K8)) 5358c2ecf20Sopenharmony_ci return false; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci /* 5388c2ecf20Sopenharmony_ci * RANDSTRUCT derives its hardening benefits from the 5398c2ecf20Sopenharmony_ci * attacker's lack of knowledge about the layout of kernel 5408c2ecf20Sopenharmony_ci * data structures. Keep the kernel image non-global in 5418c2ecf20Sopenharmony_ci * cases where RANDSTRUCT is in use to help keep the layout a 5428c2ecf20Sopenharmony_ci * secret. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_GCC_PLUGIN_RANDSTRUCT)) 5458c2ecf20Sopenharmony_ci return false; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return true; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci/* 5518c2ecf20Sopenharmony_ci * For some configurations, map all of kernel text into the user page 5528c2ecf20Sopenharmony_ci * tables. This reduces TLB misses, especially on non-PCID systems. 5538c2ecf20Sopenharmony_ci */ 5548c2ecf20Sopenharmony_cistatic void pti_clone_kernel_text(void) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci /* 5578c2ecf20Sopenharmony_ci * rodata is part of the kernel image and is normally 5588c2ecf20Sopenharmony_ci * readable on the filesystem or on the web. But, do not 5598c2ecf20Sopenharmony_ci * clone the areas past rodata, they might contain secrets. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_ci unsigned long start = PFN_ALIGN(_text); 5628c2ecf20Sopenharmony_ci unsigned long end_clone = (unsigned long)__end_rodata_aligned; 5638c2ecf20Sopenharmony_ci unsigned long end_global = PFN_ALIGN((unsigned long)_etext); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (!pti_kernel_image_global_ok()) 5668c2ecf20Sopenharmony_ci return; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci pr_debug("mapping partial kernel image into user address space\n"); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * Note that this will undo _some_ of the work that 5728c2ecf20Sopenharmony_ci * pti_set_kernel_image_nonglobal() did to clear the 5738c2ecf20Sopenharmony_ci * global bit. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci pti_clone_pgtable(start, end_clone, PTI_LEVEL_KERNEL_IMAGE); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* 5788c2ecf20Sopenharmony_ci * pti_clone_pgtable() will set the global bit in any PMDs 5798c2ecf20Sopenharmony_ci * that it clones, but we also need to get any PTEs in 5808c2ecf20Sopenharmony_ci * the last level for areas that are not huge-page-aligned. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Set the global bit for normal non-__init kernel text: */ 5848c2ecf20Sopenharmony_ci set_memory_global(start, (end_global - start) >> PAGE_SHIFT); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_cistatic void pti_set_kernel_image_nonglobal(void) 5888c2ecf20Sopenharmony_ci{ 5898c2ecf20Sopenharmony_ci /* 5908c2ecf20Sopenharmony_ci * The identity map is created with PMDs, regardless of the 5918c2ecf20Sopenharmony_ci * actual length of the kernel. We need to clear 5928c2ecf20Sopenharmony_ci * _PAGE_GLOBAL up to a PMD boundary, not just to the end 5938c2ecf20Sopenharmony_ci * of the image. 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci unsigned long start = PFN_ALIGN(_text); 5968c2ecf20Sopenharmony_ci unsigned long end = ALIGN((unsigned long)_end, PMD_PAGE_SIZE); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* 5998c2ecf20Sopenharmony_ci * This clears _PAGE_GLOBAL from the entire kernel image. 6008c2ecf20Sopenharmony_ci * pti_clone_kernel_text() map put _PAGE_GLOBAL back for 6018c2ecf20Sopenharmony_ci * areas that are mapped to userspace. 6028c2ecf20Sopenharmony_ci */ 6038c2ecf20Sopenharmony_ci set_memory_nonglobal(start, (end - start) >> PAGE_SHIFT); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci/* 6078c2ecf20Sopenharmony_ci * Initialize kernel page table isolation 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_civoid __init pti_init(void) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_PTI)) 6128c2ecf20Sopenharmony_ci return; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci pr_info("enabled\n"); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 6178c2ecf20Sopenharmony_ci /* 6188c2ecf20Sopenharmony_ci * We check for X86_FEATURE_PCID here. But the init-code will 6198c2ecf20Sopenharmony_ci * clear the feature flag on 32 bit because the feature is not 6208c2ecf20Sopenharmony_ci * supported on 32 bit anyway. To print the warning we need to 6218c2ecf20Sopenharmony_ci * check with cpuid directly again. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci if (cpuid_ecx(0x1) & BIT(17)) { 6248c2ecf20Sopenharmony_ci /* Use printk to work around pr_fmt() */ 6258c2ecf20Sopenharmony_ci printk(KERN_WARNING "\n"); 6268c2ecf20Sopenharmony_ci printk(KERN_WARNING "************************************************************\n"); 6278c2ecf20Sopenharmony_ci printk(KERN_WARNING "** WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! **\n"); 6288c2ecf20Sopenharmony_ci printk(KERN_WARNING "** **\n"); 6298c2ecf20Sopenharmony_ci printk(KERN_WARNING "** You are using 32-bit PTI on a 64-bit PCID-capable CPU. **\n"); 6308c2ecf20Sopenharmony_ci printk(KERN_WARNING "** Your performance will increase dramatically if you **\n"); 6318c2ecf20Sopenharmony_ci printk(KERN_WARNING "** switch to a 64-bit kernel! **\n"); 6328c2ecf20Sopenharmony_ci printk(KERN_WARNING "** **\n"); 6338c2ecf20Sopenharmony_ci printk(KERN_WARNING "** WARNING! WARNING! WARNING! WARNING! WARNING! WARNING! **\n"); 6348c2ecf20Sopenharmony_ci printk(KERN_WARNING "************************************************************\n"); 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci#endif 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci pti_clone_user_shared(); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci /* Undo all global bits from the init pagetables in head_64.S: */ 6418c2ecf20Sopenharmony_ci pti_set_kernel_image_nonglobal(); 6428c2ecf20Sopenharmony_ci /* Replace some of the global bits just for shared entry text: */ 6438c2ecf20Sopenharmony_ci pti_clone_entry_text(); 6448c2ecf20Sopenharmony_ci pti_setup_espfix64(); 6458c2ecf20Sopenharmony_ci pti_setup_vsyscall(); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/* 6498c2ecf20Sopenharmony_ci * Finalize the kernel mappings in the userspace page-table. Some of the 6508c2ecf20Sopenharmony_ci * mappings for the kernel image might have changed since pti_init() 6518c2ecf20Sopenharmony_ci * cloned them. This is because parts of the kernel image have been 6528c2ecf20Sopenharmony_ci * mapped RO and/or NX. These changes need to be cloned again to the 6538c2ecf20Sopenharmony_ci * userspace page-table. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_civoid pti_finalize(void) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_PTI)) 6588c2ecf20Sopenharmony_ci return; 6598c2ecf20Sopenharmony_ci /* 6608c2ecf20Sopenharmony_ci * We need to clone everything (again) that maps parts of the 6618c2ecf20Sopenharmony_ci * kernel image. 6628c2ecf20Sopenharmony_ci */ 6638c2ecf20Sopenharmony_ci pti_clone_entry_text(); 6648c2ecf20Sopenharmony_ci pti_clone_kernel_text(); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci debug_checkwx_user(); 6678c2ecf20Sopenharmony_ci} 668