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 { 3763174f61SNathan Chancellor if (main_extable_sort_needed && 3863174f61SNathan Chancellor &__stop___ex_table > &__start___ex_table) { 39bec1b9e7SBorislav Petkov pr_notice("Sorting __ex_table...\n"); 401da177e4SLinus Torvalds sort_extable(__start___ex_table, __stop___ex_table); 41bec1b9e7SBorislav Petkov } 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 4449ec9177SSantosh Sivaraj /* Given an address, look for it in the kernel exception table */ 4549ec9177SSantosh Sivaraj const 4649ec9177SSantosh Sivaraj struct exception_table_entry *search_kernel_exception_table(unsigned long addr) 4749ec9177SSantosh Sivaraj { 4849ec9177SSantosh Sivaraj return search_extable(__start___ex_table, 4949ec9177SSantosh Sivaraj __stop___ex_table - __start___ex_table, addr); 5049ec9177SSantosh Sivaraj } 5149ec9177SSantosh Sivaraj 521da177e4SLinus Torvalds /* Given an address, look for it in the exception tables. */ 531da177e4SLinus Torvalds const struct exception_table_entry *search_exception_tables(unsigned long addr) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds const struct exception_table_entry *e; 561da177e4SLinus Torvalds 5749ec9177SSantosh Sivaraj e = search_kernel_exception_table(addr); 581da177e4SLinus Torvalds if (!e) 591da177e4SLinus Torvalds e = search_module_extables(addr); 603dec541bSAlexei Starovoitov if (!e) 613dec541bSAlexei Starovoitov e = search_bpf_extables(addr); 621da177e4SLinus Torvalds return e; 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 65c0d80ddaSMarcin Nowakowski int notrace core_kernel_text(unsigned long addr) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds if (addr >= (unsigned long)_stext && 685ecbe3c3SHelge Deller addr < (unsigned long)_etext) 691da177e4SLinus Torvalds return 1; 701da177e4SLinus Torvalds 71d2635f20SChristophe Leroy if (system_state < SYSTEM_FREEING_INITMEM && 72*b9ad8fe7SKefeng 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 */ 89*b9ad8fe7SKefeng 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 /* 136ab7476cfSArjan van de Ven * On some architectures (PPC64, IA64) 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 */ 142ab7476cfSArjan van de Ven int func_ptr_is_kernel_text(void *ptr) 143ab7476cfSArjan van de Ven { 144ab7476cfSArjan van de Ven unsigned long addr; 145ab7476cfSArjan van de Ven addr = (unsigned long) dereference_function_descriptor(ptr); 146ab7476cfSArjan van de Ven if (core_kernel_text(addr)) 147ab7476cfSArjan van de Ven return 1; 148a6e6abd5SRusty Russell return is_module_text_address(addr); 149ab7476cfSArjan van de Ven } 150