History

Merge branch 'topic/func-desc-lkdtm' into next

Merge a topic branch we are maintaining with some cross-architecture changes to function descriptor handling and their use in LKDTM. From Christophe's cover letter: Fix LKDTM for PPC64/IA64/PARISC PPC64/IA64/PARISC have function descriptors. LKDTM doesn't work on those three architectures because LKDTM messes up function descriptors with functions. This series does some cleanup in the three architectures and refactors function descriptors so that it can then easily use it in a generic way in LKDTM.

Michael Ellerman committed 4 years ago

Commit 4bc06c52 parents 8219d31 5e5a6c525 files · +155 −144Browse files

Unified · Split

25 files
  1. arch/Kconfig +3 −0
  2. arch/ia64/Kconfig +1 −0
  3. arch/ia64/include/asm/elf.h +1 −1
  4. arch/ia64/include/asm/sections.h +3 −21
  5. arch/ia64/kernel/module.c +3 −3
  6. arch/parisc/Kconfig +1 −0
  7. arch/parisc/include/asm/sections.h +5 −11
  8. arch/parisc/kernel/process.c +0 −21
  9. arch/powerpc/Kconfig +1 −0
  10. arch/powerpc/Makefile +1 −1
  11. arch/powerpc/include/asm/code-patching.h +1 −1
  12. arch/powerpc/include/asm/elf.h +6 −0
  13. arch/powerpc/include/asm/sections.h +4 −25
  14. arch/powerpc/include/asm/types.h +0 −6
  15. arch/powerpc/include/uapi/asm/elf.h +0 −8
  16. arch/powerpc/kernel/module_64.c +17 −25
  17. arch/powerpc/kernel/ptrace/ptrace.c +6 −0
  18. arch/powerpc/kernel/signal_64.c +4 −4
  19. drivers/misc/lkdtm/core.c +1 −0
  20. drivers/misc/lkdtm/lkdtm.h +1 −0
  21. drivers/misc/lkdtm/perms.c +57 −14
  22. include/asm-generic/sections.h +14 −1
  23. include/linux/kallsyms.h +1 −1
  24. kernel/extable.c +23 −1
  25. tools/testing/selftests/lkdtm/tests.txt +1 −0
arch/Kconfig+3−0
@@ -205,6 +205,9 @@ config HAVE_FUNCTION_ERROR_INJECTION · 204 unmodified lines
205205 config HAVE_NMI
206206 bool
207207
208+config HAVE_FUNCTION_DESCRIPTORS
209+ bool
210+
208211 config TRACE_IRQFLAGS_SUPPORT
209212 bool
210213
arch/ia64/Kconfig+1−0
@@ -35,6 +35,7 @@ config IA64 · 34 unmodified lines
3535 select HAVE_SETUP_PER_CPU_AREA
3636 select TTY
3737 select HAVE_ARCH_TRACEHOOK
38+ select HAVE_FUNCTION_DESCRIPTORS
3839 select HAVE_VIRT_CPU_ACCOUNTING
3940 select HUGETLB_PAGE_SIZE_VARIABLE if HUGETLB_PAGE
4041 select VIRT_TO_BUS
arch/ia64/include/asm/elf.h+1−1
@@ -226,7 +226,7 @@ struct got_entry { · 225 unmodified lines
226226 * Layout of the Function Descriptor
227227 */
228228 struct fdesc {
229− uint64_t ip;
229+ uint64_t addr;
230230 uint64_t gp;
231231 };
232232
arch/ia64/include/asm/sections.h+3−21
@@ -9,6 +9,9 @@ · 8 unmodified lines
99
1010 #include <linux/elf.h>
1111 #include <linux/uaccess.h>
12+
13+typedef struct fdesc func_desc_t;
14+
1215 #include <asm-generic/sections.h>
1316
1417 extern char __phys_per_cpu_start[];
@@ -27,25 +30,4 @@ extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_b · 12 unmodified lines
2730 extern char __start_unwind[], __end_unwind[];
2831 extern char __start_ivt_text[], __end_ivt_text[];
2932
30−#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
31−
32−#undef dereference_function_descriptor
33−static inline void *dereference_function_descriptor(void *ptr)
34−{
35− struct fdesc *desc = ptr;
36− void *p;
37−
38− if (!get_kernel_nofault(p, (void *)&desc->ip))
39− ptr = p;
40− return ptr;
41−}
42−
43−#undef dereference_kernel_function_descriptor
44−static inline void *dereference_kernel_function_descriptor(void *ptr)
45−{
46− if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
47− return ptr;
48− return dereference_function_descriptor(ptr);
49−}
50−
5133 #endif /* _ASM_IA64_SECTIONS_H */
arch/ia64/kernel/module.c+3−3
@@ -602,15 +602,15 @@ get_fdesc (struct module *mod, uint64_t value, int *okp) · 601 unmodified lines
602602 return value;
603603
604604 /* Look for existing function descriptor. */
605− while (fdesc->ip) {
606− if (fdesc->ip == value)
605+ while (fdesc->addr) {
606+ if (fdesc->addr == value)
607607 return (uint64_t)fdesc;
608608 if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)
609609 BUG();
610610 }
611611
612612 /* Create new one */
613− fdesc->ip = value;
613+ fdesc->addr = value;
614614 fdesc->gp = mod->arch.gp;
615615 return (uint64_t) fdesc;
616616 }
arch/parisc/Kconfig+1−0
@@ -69,6 +69,7 @@ config PARISC · 68 unmodified lines
6969 select HAVE_DYNAMIC_FTRACE_WITH_REGS
7070 select HAVE_SOFTIRQ_ON_OWN_STACK if IRQSTACKS
7171 select TRACE_IRQFLAGS_SUPPORT
72+ select HAVE_FUNCTION_DESCRIPTORS if 64BIT
7273
7374 help
7475 The PA-RISC microprocessor is designed by Hewlett-Packard and used
arch/parisc/include/asm/sections.h+5−11
@@ -2,20 +2,14 @@ · 1 unmodified line
22 #ifndef _PARISC_SECTIONS_H
33 #define _PARISC_SECTIONS_H
44
5+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
6+#include <asm/elf.h>
7+typedef Elf64_Fdesc func_desc_t;
8+#endif
9+
510 /* nothing to see, move along */
611 #include <asm-generic/sections.h>
712
813 extern char __alt_instructions[], __alt_instructions_end[];
914
10−#ifdef CONFIG_64BIT
11−
12−#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
13−
14−#undef dereference_function_descriptor
15−void *dereference_function_descriptor(void *);
16−
17−#undef dereference_kernel_function_descriptor
18−void *dereference_kernel_function_descriptor(void *);
19−#endif
20−
2115 #endif
arch/parisc/kernel/process.c+0−21
@@ -263,27 +263,6 @@ __get_wchan(struct task_struct *p) · 262 unmodified lines
263263 return 0;
264264 }
265265
266−#ifdef CONFIG_64BIT
267−void *dereference_function_descriptor(void *ptr)
268−{
269− Elf64_Fdesc *desc = ptr;
270− void *p;
271−
272− if (!get_kernel_nofault(p, (void *)&desc->addr))
273− ptr = p;
274− return ptr;
275−}
276−
277−void *dereference_kernel_function_descriptor(void *ptr)
278−{
279− if (ptr < (void *)__start_opd ||
280− ptr >= (void *)__end_opd)
281− return ptr;
282−
283− return dereference_function_descriptor(ptr);
284−}
285−#endif
286−
287266 static inline unsigned long brk_rnd(void)
288267 {
289268 return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;
arch/powerpc/Kconfig+1−0
@@ -207,6 +207,7 @@ config PPC · 206 unmodified lines
207207 select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
208208 select HAVE_FAST_GUP
209209 select HAVE_FTRACE_MCOUNT_RECORD
210+ select HAVE_FUNCTION_DESCRIPTORS if PPC64 && !CPU_LITTLE_ENDIAN
210211 select HAVE_FUNCTION_ERROR_INJECTION
211212 select HAVE_FUNCTION_GRAPH_TRACER
212213 select HAVE_FUNCTION_TRACER
arch/powerpc/Makefile+1−1
@@ -213,7 +213,7 @@ CHECKFLAGS += -m$(BITS) -D__powerpc__ -D__powerpc$(BITS)__ · 212 unmodified lines
213213 ifdef CONFIG_CPU_BIG_ENDIAN
214214 CHECKFLAGS += -D__BIG_ENDIAN__
215215 else
216−CHECKFLAGS += -D__LITTLE_ENDIAN__
216+CHECKFLAGS += -D__LITTLE_ENDIAN__ -D_CALL_ELF=2
217217 endif
218218
219219 ifdef CONFIG_476FPE_ERR46
arch/powerpc/include/asm/code-patching.h+1−1
@@ -118,7 +118,7 @@ static inline unsigned long ppc_function_entry(void *func) · 117 unmodified lines
118118 * function's descriptor. The first entry in the descriptor is the
119119 * address of the function text.
120120 */
121− return ((func_descr_t *)func)->entry;
121+ return ((struct func_desc *)func)->addr;
122122 #else
123123 return (unsigned long)func;
124124 #endif
arch/powerpc/include/asm/elf.h+6−0
@@ -176,4 +176,10 @@ do { \ · 175 unmodified lines
176176 /* Relocate the kernel image to @final_address */
177177 void relocate(unsigned long final_address);
178178
179+struct func_desc {
180+ unsigned long addr;
181+ unsigned long toc;
182+ unsigned long env;
183+};
184+
179185 #endif /* _ASM_POWERPC_ELF_H */
arch/powerpc/include/asm/sections.h+4−25
@@ -6,6 +6,10 @@ · 5 unmodified lines
66 #include <linux/elf.h>
77 #include <linux/uaccess.h>
88
9+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
10+typedef struct func_desc func_desc_t;
11+#endif
12+
913 #include <asm-generic/sections.h>
1014
1115 extern char __head_end[];
@@ -54,31 +58,6 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end) · 42 unmodified lines
5458 (unsigned long)_stext < end;
5559 }
5660
57−#ifdef PPC64_ELF_ABI_v1
58−
59−#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
60−
61−#undef dereference_function_descriptor
62−static inline void *dereference_function_descriptor(void *ptr)
63−{
64− struct ppc64_opd_entry *desc = ptr;
65− void *p;
66−
67− if (!get_kernel_nofault(p, (void *)&desc->funcaddr))
68− ptr = p;
69− return ptr;
70−}
71−
72−#undef dereference_kernel_function_descriptor
73−static inline void *dereference_kernel_function_descriptor(void *ptr)
74−{
75− if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
76− return ptr;
77−
78− return dereference_function_descriptor(ptr);
79−}
80−#endif /* PPC64_ELF_ABI_v1 */
81−
8261 #endif
8362
8463 #endif /* __KERNEL__ */
arch/powerpc/include/asm/types.h+0−6
@@ -23,12 +23,6 @@ · 22 unmodified lines
2323
2424 typedef __vector128 vector128;
2525
26−typedef struct {
27− unsigned long entry;
28− unsigned long toc;
29− unsigned long env;
30−} func_descr_t;
31−
3226 #endif /* __ASSEMBLY__ */
3327
3428 #endif /* _ASM_POWERPC_TYPES_H */
arch/powerpc/include/uapi/asm/elf.h+0−8
@@ -289,12 +289,4 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG]; · 288 unmodified lines
289289 /* Keep this the last entry. */
290290 #define R_PPC64_NUM 253
291291
292−/* There's actually a third entry here, but it's unused */
293−struct ppc64_opd_entry
294−{
295− unsigned long funcaddr;
296− unsigned long r2;
297−};
298−
299−
300292 #endif /* _UAPI_ASM_POWERPC_ELF_H */
arch/powerpc/kernel/module_64.c+17−25
@@ -33,20 +33,13 @@ · 32 unmodified lines
3333
3434 #ifdef PPC64_ELF_ABI_v2
3535
36−/* An address is simply the address of the function. */
37−typedef unsigned long func_desc_t;
38−
3936 static func_desc_t func_desc(unsigned long addr)
4037 {
41− return addr;
42−}
43−static unsigned long func_addr(unsigned long addr)
44−{
45− return addr;
46−}
47−static unsigned long stub_func_addr(func_desc_t func)
48−{
49− return func;
38+ func_desc_t desc = {
39+ .addr = addr,
40+ };
41+
42+ return desc;
5043 }
5144
5245 /* PowerPC64 specific values for the Elf64_Sym st_other field. */
@@ -64,20 +57,9 @@ static unsigned int local_entry_offset(const Elf64_Sym *sym) · 11 unmodified lines
6457 }
6558 #else
6659
67−/* An address is address of the OPD entry, which contains address of fn. */
68−typedef struct ppc64_opd_entry func_desc_t;
69−
7060 static func_desc_t func_desc(unsigned long addr)
7161 {
72− return *(struct ppc64_opd_entry *)addr;
73−}
74−static unsigned long func_addr(unsigned long addr)
75−{
76− return func_desc(addr).funcaddr;
77−}
78−static unsigned long stub_func_addr(func_desc_t func)
79−{
80− return func.funcaddr;
62+ return *(struct func_desc *)addr;
8163 }
8264 static unsigned int local_entry_offset(const Elf64_Sym *sym)
8365 {
@@ -94,6 +76,16 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr) · 10 unmodified lines
9476 }
9577 #endif
9678
79+static unsigned long func_addr(unsigned long addr)
80+{
81+ return func_desc(addr).addr;
82+}
83+
84+static unsigned long stub_func_addr(func_desc_t func)
85+{
86+ return func.addr;
87+}
88+
9789 #define STUB_MAGIC 0x73747562 /* stub */
9890
9991 /* Like PPC32, we need little trampolines to do > 24-bit jumps (into
@@ -188,7 +180,7 @@ static int relacmp(const void *_x, const void *_y) · 88 unmodified lines
188180 static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
189181 const Elf64_Shdr *sechdrs)
190182 {
191− /* One extra reloc so it's always 0-funcaddr terminated */
183+ /* One extra reloc so it's always 0-addr terminated */
192184 unsigned long relocs = 1;
193185 unsigned i;
194186
arch/powerpc/kernel/ptrace/ptrace.c+6−0
@@ -445,4 +445,10 @@ void __init pt_regs_check(void) · 444 unmodified lines
445445 * real registers.
446446 */
447447 BUILD_BUG_ON(PT_DSCR < sizeof(struct user_pt_regs) / sizeof(unsigned long));
448+
449+#ifdef PPC64_ELF_ABI_v1
450+ BUILD_BUG_ON(!IS_ENABLED(CONFIG_HAVE_FUNCTION_DESCRIPTORS));
451+#else
452+ BUILD_BUG_ON(IS_ENABLED(CONFIG_HAVE_FUNCTION_DESCRIPTORS));
453+#endif
448454 }
arch/powerpc/kernel/signal_64.c+4−4
@@ -936,11 +936,11 @@ int handle_rt_signal64(struct ksignal *ksig, sigset_t *set, · 935 unmodified lines
936936 * descriptor is the entry address of signal and the second
937937 * entry is the TOC value we need to use.
938938 */
939− func_descr_t __user *funct_desc_ptr =
940− (func_descr_t __user *) ksig->ka.sa.sa_handler;
939+ struct func_desc __user *ptr =
940+ (struct func_desc __user *)ksig->ka.sa.sa_handler;
941941
942− err |= get_user(regs->ctr, &funct_desc_ptr->entry);
943− err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
942+ err |= get_user(regs->ctr, &ptr->addr);
943+ err |= get_user(regs->gpr[2], &ptr->toc);
944944 }
945945
946946 /* enter the signal handler in native-endian mode */
drivers/misc/lkdtm/core.c+1−0
@@ -149,6 +149,7 @@ static const struct crashtype crashtypes[] = { · 148 unmodified lines
149149 CRASHTYPE(WRITE_RO),
150150 CRASHTYPE(WRITE_RO_AFTER_INIT),
151151 CRASHTYPE(WRITE_KERN),
152+ CRASHTYPE(WRITE_OPD),
152153 CRASHTYPE(REFCOUNT_INC_OVERFLOW),
153154 CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
154155 CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
drivers/misc/lkdtm/lkdtm.h+1−0
@@ -106,6 +106,7 @@ void __init lkdtm_perms_init(void); · 105 unmodified lines
106106 void lkdtm_WRITE_RO(void);
107107 void lkdtm_WRITE_RO_AFTER_INIT(void);
108108 void lkdtm_WRITE_KERN(void);
109+void lkdtm_WRITE_OPD(void);
109110 void lkdtm_EXEC_DATA(void);
110111 void lkdtm_EXEC_STACK(void);
111112 void lkdtm_EXEC_KMALLOC(void);
drivers/misc/lkdtm/perms.c+57−14
@@ -10,6 +10,7 @@ · 9 unmodified lines
1010 #include <linux/mman.h>
1111 #include <linux/uaccess.h>
1212 #include <asm/cacheflush.h>
13+#include <asm/sections.h>
1314
1415 /* Whether or not to fill the target memory area with do_nothing(). */
1516 #define CODE_WRITE true
@@ -21,7 +22,7 @@ · 5 unmodified lines
2122 /* This is non-const, so it will end up in the .data section. */
2223 static u8 data_area[EXEC_SIZE];
2324
24−/* This is cost, so it will end up in the .rodata section. */
25+/* This is const, so it will end up in the .rodata section. */
2526 static const unsigned long rodata = 0xAA55AA55;
2627
2728 /* This is marked __ro_after_init, so it should ultimately be .rodata. */
@@ -31,31 +32,51 @@ static unsigned long ro_after_init __ro_after_init = 0x55AA5500; · 3 unmodified lines
3132 * This just returns to the caller. It is designed to be copied into
3233 * non-executable memory regions.
3334 */
34−static void do_nothing(void)
35+static noinline void do_nothing(void)
3536 {
3637 return;
3738 }
3839
3940 /* Must immediately follow do_nothing for size calculuations to work out. */
40−static void do_overwritten(void)
41+static noinline void do_overwritten(void)
4142 {
4243 pr_info("do_overwritten wasn't overwritten!\n");
4344 return;
4445 }
4546
47+static noinline void do_almost_nothing(void)
48+{
49+ pr_info("do_nothing was hijacked!\n");
50+}
51+
52+static void *setup_function_descriptor(func_desc_t *fdesc, void *dst)
53+{
54+ if (!have_function_descriptors())
55+ return dst;
56+
57+ memcpy(fdesc, do_nothing, sizeof(*fdesc));
58+ fdesc->addr = (unsigned long)dst;
59+ barrier();
60+
61+ return fdesc;
62+}
63+
4664 static noinline void execute_location(void *dst, bool write)
4765 {
48− void (*func)(void) = dst;
66+ void (*func)(void);
67+ func_desc_t fdesc;
68+ void *do_nothing_text = dereference_function_descriptor(do_nothing);
4969
50− pr_info("attempting ok execution at %px\n", do_nothing);
70+ pr_info("attempting ok execution at %px\n", do_nothing_text);
5171 do_nothing();
5272
5373 if (write == CODE_WRITE) {
54− memcpy(dst, do_nothing, EXEC_SIZE);
74+ memcpy(dst, do_nothing_text, EXEC_SIZE);
5575 flush_icache_range((unsigned long)dst,
5676 (unsigned long)dst + EXEC_SIZE);
5777 }
58− pr_info("attempting bad execution at %px\n", func);
78+ pr_info("attempting bad execution at %px\n", dst);
79+ func = setup_function_descriptor(&fdesc, dst);
5980 func();
6081 pr_err("FAIL: func returned\n");
6182 }
@@ -65,16 +86,19 @@ static void execute_user_location(void *dst) · 3 unmodified lines
6586 int copied;
6687
6788 /* Intentionally crossing kernel/user memory boundary. */
68− void (*func)(void) = dst;
89+ void (*func)(void);
90+ func_desc_t fdesc;
91+ void *do_nothing_text = dereference_function_descriptor(do_nothing);
6992
70− pr_info("attempting ok execution at %px\n", do_nothing);
93+ pr_info("attempting ok execution at %px\n", do_nothing_text);
7194 do_nothing();
7295
73− copied = access_process_vm(current, (unsigned long)dst, do_nothing,
96+ copied = access_process_vm(current, (unsigned long)dst, do_nothing_text,
7497 EXEC_SIZE, FOLL_WRITE);
7598 if (copied < EXEC_SIZE)
7699 return;
77− pr_info("attempting bad execution at %px\n", func);
100+ pr_info("attempting bad execution at %px\n", dst);
101+ func = setup_function_descriptor(&fdesc, dst);
78102 func();
79103 pr_err("FAIL: func returned\n");
80104 }
@@ -113,8 +137,9 @@ void lkdtm_WRITE_KERN(void) · 32 unmodified lines
113137 size_t size;
114138 volatile unsigned char *ptr;
115139
116− size = (unsigned long)do_overwritten - (unsigned long)do_nothing;
117− ptr = (unsigned char *)do_overwritten;
140+ size = (unsigned long)dereference_function_descriptor(do_overwritten) -
141+ (unsigned long)dereference_function_descriptor(do_nothing);
142+ ptr = dereference_function_descriptor(do_overwritten);
118143
119144 pr_info("attempting bad %zu byte write at %px\n", size, ptr);
120145 memcpy((void *)ptr, (unsigned char *)do_nothing, size);
@@ -124,6 +149,23 @@ void lkdtm_WRITE_KERN(void) · 3 unmodified lines
124149 do_overwritten();
125150 }
126151
152+void lkdtm_WRITE_OPD(void)
153+{
154+ size_t size = sizeof(func_desc_t);
155+ void (*func)(void) = do_nothing;
156+
157+ if (!have_function_descriptors()) {
158+ pr_info("XFAIL: Platform doesn't use function descriptors.\n");
159+ return;
160+ }
161+ pr_info("attempting bad %zu bytes write at %px\n", size, do_nothing);
162+ memcpy(do_nothing, do_almost_nothing, size);
163+ pr_err("FAIL: survived bad write\n");
164+
165+ asm("" : "=m"(func));
166+ func();
167+}
168+
127169 void lkdtm_EXEC_DATA(void)
128170 {
129171 execute_location(data_area, CODE_WRITE);
@@ -151,7 +193,8 @@ void lkdtm_EXEC_VMALLOC(void) · 21 unmodified lines
151193
152194 void lkdtm_EXEC_RODATA(void)
153195 {
154− execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS);
196+ execute_location(dereference_function_descriptor(lkdtm_rodata_do_nothing),
197+ CODE_AS_IS);
155198 }
156199
157200 void lkdtm_EXEC_USERSPACE(void)
include/asm-generic/sections.h+14−1
@@ -59,11 +59,24 @@ extern char __noinstr_text_start[], __noinstr_text_end[]; · 58 unmodified lines
5959 extern __visible const void __nosave_begin, __nosave_end;
6060
6161 /* Function descriptor handling (if any). Override in asm/sections.h */
62−#ifndef dereference_function_descriptor
62+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
63+void *dereference_function_descriptor(void *ptr);
64+void *dereference_kernel_function_descriptor(void *ptr);
65+#else
6366 #define dereference_function_descriptor(p) ((void *)(p))
6467 #define dereference_kernel_function_descriptor(p) ((void *)(p))
68+
69+/* An address is simply the address of the function. */
70+typedef struct {
71+ unsigned long addr;
72+} func_desc_t;
6573 #endif
6674
75+static inline bool have_function_descriptors(void)
76+{
77+ return IS_ENABLED(CONFIG_HAVE_FUNCTION_DESCRIPTORS);
78+}
79+
6780 /**
6881 * memory_contains - checks if an object is contained within a memory region
6982 * @begin: virtual address of the beginning of the memory region
include/linux/kallsyms.h+1−1
@@ -48,7 +48,7 @@ static inline int is_ksym_addr(unsigned long addr) · 47 unmodified lines
4848
4949 static inline void *dereference_symbol_descriptor(void *ptr)
5050 {
51−#ifdef HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR
51+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
5252 struct module *mod;
5353
5454 ptr = dereference_kernel_function_descriptor(ptr);
kernel/extable.c+23−1
@@ -3,6 +3,7 @@ · 2 unmodified lines
33 Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
44
55 */
6+#include <linux/elf.h>
67 #include <linux/ftrace.h>
78 #include <linux/memory.h>
89 #include <linux/extable.h>
@@ -132,12 +133,33 @@ out: · 123 unmodified lines
132133 }
133134
134135 /*
135− * On some architectures (PPC64, IA64) function pointers
136+ * On some architectures (PPC64, IA64, PARISC) function pointers
136137 * are actually only tokens to some data that then holds the
137138 * real function address. As a result, to find if a function
138139 * pointer is part of the kernel text, we need to do some
139140 * special dereferencing first.
140141 */
142+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
143+void *dereference_function_descriptor(void *ptr)
144+{
145+ func_desc_t *desc = ptr;
146+ void *p;
147+
148+ if (!get_kernel_nofault(p, (void *)&desc->addr))
149+ ptr = p;
150+ return ptr;
151+}
152+EXPORT_SYMBOL_GPL(dereference_function_descriptor);
153+
154+void *dereference_kernel_function_descriptor(void *ptr)
155+{
156+ if (ptr < (void *)__start_opd || ptr >= (void *)__end_opd)
157+ return ptr;
158+
159+ return dereference_function_descriptor(ptr);
160+}
161+#endif
162+
141163 int func_ptr_is_kernel_text(void *ptr)
142164 {
143165 unsigned long addr;
tools/testing/selftests/lkdtm/tests.txt+1−0
@@ -44,6 +44,7 @@ ACCESS_NULL · 43 unmodified lines
4444 WRITE_RO
4545 WRITE_RO_AFTER_INIT
4646 WRITE_KERN
47+WRITE_OPD
4748 REFCOUNT_INC_OVERFLOW
4849 REFCOUNT_ADD_OVERFLOW
4950 REFCOUNT_INC_NOT_ZERO_OVERFLOW