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 */ 68b96f011SFrederic Weisbecker #include <linux/ftrace.h> 7f80d2d77SDmitri Vorobiev #include <linux/memory.h> 88a293be0SPaul Gortmaker #include <linux/extable.h> 9505f2b97SIngo Molnar #include <linux/module.h> 10505f2b97SIngo Molnar #include <linux/mutex.h> 11505f2b97SIngo Molnar #include <linux/init.h> 125b485629SMasami Hiramatsu #include <linux/kprobes.h> 1374451e66SDaniel Borkmann #include <linux/filter.h> 14505f2b97SIngo Molnar 151da177e4SLinus Torvalds #include <asm/sections.h> 167c0f6ba6SLinus Torvalds #include <linux/uaccess.h> 17505f2b97SIngo Molnar 18505f2b97SIngo Molnar /* 19505f2b97SIngo Molnar * mutex protecting text section modification (dynamic code patching). 20505f2b97SIngo Molnar * some users need to sleep (allocating memory...) while they hold this lock. 21505f2b97SIngo Molnar * 22e846d139SZhou Chengming * Note: Also protects SMP-alternatives modification on x86. 23e846d139SZhou Chengming * 24505f2b97SIngo Molnar * NOT exported to modules - patching kernel text is a really delicate matter. 25505f2b97SIngo Molnar */ 26505f2b97SIngo Molnar DEFINE_MUTEX(text_mutex); 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds extern struct exception_table_entry __start___ex_table[]; 291da177e4SLinus Torvalds extern struct exception_table_entry __stop___ex_table[]; 301da177e4SLinus Torvalds 31d219e2e8SDavid Daney /* Cleared by build time tools if the table is already sorted. */ 3200b71030SAndi Kleen u32 __initdata __visible main_extable_sort_needed = 1; 33d219e2e8SDavid Daney 341da177e4SLinus Torvalds /* Sort the kernel's built-in exception table */ 351da177e4SLinus Torvalds void __init sort_main_extable(void) 361da177e4SLinus Torvalds { 37e656a634SUwe Kleine-König if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) { 38bec1b9e7SBorislav Petkov pr_notice("Sorting __ex_table...\n"); 391da177e4SLinus Torvalds sort_extable(__start___ex_table, __stop___ex_table); 40bec1b9e7SBorislav Petkov } 411da177e4SLinus Torvalds } 421da177e4SLinus Torvalds 4349ec9177SSantosh Sivaraj /* Given an address, look for it in the kernel exception table */ 4449ec9177SSantosh Sivaraj const 4549ec9177SSantosh Sivaraj struct exception_table_entry *search_kernel_exception_table(unsigned long addr) 4649ec9177SSantosh Sivaraj { 4749ec9177SSantosh Sivaraj return search_extable(__start___ex_table, 4849ec9177SSantosh Sivaraj __stop___ex_table - __start___ex_table, addr); 4949ec9177SSantosh Sivaraj } 5049ec9177SSantosh Sivaraj 511da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */ 521da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr) 531da177e4SLinus Torvalds { 541da177e4SLinus Torvalds const struct exception_table_entry *e; 551da177e4SLinus Torvalds 5649ec9177SSantosh Sivaraj e = search_kernel_exception_table(addr); 571da177e4SLinus Torvalds if (!e) 581da177e4SLinus Torvalds e = search_module_extables(addr); 593dec541bSAlexei Starovoitov if (!e) 603dec541bSAlexei Starovoitov e = search_bpf_extables(addr); 611da177e4SLinus Torvalds return e; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 649fbcc57aSJosh Poimboeuf int init_kernel_text(unsigned long addr) 654a44bac1SIngo Molnar { 664a44bac1SIngo Molnar if (addr >= (unsigned long)_sinittext && 675ecbe3c3SHelge Deller addr < (unsigned long)_einittext) 684a44bac1SIngo Molnar return 1; 694a44bac1SIngo Molnar return 0; 704a44bac1SIngo Molnar } 714a44bac1SIngo Molnar 72c0d80ddaSMarcin Nowakowski int notrace core_kernel_text(unsigned long addr) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds if (addr >= (unsigned long)_stext && 755ecbe3c3SHelge Deller addr < (unsigned long)_etext) 761da177e4SLinus Torvalds return 1; 771da177e4SLinus Torvalds 780594729cSThomas Gleixner if (system_state < SYSTEM_RUNNING && 794a44bac1SIngo Molnar init_kernel_text(addr)) 801da177e4SLinus Torvalds return 1; 811da177e4SLinus Torvalds return 0; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 84a2d063acSSteven Rostedt /** 85a2d063acSSteven Rostedt * core_kernel_data - tell if addr points to kernel data 86a2d063acSSteven Rostedt * @addr: address to test 87a2d063acSSteven Rostedt * 88a2d063acSSteven Rostedt * Returns true if @addr passed in is from the core kernel data 89a2d063acSSteven Rostedt * section. 90a2d063acSSteven Rostedt * 91a2d063acSSteven Rostedt * Note: On some archs it may return true for core RODATA, and false 92a2d063acSSteven Rostedt * for others. But will always be true for core RW data. 93a2d063acSSteven Rostedt */ 94cdbe61bfSSteven Rostedt int core_kernel_data(unsigned long addr) 95cdbe61bfSSteven Rostedt { 96a2d063acSSteven Rostedt if (addr >= (unsigned long)_sdata && 97cdbe61bfSSteven Rostedt addr < (unsigned long)_edata) 98cdbe61bfSSteven Rostedt return 1; 99cdbe61bfSSteven Rostedt return 0; 100cdbe61bfSSteven Rostedt } 101cdbe61bfSSteven Rostedt 1023861a17bSFrederic Weisbecker int __kernel_text_address(unsigned long addr) 1031da177e4SLinus Torvalds { 1049aadde91SSteven Rostedt (VMware) if (kernel_text_address(addr)) 10574451e66SDaniel Borkmann return 1; 1064a44bac1SIngo Molnar /* 1074a44bac1SIngo Molnar * There might be init symbols in saved stacktraces. 1084a44bac1SIngo Molnar * Give those symbols a chance to be printed in 1094a44bac1SIngo Molnar * backtraces (such as lockdep traces). 1104a44bac1SIngo Molnar * 1114a44bac1SIngo Molnar * Since we are after the module-symbols check, there's 1124a44bac1SIngo Molnar * no danger of address overlap: 1134a44bac1SIngo Molnar */ 1144a44bac1SIngo Molnar if (init_kernel_text(addr)) 1154a44bac1SIngo Molnar return 1; 1164a44bac1SIngo Molnar return 0; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds int kernel_text_address(unsigned long addr) 1201da177e4SLinus Torvalds { 121e8cac8b1SSteven Rostedt (VMware) bool no_rcu; 122e8cac8b1SSteven Rostedt (VMware) int ret = 1; 123e8cac8b1SSteven Rostedt (VMware) 1241da177e4SLinus Torvalds if (core_kernel_text(addr)) 1251da177e4SLinus Torvalds return 1; 126e8cac8b1SSteven Rostedt (VMware) 127e8cac8b1SSteven Rostedt (VMware) /* 128e8cac8b1SSteven Rostedt (VMware) * If a stack dump happens while RCU is not watching, then 129e8cac8b1SSteven Rostedt (VMware) * RCU needs to be notified that it requires to start 130e8cac8b1SSteven Rostedt (VMware) * watching again. This can happen either by tracing that 131e8cac8b1SSteven Rostedt (VMware) * triggers a stack trace, or a WARN() that happens during 132e8cac8b1SSteven Rostedt (VMware) * coming back from idle, or cpu on or offlining. 133e8cac8b1SSteven Rostedt (VMware) * 134*e9b4e606SJiri Olsa * is_module_text_address() as well as the kprobe slots, 135*e9b4e606SJiri Olsa * is_bpf_text_address() and is_bpf_image_address require 136*e9b4e606SJiri Olsa * RCU to be watching. 137e8cac8b1SSteven Rostedt (VMware) */ 138e8cac8b1SSteven Rostedt (VMware) no_rcu = !rcu_is_watching(); 139e8cac8b1SSteven Rostedt (VMware) 140e8cac8b1SSteven Rostedt (VMware) /* Treat this like an NMI as it can happen anywhere */ 141e8cac8b1SSteven Rostedt (VMware) if (no_rcu) 142e8cac8b1SSteven Rostedt (VMware) rcu_nmi_enter(); 143e8cac8b1SSteven Rostedt (VMware) 144aec0be2dSSteven Rostedt (Red Hat) if (is_module_text_address(addr)) 145e8cac8b1SSteven Rostedt (VMware) goto out; 1465b485629SMasami Hiramatsu if (is_ftrace_trampoline(addr)) 147e8cac8b1SSteven Rostedt (VMware) goto out; 1485b485629SMasami Hiramatsu if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr)) 149e8cac8b1SSteven Rostedt (VMware) goto out; 15074451e66SDaniel Borkmann if (is_bpf_text_address(addr)) 151e8cac8b1SSteven Rostedt (VMware) goto out; 152*e9b4e606SJiri Olsa if (is_bpf_image_address(addr)) 153*e9b4e606SJiri Olsa goto out; 154e8cac8b1SSteven Rostedt (VMware) ret = 0; 155e8cac8b1SSteven Rostedt (VMware) out: 156e8cac8b1SSteven Rostedt (VMware) if (no_rcu) 157e8cac8b1SSteven Rostedt (VMware) rcu_nmi_exit(); 158e8cac8b1SSteven Rostedt (VMware) 159e8cac8b1SSteven Rostedt (VMware) return ret; 1601da177e4SLinus Torvalds } 161ab7476cfSArjan van de Ven 162ab7476cfSArjan van de Ven /* 163ab7476cfSArjan van de Ven * On some architectures (PPC64, IA64) function pointers 164ab7476cfSArjan van de Ven * are actually only tokens to some data that then holds the 165ab7476cfSArjan van de Ven * real function address. As a result, to find if a function 166ab7476cfSArjan van de Ven * pointer is part of the kernel text, we need to do some 167ab7476cfSArjan van de Ven * special dereferencing first. 168ab7476cfSArjan van de Ven */ 169ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr) 170ab7476cfSArjan van de Ven { 171ab7476cfSArjan van de Ven unsigned long addr; 172ab7476cfSArjan van de Ven addr = (unsigned long) dereference_function_descriptor(ptr); 173ab7476cfSArjan van de Ven if (core_kernel_text(addr)) 174ab7476cfSArjan van de Ven return 1; 175a6e6abd5SRusty Russell return is_module_text_address(addr); 176ab7476cfSArjan van de Ven } 177