0001
0002
0003
0004
0005
0006 #include <linux/elf.h>
0007 #include <linux/ftrace.h>
0008 #include <linux/memory.h>
0009 #include <linux/extable.h>
0010 #include <linux/module.h>
0011 #include <linux/mutex.h>
0012 #include <linux/init.h>
0013 #include <linux/kprobes.h>
0014 #include <linux/filter.h>
0015
0016 #include <asm/sections.h>
0017 #include <linux/uaccess.h>
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 DEFINE_MUTEX(text_mutex);
0028
0029 extern struct exception_table_entry __start___ex_table[];
0030 extern struct exception_table_entry __stop___ex_table[];
0031
0032
0033 u32 __initdata __visible main_extable_sort_needed = 1;
0034
0035
0036 void __init sort_main_extable(void)
0037 {
0038 if (main_extable_sort_needed &&
0039 &__stop___ex_table > &__start___ex_table) {
0040 pr_notice("Sorting __ex_table...\n");
0041 sort_extable(__start___ex_table, __stop___ex_table);
0042 }
0043 }
0044
0045
0046 const
0047 struct exception_table_entry *search_kernel_exception_table(unsigned long addr)
0048 {
0049 return search_extable(__start___ex_table,
0050 __stop___ex_table - __start___ex_table, addr);
0051 }
0052
0053
0054 const struct exception_table_entry *search_exception_tables(unsigned long addr)
0055 {
0056 const struct exception_table_entry *e;
0057
0058 e = search_kernel_exception_table(addr);
0059 if (!e)
0060 e = search_module_extables(addr);
0061 if (!e)
0062 e = search_bpf_extables(addr);
0063 return e;
0064 }
0065
0066 int notrace core_kernel_text(unsigned long addr)
0067 {
0068 if (is_kernel_text(addr))
0069 return 1;
0070
0071 if (system_state < SYSTEM_FREEING_INITMEM &&
0072 is_kernel_inittext(addr))
0073 return 1;
0074 return 0;
0075 }
0076
0077 int __kernel_text_address(unsigned long addr)
0078 {
0079 if (kernel_text_address(addr))
0080 return 1;
0081
0082
0083
0084
0085
0086
0087
0088
0089 if (is_kernel_inittext(addr))
0090 return 1;
0091 return 0;
0092 }
0093
0094 int kernel_text_address(unsigned long addr)
0095 {
0096 bool no_rcu;
0097 int ret = 1;
0098
0099 if (core_kernel_text(addr))
0100 return 1;
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 no_rcu = !rcu_is_watching();
0114
0115
0116 if (no_rcu)
0117 ct_nmi_enter();
0118
0119 if (is_module_text_address(addr))
0120 goto out;
0121 if (is_ftrace_trampoline(addr))
0122 goto out;
0123 if (is_kprobe_optinsn_slot(addr) || is_kprobe_insn_slot(addr))
0124 goto out;
0125 if (is_bpf_text_address(addr))
0126 goto out;
0127 ret = 0;
0128 out:
0129 if (no_rcu)
0130 ct_nmi_exit();
0131
0132 return ret;
0133 }
0134
0135
0136
0137
0138
0139
0140
0141
0142 #ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
0143 void *dereference_function_descriptor(void *ptr)
0144 {
0145 func_desc_t *desc = ptr;
0146 void *p;
0147
0148 if (!get_kernel_nofault(p, (void *)&desc->addr))
0149 ptr = p;
0150 return ptr;
0151 }
0152 EXPORT_SYMBOL_GPL(dereference_function_descriptor);
0153
0154 void *dereference_kernel_function_descriptor(void *ptr)
0155 {
0156 if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
0157 return ptr;
0158
0159 return dereference_function_descriptor(ptr);
0160 }
0161 #endif
0162
0163 int func_ptr_is_kernel_text(void *ptr)
0164 {
0165 unsigned long addr;
0166 addr = (unsigned long) dereference_function_descriptor(ptr);
0167 if (core_kernel_text(addr))
0168 return 1;
0169 return is_module_text_address(addr);
0170 }