11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* Rewritten by Rusty Russell, on the backs of many others... 31da177e4SLinus Torvalds Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds */ 6*e1478d8eSChristophe Leroy #include <linux/elf.h> 78b96f011SFrederic Weisbecker #include <linux/ftrace.h> 8f80d2d77SDmitri Vorobiev #include <linux/memory.h> 98a293be0SPaul Gortmaker #include <linux/extable.h> 10505f2b97SIngo Molnar #include <linux/module.h> 11505f2b97SIngo Molnar #include <linux/mutex.h> 12505f2b97SIngo Molnar #include <linux/init.h> 135b485629SMasami Hiramatsu #include <linux/kprobes.h> 1474451e66SDaniel Borkmann #include <linux/filter.h> 15505f2b97SIngo Molnar 161da177e4SLinus Torvalds #include <asm/sections.h> 177c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 18505f2b97SIngo Molnar 19505f2b97SIngo Molnar /* 20505f2b97SIngo Molnar * mutex protecting text section modification (dynamic code patching). 21505f2b97SIngo Molnar * some users need to sleep (allocating memory...) while they hold this lock. 22505f2b97SIngo Molnar * 23e846d139SZhou Chengming * Note: Also protects SMP-alternatives modification on x86. 24e846d139SZhou Chengming * 25505f2b97SIngo Molnar * NOT exported to modules - patching kernel text is a really delicate matter. 26505f2b97SIngo Molnar */ 27505f2b97SIngo Molnar DEFINE_MUTEX(text_mutex); 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[]; 301da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[]; 311da177e4SLinus Torvalds 32d219e2e8SDavid Daney /* Cleared by build time tools if the table is already sorted. */ 3300b71030SAndi Kleen u32 __initdata __visible main_extable_sort_needed = 1; 34d219e2e8SDavid Daney 351da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */ 361da177e4SLinus Torvalds void __init sort_main_extable(void) 371da177e4SLinus Torvalds { 3863174f61SNathan Chancellor if (main_extable_sort_needed && 3963174f61SNathan Chancellor &__stop___ex_table > &__start___ex_table) { 40bec1b9e7SBorislav Petkov pr_notice("Sorting __ex_table...\n"); 411da177e4SLinus Torvalds sort_extable(__start___ex_table, __stop___ex_table); 42bec1b9e7SBorislav Petkov } 431da177e4SLinus Torvalds } 441da177e4SLinus Torvalds 4549ec9177SSantosh Sivaraj /* Given an address, look for it in the kernel exception table */ 4649ec9177SSantosh Sivaraj const 4749ec9177SSantosh Sivaraj struct exception_table_entry *search_kernel_exception_table(unsigned long addr) 4849ec9177SSantosh Sivaraj { 4949ec9177SSantosh Sivaraj return search_extable(__start___ex_table, 5049ec9177SSantosh Sivaraj __stop___ex_table - __start___ex_table, addr); 5149ec9177SSantosh Sivaraj } 5249ec9177SSantosh Sivaraj 531da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */ 541da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds const struct exception_table_entry *e; 571da177e4SLinus Torvalds 5849ec9177SSantosh Sivaraj e = search_kernel_exception_table(addr); 591da177e4SLinus Torvalds if (!e) 601da177e4SLinus Torvalds e = search_module_extables(addr); 613dec541bSAlexei Starovoitov if (!e) 623dec541bSAlexei Starovoitov e = search_bpf_extables(addr); 631da177e4SLinus Torvalds return e; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 66c0d80ddaSMarcin Nowakowski int notrace core_kernel_text(unsigned long addr) 671da177e4SLinus Torvalds { 68808b6456SKefeng Wang if (is_kernel_text(addr)) 691da177e4SLinus Torvalds return 1; 701da177e4SLinus Torvalds 71d2635f20SChristophe Leroy if (system_state < SYSTEM_FREEING_INITMEM && 72b9ad8fe7SKefeng Wang is_kernel_inittext(addr)) 731da177e4SLinus Torvalds return 1; 741da177e4SLinus Torvalds return 0; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 773861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr) 781da177e4SLinus Torvalds { 799aadde91SSteven Rostedt (VMware) if (kernel_text_address(addr)) 8074451e66SDaniel Borkmann return 1; 814a44bac1SIngo Molnar /* 824a44bac1SIngo Molnar * There might be init symbols in saved stacktraces. 834a44bac1SIngo Molnar * Give those symbols a chance to be printed in 844a44bac1SIngo Molnar * backtraces (such as lockdep traces). 854a44bac1SIngo Molnar * 864a44bac1SIngo Molnar * Since we are after the module-symbols check, there's 874a44bac1SIngo Molnar * no danger of address overlap: 884a44bac1SIngo Molnar */ 89b9ad8fe7SKefeng Wang if (is_kernel_inittext(addr)) 904a44bac1SIngo Molnar return 1; 914a44bac1SIngo Molnar return 0; 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds int kernel_text_address(unsigned long addr) 951da177e4SLinus Torvalds { 96e8cac8b1SSteven Rostedt (VMware) bool no_rcu; 97e8cac8b1SSteven Rostedt (VMware) int ret = 1; 98e8cac8b1SSteven Rostedt (VMware) 991da177e4SLinus Torvalds if (core_kernel_text(addr)) 1001da177e4SLinus Torvalds return 1; 101e8cac8b1SSteven Rostedt (VMware) 102e8cac8b1SSteven Rostedt (VMware) /* 103e8cac8b1SSteven Rostedt (VMware) * If a stack dump happens while RCU is not watching, then 104e8cac8b1SSteven Rostedt (VMware) * RCU needs to be notified that it requires to start 105e8cac8b1SSteven Rostedt (VMware) * watching again. This can happen either by tracing that 106e8cac8b1SSteven Rostedt (VMware) * triggers a stack trace, or a WARN() that happens during 107e8cac8b1SSteven Rostedt (VMware) * coming back from idle, or cpu on or offlining. 108e8cac8b1SSteven Rostedt (VMware) * 109e9b4e606SJiri Olsa * is_module_text_address() as well as the kprobe slots, 110e9b4e606SJiri Olsa * is_bpf_text_address() and is_bpf_image_address require 111e9b4e606SJiri Olsa * RCU to be watching. 112e8cac8b1SSteven Rostedt (VMware) */ 113e8cac8b1SSteven Rostedt (VMware) no_rcu = !rcu_is_watching(); 114e8cac8b1SSteven Rostedt (VMware) 115e8cac8b1SSteven Rostedt (VMware) /* Treat this like an NMI as it can happen anywhere */ 116e8cac8b1SSteven Rostedt (VMware) if (no_rcu) 117e8cac8b1SSteven Rostedt (VMware) rcu_nmi_enter(); 118e8cac8b1SSteven Rostedt (VMware) 119aec0be2dSSteven Rostedt (Red Hat) if (is_module_text_address(addr)) 120e8cac8b1SSteven Rostedt (VMware) goto out; 1215b485629SMasami Hiramatsu if (is_ftrace_trampoline(addr)) 122e8cac8b1SSteven Rostedt (VMware) goto out; 1235b485629SMasami Hiramatsu if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr)) 124e8cac8b1SSteven Rostedt (VMware) goto out; 12574451e66SDaniel Borkmann if (is_bpf_text_address(addr)) 126e8cac8b1SSteven Rostedt (VMware) goto out; 127e8cac8b1SSteven Rostedt (VMware) ret = 0; 128e8cac8b1SSteven Rostedt (VMware) out: 129e8cac8b1SSteven Rostedt (VMware) if (no_rcu) 130e8cac8b1SSteven Rostedt (VMware) rcu_nmi_exit(); 131e8cac8b1SSteven Rostedt (VMware) 132e8cac8b1SSteven Rostedt (VMware) return ret; 1331da177e4SLinus Torvalds } 134ab7476cfSArjan van de Ven 135ab7476cfSArjan van de Ven /* 136*e1478d8eSChristophe Leroy * On some architectures (PPC64, IA64, PARISC) function pointers 137ab7476cfSArjan van de Ven * are actually only tokens to some data that then holds the 138ab7476cfSArjan van de Ven * real function address. As a result, to find if a function 139ab7476cfSArjan van de Ven * pointer is part of the kernel text, we need to do some 140ab7476cfSArjan van de Ven * special dereferencing first. 141ab7476cfSArjan van de Ven */ 142*e1478d8eSChristophe Leroy #ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS 143*e1478d8eSChristophe Leroy void *dereference_function_descriptor(void *ptr) 144*e1478d8eSChristophe Leroy { 145*e1478d8eSChristophe Leroy func_desc_t *desc = ptr; 146*e1478d8eSChristophe Leroy void *p; 147*e1478d8eSChristophe Leroy 148*e1478d8eSChristophe Leroy if (!get_kernel_nofault(p, (void *)&desc->addr)) 149*e1478d8eSChristophe Leroy ptr = p; 150*e1478d8eSChristophe Leroy return ptr; 151*e1478d8eSChristophe Leroy } 152*e1478d8eSChristophe Leroy 153*e1478d8eSChristophe Leroy void *dereference_kernel_function_descriptor(void *ptr) 154*e1478d8eSChristophe Leroy { 155*e1478d8eSChristophe Leroy if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd) 156*e1478d8eSChristophe Leroy return ptr; 157*e1478d8eSChristophe Leroy 158*e1478d8eSChristophe Leroy return dereference_function_descriptor(ptr); 159*e1478d8eSChristophe Leroy } 160*e1478d8eSChristophe Leroy #endif 161*e1478d8eSChristophe Leroy 162ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr) 163ab7476cfSArjan van de Ven { 164ab7476cfSArjan van de Ven unsigned long addr; 165ab7476cfSArjan van de Ven addr = (unsigned long) dereference_function_descriptor(ptr); 166ab7476cfSArjan van de Ven if (core_kernel_text(addr)) 167ab7476cfSArjan van de Ven return 1; 168a6e6abd5SRusty Russell return is_module_text_address(addr); 169ab7476cfSArjan van de Ven } 170