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
205config HAVE_NMI205config HAVE_NMI
206 bool206 bool
207 207
208config HAVE_FUNCTION_DESCRIPTORS
209 bool
210
208config TRACE_IRQFLAGS_SUPPORT211config TRACE_IRQFLAGS_SUPPORT
209 bool212 bool
210 213
arch/ia64/Kconfig+1−0
@@ -35,6 +35,7 @@ config IA64 · 34 unmodified lines
35 select HAVE_SETUP_PER_CPU_AREA35 select HAVE_SETUP_PER_CPU_AREA
36 select TTY36 select TTY
37 select HAVE_ARCH_TRACEHOOK37 select HAVE_ARCH_TRACEHOOK
38 select HAVE_FUNCTION_DESCRIPTORS
38 select HAVE_VIRT_CPU_ACCOUNTING39 select HAVE_VIRT_CPU_ACCOUNTING
39 select HUGETLB_PAGE_SIZE_VARIABLE if HUGETLB_PAGE40 select HUGETLB_PAGE_SIZE_VARIABLE if HUGETLB_PAGE
40 select VIRT_TO_BUS41 select VIRT_TO_BUS
arch/ia64/include/asm/elf.h+1−1
@@ -226,7 +226,7 @@ struct got_entry { · 225 unmodified lines
226 * Layout of the Function Descriptor226 * Layout of the Function Descriptor
227 */227 */
228struct fdesc {228struct fdesc {
229 uint64_t ip;229 uint64_t addr;
230 uint64_t gp;230 uint64_t gp;
231};231};
232 232
arch/ia64/include/asm/sections.h+3−21
@@ -9,6 +9,9 @@ · 8 unmodified lines
9 9
10#include <linux/elf.h>10#include <linux/elf.h>
11#include <linux/uaccess.h>11#include <linux/uaccess.h>
12
13typedef struct fdesc func_desc_t;
14
12#include <asm-generic/sections.h>15#include <asm-generic/sections.h>
13 16
14extern char __phys_per_cpu_start[];17extern 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
27extern char __start_unwind[], __end_unwind[];30extern char __start_unwind[], __end_unwind[];
28extern char __start_ivt_text[], __end_ivt_text[];31extern char __start_ivt_text[], __end_ivt_text[];
29 32
30#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
31
32#undef dereference_function_descriptor
33static 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
44static 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
51#endif /* _ASM_IA64_SECTIONS_H */33#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
602 return value;602 return value;
603 603
604 /* Look for existing function descriptor. */604 /* Look for existing function descriptor. */
605 while (fdesc->ip) {605 while (fdesc->addr) {
606 if (fdesc->ip == value)606 if (fdesc->addr == value)
607 return (uint64_t)fdesc;607 return (uint64_t)fdesc;
608 if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)608 if ((uint64_t) ++fdesc >= mod->arch.opd->sh_addr + mod->arch.opd->sh_size)
609 BUG();609 BUG();
610 }610 }
611 611
612 /* Create new one */612 /* Create new one */
613 fdesc->ip = value;613 fdesc->addr = value;
614 fdesc->gp = mod->arch.gp;614 fdesc->gp = mod->arch.gp;
615 return (uint64_t) fdesc;615 return (uint64_t) fdesc;
616}616}
arch/parisc/Kconfig+1−0
@@ -69,6 +69,7 @@ config PARISC · 68 unmodified lines
69 select HAVE_DYNAMIC_FTRACE_WITH_REGS69 select HAVE_DYNAMIC_FTRACE_WITH_REGS
70 select HAVE_SOFTIRQ_ON_OWN_STACK if IRQSTACKS70 select HAVE_SOFTIRQ_ON_OWN_STACK if IRQSTACKS
71 select TRACE_IRQFLAGS_SUPPORT71 select TRACE_IRQFLAGS_SUPPORT
72 select HAVE_FUNCTION_DESCRIPTORS if 64BIT
72 73
73 help74 help
74 The PA-RISC microprocessor is designed by Hewlett-Packard and used75 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
2#ifndef _PARISC_SECTIONS_H2#ifndef _PARISC_SECTIONS_H
3#define _PARISC_SECTIONS_H3#define _PARISC_SECTIONS_H
4 4
5#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
6#include <asm/elf.h>
7typedef Elf64_Fdesc func_desc_t;
8#endif
9
5/* nothing to see, move along */10/* nothing to see, move along */
6#include <asm-generic/sections.h>11#include <asm-generic/sections.h>
7 12
8extern char __alt_instructions[], __alt_instructions_end[];13extern char __alt_instructions[], __alt_instructions_end[];
9 14
10#ifdef CONFIG_64BIT
11
12#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
13
14#undef dereference_function_descriptor
15void *dereference_function_descriptor(void *);
16
17#undef dereference_kernel_function_descriptor
18void *dereference_kernel_function_descriptor(void *);
19#endif
20
21#endif15#endif
arch/parisc/kernel/process.c+0−21
@@ -263,27 +263,6 @@ __get_wchan(struct task_struct *p) · 262 unmodified lines
263 return 0;263 return 0;
264}264}
265 265
266#ifdef CONFIG_64BIT
267void *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
277void *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
287static inline unsigned long brk_rnd(void)266static inline unsigned long brk_rnd(void)
288{267{
289 return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;268 return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;
arch/powerpc/Kconfig+1−0
@@ -207,6 +207,7 @@ config PPC · 206 unmodified lines
207 select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)207 select HAVE_EFFICIENT_UNALIGNED_ACCESS if !(CPU_LITTLE_ENDIAN && POWER7_CPU)
208 select HAVE_FAST_GUP208 select HAVE_FAST_GUP
209 select HAVE_FTRACE_MCOUNT_RECORD209 select HAVE_FTRACE_MCOUNT_RECORD
210 select HAVE_FUNCTION_DESCRIPTORS if PPC64 && !CPU_LITTLE_ENDIAN
210 select HAVE_FUNCTION_ERROR_INJECTION211 select HAVE_FUNCTION_ERROR_INJECTION
211 select HAVE_FUNCTION_GRAPH_TRACER212 select HAVE_FUNCTION_GRAPH_TRACER
212 select HAVE_FUNCTION_TRACER213 select HAVE_FUNCTION_TRACER
arch/powerpc/Makefile+1−1
@@ -213,7 +213,7 @@ CHECKFLAGS += -m$(BITS) -D__powerpc__ -D__powerpc$(BITS)__ · 212 unmodified lines
213ifdef CONFIG_CPU_BIG_ENDIAN213ifdef CONFIG_CPU_BIG_ENDIAN
214CHECKFLAGS += -D__BIG_ENDIAN__214CHECKFLAGS += -D__BIG_ENDIAN__
215else215else
216CHECKFLAGS += -D__LITTLE_ENDIAN__216CHECKFLAGS += -D__LITTLE_ENDIAN__ -D_CALL_ELF=2
217endif217endif
218 218
219ifdef CONFIG_476FPE_ERR46219ifdef 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
118 * function's descriptor. The first entry in the descriptor is the118 * function's descriptor. The first entry in the descriptor is the
119 * address of the function text.119 * address of the function text.
120 */120 */
121 return ((func_descr_t *)func)->entry;121 return ((struct func_desc *)func)->addr;
122#else122#else
123 return (unsigned long)func;123 return (unsigned long)func;
124#endif124#endif
arch/powerpc/include/asm/elf.h+6−0
@@ -176,4 +176,10 @@ do { \ · 175 unmodified lines
176/* Relocate the kernel image to @final_address */176/* Relocate the kernel image to @final_address */
177void relocate(unsigned long final_address);177void relocate(unsigned long final_address);
178 178
179struct func_desc {
180 unsigned long addr;
181 unsigned long toc;
182 unsigned long env;
183};
184
179#endif /* _ASM_POWERPC_ELF_H */185#endif /* _ASM_POWERPC_ELF_H */
arch/powerpc/include/asm/sections.h+4−25
@@ -6,6 +6,10 @@ · 5 unmodified lines
6#include <linux/elf.h>6#include <linux/elf.h>
7#include <linux/uaccess.h>7#include <linux/uaccess.h>
8 8
9#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
10typedef struct func_desc func_desc_t;
11#endif
12
9#include <asm-generic/sections.h>13#include <asm-generic/sections.h>
10 14
11extern char __head_end[];15extern char __head_end[];
@@ -54,31 +58,6 @@ static inline int overlaps_kernel_text(unsigned long start, unsigned long end) · 42 unmodified lines
54 (unsigned long)_stext < end;58 (unsigned long)_stext < end;
55}59}
56 60
57#ifdef PPC64_ELF_ABI_v1
58
59#define HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR 1
60
61#undef dereference_function_descriptor
62static 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
73static 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
82#endif61#endif
83 62
84#endif /* __KERNEL__ */63#endif /* __KERNEL__ */
arch/powerpc/include/asm/types.h+0−6
@@ -23,12 +23,6 @@ · 22 unmodified lines
23 23
24typedef __vector128 vector128;24typedef __vector128 vector128;
25 25
26typedef struct {
27 unsigned long entry;
28 unsigned long toc;
29 unsigned long env;
30} func_descr_t;
31
32#endif /* __ASSEMBLY__ */26#endif /* __ASSEMBLY__ */
33 27
34#endif /* _ASM_POWERPC_TYPES_H */28#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
289/* Keep this the last entry. */289/* Keep this the last entry. */
290#define R_PPC64_NUM 253290#define R_PPC64_NUM 253
291 291
292/* There's actually a third entry here, but it's unused */
293struct ppc64_opd_entry
294{
295 unsigned long funcaddr;
296 unsigned long r2;
297};
298
299
300#endif /* _UAPI_ASM_POWERPC_ELF_H */292#endif /* _UAPI_ASM_POWERPC_ELF_H */
arch/powerpc/kernel/module_64.c+17−25
@@ -33,20 +33,13 @@ · 32 unmodified lines
33 33
34#ifdef PPC64_ELF_ABI_v234#ifdef PPC64_ELF_ABI_v2
35 35
36/* An address is simply the address of the function. */
37typedef unsigned long func_desc_t;
38
39static func_desc_t func_desc(unsigned long addr)36static func_desc_t func_desc(unsigned long addr)
40{37{
41 return addr;38 func_desc_t desc = {
42}39 .addr = addr,
43static unsigned long func_addr(unsigned long addr)40 };
44{41
45 return addr;42 return desc;
46}
47static unsigned long stub_func_addr(func_desc_t func)
48{
49 return func;
50}43}
51 44
52/* PowerPC64 specific values for the Elf64_Sym st_other field. */45/* 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
64}57}
65#else58#else
66 59
67/* An address is address of the OPD entry, which contains address of fn. */
68typedef struct ppc64_opd_entry func_desc_t;
69
70static func_desc_t func_desc(unsigned long addr)60static func_desc_t func_desc(unsigned long addr)
71{61{
72 return *(struct ppc64_opd_entry *)addr;62 return *(struct func_desc *)addr;
73}
74static unsigned long func_addr(unsigned long addr)
75{
76 return func_desc(addr).funcaddr;
77}
78static unsigned long stub_func_addr(func_desc_t func)
79{
80 return func.funcaddr;
81}63}
82static unsigned int local_entry_offset(const Elf64_Sym *sym)64static unsigned int local_entry_offset(const Elf64_Sym *sym)
83{65{
@@ -94,6 +76,16 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr) · 10 unmodified lines
94}76}
95#endif77#endif
96 78
79static unsigned long func_addr(unsigned long addr)
80{
81 return func_desc(addr).addr;
82}
83
84static unsigned long stub_func_addr(func_desc_t func)
85{
86 return func.addr;
87}
88
97#define STUB_MAGIC 0x73747562 /* stub */89#define STUB_MAGIC 0x73747562 /* stub */
98 90
99/* Like PPC32, we need little trampolines to do > 24-bit jumps (into91/* 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
188static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,180static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
189 const Elf64_Shdr *sechdrs)181 const Elf64_Shdr *sechdrs)
190{182{
191 /* One extra reloc so it's always 0-funcaddr terminated */183 /* One extra reloc so it's always 0-addr terminated */
192 unsigned long relocs = 1;184 unsigned long relocs = 1;
193 unsigned i;185 unsigned i;
194 186
arch/powerpc/kernel/ptrace/ptrace.c+6−0
@@ -445,4 +445,10 @@ void __init pt_regs_check(void) · 444 unmodified lines
445 * real registers.445 * real registers.
446 */446 */
447 BUILD_BUG_ON(PT_DSCR < sizeof(struct user_pt_regs) / sizeof(unsigned long));447 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
448}454}
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
936 * descriptor is the entry address of signal and the second936 * descriptor is the entry address of signal and the second
937 * entry is the TOC value we need to use.937 * entry is the TOC value we need to use.
938 */938 */
939 func_descr_t __user *funct_desc_ptr =939 struct func_desc __user *ptr =
940 (func_descr_t __user *) ksig->ka.sa.sa_handler;940 (struct func_desc __user *)ksig->ka.sa.sa_handler;
941 941
942 err |= get_user(regs->ctr, &funct_desc_ptr->entry);942 err |= get_user(regs->ctr, &ptr->addr);
943 err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);943 err |= get_user(regs->gpr[2], &ptr->toc);
944 }944 }
945 945
946 /* enter the signal handler in native-endian mode */946 /* 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
149 CRASHTYPE(WRITE_RO),149 CRASHTYPE(WRITE_RO),
150 CRASHTYPE(WRITE_RO_AFTER_INIT),150 CRASHTYPE(WRITE_RO_AFTER_INIT),
151 CRASHTYPE(WRITE_KERN),151 CRASHTYPE(WRITE_KERN),
152 CRASHTYPE(WRITE_OPD),
152 CRASHTYPE(REFCOUNT_INC_OVERFLOW),153 CRASHTYPE(REFCOUNT_INC_OVERFLOW),
153 CRASHTYPE(REFCOUNT_ADD_OVERFLOW),154 CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
154 CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),155 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
106void lkdtm_WRITE_RO(void);106void lkdtm_WRITE_RO(void);
107void lkdtm_WRITE_RO_AFTER_INIT(void);107void lkdtm_WRITE_RO_AFTER_INIT(void);
108void lkdtm_WRITE_KERN(void);108void lkdtm_WRITE_KERN(void);
109void lkdtm_WRITE_OPD(void);
109void lkdtm_EXEC_DATA(void);110void lkdtm_EXEC_DATA(void);
110void lkdtm_EXEC_STACK(void);111void lkdtm_EXEC_STACK(void);
111void lkdtm_EXEC_KMALLOC(void);112void lkdtm_EXEC_KMALLOC(void);
drivers/misc/lkdtm/perms.c+57−14
@@ -10,6 +10,7 @@ · 9 unmodified lines
10#include <linux/mman.h>10#include <linux/mman.h>
11#include <linux/uaccess.h>11#include <linux/uaccess.h>
12#include <asm/cacheflush.h>12#include <asm/cacheflush.h>
13#include <asm/sections.h>
13 14
14/* Whether or not to fill the target memory area with do_nothing(). */15/* Whether or not to fill the target memory area with do_nothing(). */
15#define CODE_WRITE true16#define CODE_WRITE true
@@ -21,7 +22,7 @@ · 5 unmodified lines
21/* This is non-const, so it will end up in the .data section. */22/* This is non-const, so it will end up in the .data section. */
22static u8 data_area[EXEC_SIZE];23static u8 data_area[EXEC_SIZE];
23 24
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. */
25static const unsigned long rodata = 0xAA55AA55;26static const unsigned long rodata = 0xAA55AA55;
26 27
27/* This is marked __ro_after_init, so it should ultimately be .rodata. */28/* 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
31 * This just returns to the caller. It is designed to be copied into32 * This just returns to the caller. It is designed to be copied into
32 * non-executable memory regions.33 * non-executable memory regions.
33 */34 */
34static void do_nothing(void)35static noinline void do_nothing(void)
35{36{
36 return;37 return;
37}38}
38 39
39/* Must immediately follow do_nothing for size calculuations to work out. */40/* Must immediately follow do_nothing for size calculuations to work out. */
40static void do_overwritten(void)41static noinline void do_overwritten(void)
41{42{
42 pr_info("do_overwritten wasn't overwritten!\n");43 pr_info("do_overwritten wasn't overwritten!\n");
43 return;44 return;
44}45}
45 46
47static noinline void do_almost_nothing(void)
48{
49 pr_info("do_nothing was hijacked!\n");
50}
51
52static 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
46static noinline void execute_location(void *dst, bool write)64static noinline void execute_location(void *dst, bool write)
47{65{
48 void (*func)(void) = dst;66 void (*func)(void);
67 func_desc_t fdesc;
68 void *do_nothing_text = dereference_function_descriptor(do_nothing);
49 69
50 pr_info("attempting ok execution at %px\n", do_nothing);70 pr_info("attempting ok execution at %px\n", do_nothing_text);
51 do_nothing();71 do_nothing();
52 72
53 if (write == CODE_WRITE) {73 if (write == CODE_WRITE) {
54 memcpy(dst, do_nothing, EXEC_SIZE);74 memcpy(dst, do_nothing_text, EXEC_SIZE);
55 flush_icache_range((unsigned long)dst,75 flush_icache_range((unsigned long)dst,
56 (unsigned long)dst + EXEC_SIZE);76 (unsigned long)dst + EXEC_SIZE);
57 }77 }
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);
59 func();80 func();
60 pr_err("FAIL: func returned\n");81 pr_err("FAIL: func returned\n");
61}82}
@@ -65,16 +86,19 @@ static void execute_user_location(void *dst) · 3 unmodified lines
65 int copied;86 int copied;
66 87
67 /* Intentionally crossing kernel/user memory boundary. */88 /* 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);
69 92
70 pr_info("attempting ok execution at %px\n", do_nothing);93 pr_info("attempting ok execution at %px\n", do_nothing_text);
71 do_nothing();94 do_nothing();
72 95
73 copied = access_process_vm(current, (unsigned long)dst, do_nothing,96 copied = access_process_vm(current, (unsigned long)dst, do_nothing_text,
74 EXEC_SIZE, FOLL_WRITE);97 EXEC_SIZE, FOLL_WRITE);
75 if (copied < EXEC_SIZE)98 if (copied < EXEC_SIZE)
76 return;99 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);
78 func();102 func();
79 pr_err("FAIL: func returned\n");103 pr_err("FAIL: func returned\n");
80}104}
@@ -113,8 +137,9 @@ void lkdtm_WRITE_KERN(void) · 32 unmodified lines
113 size_t size;137 size_t size;
114 volatile unsigned char *ptr;138 volatile unsigned char *ptr;
115 139
116 size = (unsigned long)do_overwritten - (unsigned long)do_nothing;140 size = (unsigned long)dereference_function_descriptor(do_overwritten) -
117 ptr = (unsigned char *)do_overwritten;141 (unsigned long)dereference_function_descriptor(do_nothing);
142 ptr = dereference_function_descriptor(do_overwritten);
118 143
119 pr_info("attempting bad %zu byte write at %px\n", size, ptr);144 pr_info("attempting bad %zu byte write at %px\n", size, ptr);
120 memcpy((void *)ptr, (unsigned char *)do_nothing, size);145 memcpy((void *)ptr, (unsigned char *)do_nothing, size);
@@ -124,6 +149,23 @@ void lkdtm_WRITE_KERN(void) · 3 unmodified lines
124 do_overwritten();149 do_overwritten();
125}150}
126 151
152void 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
127void lkdtm_EXEC_DATA(void)169void lkdtm_EXEC_DATA(void)
128{170{
129 execute_location(data_area, CODE_WRITE);171 execute_location(data_area, CODE_WRITE);
@@ -151,7 +193,8 @@ void lkdtm_EXEC_VMALLOC(void) · 21 unmodified lines
151 193
152void lkdtm_EXEC_RODATA(void)194void lkdtm_EXEC_RODATA(void)
153{195{
154 execute_location(lkdtm_rodata_do_nothing, CODE_AS_IS);196 execute_location(dereference_function_descriptor(lkdtm_rodata_do_nothing),
197 CODE_AS_IS);
155}198}
156 199
157void lkdtm_EXEC_USERSPACE(void)200void 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
59extern __visible const void __nosave_begin, __nosave_end;59extern __visible const void __nosave_begin, __nosave_end;
60 60
61/* Function descriptor handling (if any). Override in asm/sections.h */61/* Function descriptor handling (if any). Override in asm/sections.h */
62#ifndef dereference_function_descriptor62#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
63void *dereference_function_descriptor(void *ptr);
64void *dereference_kernel_function_descriptor(void *ptr);
65#else
63#define dereference_function_descriptor(p) ((void *)(p))66#define dereference_function_descriptor(p) ((void *)(p))
64#define dereference_kernel_function_descriptor(p) ((void *)(p))67#define dereference_kernel_function_descriptor(p) ((void *)(p))
68
69/* An address is simply the address of the function. */
70typedef struct {
71 unsigned long addr;
72} func_desc_t;
65#endif73#endif
66 74
75static inline bool have_function_descriptors(void)
76{
77 return IS_ENABLED(CONFIG_HAVE_FUNCTION_DESCRIPTORS);
78}
79
67/**80/**
68 * memory_contains - checks if an object is contained within a memory region81 * memory_contains - checks if an object is contained within a memory region
69 * @begin: virtual address of the beginning of the memory region82 * @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
48 48
49static inline void *dereference_symbol_descriptor(void *ptr)49static inline void *dereference_symbol_descriptor(void *ptr)
50{50{
51#ifdef HAVE_DEREFERENCE_FUNCTION_DESCRIPTOR51#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
52 struct module *mod;52 struct module *mod;
53 53
54 ptr = dereference_kernel_function_descriptor(ptr);54 ptr = dereference_kernel_function_descriptor(ptr);
kernel/extable.c+23−1
@@ -3,6 +3,7 @@ · 2 unmodified lines
3 Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.3 Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
4 4
5*/5*/
6#include <linux/elf.h>
6#include <linux/ftrace.h>7#include <linux/ftrace.h>
7#include <linux/memory.h>8#include <linux/memory.h>
8#include <linux/extable.h>9#include <linux/extable.h>
@@ -132,12 +133,33 @@ out: · 123 unmodified lines
132}133}
133 134
134/*135/*
135 * On some architectures (PPC64, IA64) function pointers136 * On some architectures (PPC64, IA64, PARISC) function pointers
136 * are actually only tokens to some data that then holds the137 * are actually only tokens to some data that then holds the
137 * real function address. As a result, to find if a function138 * real function address. As a result, to find if a function
138 * pointer is part of the kernel text, we need to do some139 * pointer is part of the kernel text, we need to do some
139 * special dereferencing first.140 * special dereferencing first.
140 */141 */
142#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
143void *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}
152EXPORT_SYMBOL_GPL(dereference_function_descriptor);
153
154void *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
141int func_ptr_is_kernel_text(void *ptr)163int func_ptr_is_kernel_text(void *ptr)
142{164{
143 unsigned long addr;165 unsigned long addr;
tools/testing/selftests/lkdtm/tests.txt+1−0
@@ -44,6 +44,7 @@ ACCESS_NULL · 43 unmodified lines
44WRITE_RO44WRITE_RO
45WRITE_RO_AFTER_INIT45WRITE_RO_AFTER_INIT
46WRITE_KERN46WRITE_KERN
47WRITE_OPD
47REFCOUNT_INC_OVERFLOW48REFCOUNT_INC_OVERFLOW
48REFCOUNT_ADD_OVERFLOW49REFCOUNT_ADD_OVERFLOW
49REFCOUNT_INC_NOT_ZERO_OVERFLOW50REFCOUNT_INC_NOT_ZERO_OVERFLOW