Skip to content

Commit 2860cd8

Browse files
committed
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. Cc: Josh Poimboeuf <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: [email protected] Acked-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Miroslav Benes <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent 02a474c commit 2860cd8

File tree

8 files changed

+29
-9
lines changed

8 files changed

+29
-9
lines changed

arch/powerpc/include/asm/livepatch.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs)
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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ SYM_INNER_LABEL(ftrace_caller_op_ptr, SYM_L_GLOBAL)
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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ struct ftrace_regs {
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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ config HAVE_LIVEPATCH
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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ static void notrace klp_ftrace_handler(unsigned long ip,
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,
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)
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

0 commit comments

Comments
 (0)