History

livepatch: Use the default ftrace_ops instead of REGS when ARGS is available

When CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS is available, the ftrace call will be able to set the ip of the calling function. This will improve the performance of live kernel patching where it does not need all the regs to be stored just to change the instruction pointer. If all archs that support live kernel patching also support HAVE_DYNAMIC_FTRACE_WITH_ARGS, then the architecture specific function klp_arch_set_pc() could be made generic. It is possible that an arch can support HAVE_DYNAMIC_FTRACE_WITH_ARGS but not HAVE_DYNAMIC_FTRACE_WITH_REGS and then have access to live patching.

Steven Rostedt (VMware) committed 6 years ago

Commit 2860cd81 parent 02a474c8 files · +29 −9Browse files

Unified · Split

8 files
  1. arch/powerpc/include/asm/livepatch.h +3 −1
  2. arch/s390/include/asm/livepatch.h +4 −1
  3. arch/x86/include/asm/ftrace.h +3 −0
  4. arch/x86/include/asm/livepatch.h +2 −2
  5. arch/x86/kernel/ftrace_64.S +4 −0
  6. include/linux/ftrace.h +7 −0
  7. kernel/livepatch/Kconfig +1 −1
  8. kernel/livepatch/patch.c +5 −4
arch/powerpc/include/asm/livepatch.h+3−1
@@ -12,8 +12,10 @@ · 11 unmodified lines
1212 #include <linux/sched/task_stack.h>
1313
1414 #ifdef CONFIG_LIVEPATCH
15−static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
15+static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
1616 {
17+ struct pt_regs *regs = ftrace_get_regs(fregs);
18+
1719 regs->nip = ip;
1820 }
1921
arch/s390/include/asm/livepatch.h+4−1
@@ -11,10 +11,13 @@ · 10 unmodified lines
1111 #ifndef ASM_LIVEPATCH_H
1212 #define ASM_LIVEPATCH_H
1313
14+#include <linux/ftrace.h>
1415 #include <asm/ptrace.h>
1516
16−static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
17+static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
1718 {
19+ struct pt_regs *regs = ftrace_get_regs(fregs);
20+
1821 regs->psw.addr = ip;
1922 }
2023
arch/x86/include/asm/ftrace.h+3−0
@@ -54,6 +54,9 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs) · 53 unmodified lines
5454 return NULL;
5555 return &fregs->regs;
5656 }
57+
58+#define ftrace_instruction_pointer_set(fregs, _ip) \
59+ do { (fregs)->regs.ip = (_ip); } while (0)
5760 #endif
5861
5962 #ifdef CONFIG_DYNAMIC_FTRACE
arch/x86/include/asm/livepatch.h+2−2
@@ -12,9 +12,9 @@ · 11 unmodified lines
1212 #include <asm/setup.h>
1313 #include <linux/ftrace.h>
1414
15−static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
15+static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
1616 {
17− regs->ip = ip;
17+ ftrace_instruction_pointer_set(fregs, ip);
1818 }
1919
2020 #endif /* _ASM_X86_LIVEPATCH_H */
arch/x86/kernel/ftrace_64.S+4−0
@@ -157,6 +157,10 @@ SYM_INNER_LABEL(ftrace_caller_op_ptr, SYM_L_GLOBAL) · 156 unmodified lines
157157 SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
158158 call ftrace_stub
159159
160+ /* Handlers can change the RIP */
161+ movq RIP(%rsp), %rax
162+ movq %rax, MCOUNT_REG_SIZE(%rsp)
163+
160164 restore_mcount_regs
161165
162166 /*
include/linux/ftrace.h+7−0
@@ -97,6 +97,13 @@ struct ftrace_regs { · 96 unmodified lines
9797 };
9898 #define arch_ftrace_get_regs(fregs) (&(fregs)->regs)
9999
100+/*
101+ * ftrace_instruction_pointer_set() is to be defined by the architecture
102+ * if to allow setting of the instruction pointer from the ftrace_regs
103+ * when HAVE_DYNAMIC_FTRACE_WITH_ARGS is set and it supports
104+ * live kernel patching.
105+ */
106+#define ftrace_instruction_pointer_set(fregs, ip) do { } while (0)
100107 #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
101108
102109 static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs)
kernel/livepatch/Kconfig+1−1
@@ -6,7 +6,7 @@ config HAVE_LIVEPATCH · 5 unmodified lines
66
77 config LIVEPATCH
88 bool "Kernel Live Patching"
9− depends on DYNAMIC_FTRACE_WITH_REGS
9+ depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
1010 depends on MODULES
1111 depends on SYSFS
1212 depends on KALLSYMS_ALL
kernel/livepatch/patch.c+5−4
@@ -42,7 +42,6 @@ static void notrace klp_ftrace_handler(unsigned long ip, · 41 unmodified lines
4242 struct ftrace_ops *fops,
4343 struct ftrace_regs *fregs)
4444 {
45− struct pt_regs *regs = ftrace_get_regs(fregs);
4645 struct klp_ops *ops;
4746 struct klp_func *func;
4847 int patch_state;
@@ -118,7 +117,7 @@ static void notrace klp_ftrace_handler(unsigned long ip, · 69 unmodified lines
118117 if (func->nop)
119118 goto unlock;
120119
121− klp_arch_set_pc(regs, (unsigned long)func->new_func);
120+ klp_arch_set_pc(fregs, (unsigned long)func->new_func);
122121
123122 unlock:
124123 preempt_enable_notrace();
@@ -200,8 +199,10 @@ static int klp_patch_func(struct klp_func *func) · 75 unmodified lines
200199 return -ENOMEM;
201200
202201 ops->fops.func = klp_ftrace_handler;
203− ops->fops.flags = FTRACE_OPS_FL_SAVE_REGS |
204− FTRACE_OPS_FL_DYNAMIC |
202+ ops->fops.flags = FTRACE_OPS_FL_DYNAMIC |
203+#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
204+ FTRACE_OPS_FL_SAVE_REGS |
205+#endif
205206 FTRACE_OPS_FL_IPMODIFY |
206207 FTRACE_OPS_FL_PERMANENT;
207208