xref: /openbmc/linux/kernel/extable.c (revision e9b4e606c2289d6610113253922bb8c9ac7f68b0)
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