mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 06:01:57 +00:00
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 <jpoimboe@redhat.com> Cc: Jiri Kosina <jikos@kernel.org> Cc: live-patching@vger.kernel.org Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
This commit is contained in:
parent
02a474ca26
commit
2860cd8a23
@ -12,8 +12,10 @@
|
||||
#include <linux/sched/task_stack.h>
|
||||
|
||||
#ifdef CONFIG_LIVEPATCH
|
||||
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
|
||||
static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
|
||||
{
|
||||
struct pt_regs *regs = ftrace_get_regs(fregs);
|
||||
|
||||
regs->nip = ip;
|
||||
}
|
||||
|
||||
|
@ -11,10 +11,13 @@
|
||||
#ifndef ASM_LIVEPATCH_H
|
||||
#define ASM_LIVEPATCH_H
|
||||
|
||||
#include <linux/ftrace.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
|
||||
static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
|
||||
{
|
||||
struct pt_regs *regs = ftrace_get_regs(fregs);
|
||||
|
||||
regs->psw.addr = ip;
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,9 @@ arch_ftrace_get_regs(struct ftrace_regs *fregs)
|
||||
return NULL;
|
||||
return &fregs->regs;
|
||||
}
|
||||
|
||||
#define ftrace_instruction_pointer_set(fregs, _ip) \
|
||||
do { (fregs)->regs.ip = (_ip); } while (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include <asm/setup.h>
|
||||
#include <linux/ftrace.h>
|
||||
|
||||
static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip)
|
||||
static inline void klp_arch_set_pc(struct ftrace_regs *fregs, unsigned long ip)
|
||||
{
|
||||
regs->ip = ip;
|
||||
ftrace_instruction_pointer_set(fregs, ip);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_LIVEPATCH_H */
|
||||
|
@ -157,6 +157,10 @@ SYM_INNER_LABEL(ftrace_caller_op_ptr, SYM_L_GLOBAL)
|
||||
SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
|
||||
call ftrace_stub
|
||||
|
||||
/* Handlers can change the RIP */
|
||||
movq RIP(%rsp), %rax
|
||||
movq %rax, MCOUNT_REG_SIZE(%rsp)
|
||||
|
||||
restore_mcount_regs
|
||||
|
||||
/*
|
||||
|
@ -97,6 +97,13 @@ struct ftrace_regs {
|
||||
};
|
||||
#define arch_ftrace_get_regs(fregs) (&(fregs)->regs)
|
||||
|
||||
/*
|
||||
* ftrace_instruction_pointer_set() is to be defined by the architecture
|
||||
* if to allow setting of the instruction pointer from the ftrace_regs
|
||||
* when HAVE_DYNAMIC_FTRACE_WITH_ARGS is set and it supports
|
||||
* live kernel patching.
|
||||
*/
|
||||
#define ftrace_instruction_pointer_set(fregs, ip) do { } while (0)
|
||||
#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
|
||||
|
||||
static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs)
|
||||
|
@ -6,7 +6,7 @@ config HAVE_LIVEPATCH
|
||||
|
||||
config LIVEPATCH
|
||||
bool "Kernel Live Patching"
|
||||
depends on DYNAMIC_FTRACE_WITH_REGS
|
||||
depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
|
||||
depends on MODULES
|
||||
depends on SYSFS
|
||||
depends on KALLSYMS_ALL
|
||||
|
@ -42,7 +42,6 @@ static void notrace klp_ftrace_handler(unsigned long ip,
|
||||
struct ftrace_ops *fops,
|
||||
struct ftrace_regs *fregs)
|
||||
{
|
||||
struct pt_regs *regs = ftrace_get_regs(fregs);
|
||||
struct klp_ops *ops;
|
||||
struct klp_func *func;
|
||||
int patch_state;
|
||||
@ -118,7 +117,7 @@ static void notrace klp_ftrace_handler(unsigned long ip,
|
||||
if (func->nop)
|
||||
goto unlock;
|
||||
|
||||
klp_arch_set_pc(regs, (unsigned long)func->new_func);
|
||||
klp_arch_set_pc(fregs, (unsigned long)func->new_func);
|
||||
|
||||
unlock:
|
||||
preempt_enable_notrace();
|
||||
@ -200,8 +199,10 @@ static int klp_patch_func(struct klp_func *func)
|
||||
return -ENOMEM;
|
||||
|
||||
ops->fops.func = klp_ftrace_handler;
|
||||
ops->fops.flags = FTRACE_OPS_FL_SAVE_REGS |
|
||||
FTRACE_OPS_FL_DYNAMIC |
|
||||
ops->fops.flags = FTRACE_OPS_FL_DYNAMIC |
|
||||
#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
|
||||
FTRACE_OPS_FL_SAVE_REGS |
|
||||
#endif
|
||||
FTRACE_OPS_FL_IPMODIFY |
|
||||
FTRACE_OPS_FL_PERMANENT;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user