mainline inclusion from mainline-v5.16-rc1 commit 03bac0df2886882c43e6d0bfff9dee84a184fc7e category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I9R2TB
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
------------------------------------------------------
Introduce kretprobe_find_ret_addr() and is_kretprobe_trampoline(). These APIs will be used by the ORC stack unwinder and ftrace, so that they can check whether the given address points kretprobe trampoline code and query the correct return address in that case.
Signed-off-by: Masami Hiramatsu mhiramat@kernel.org Tested-by: Andrii Nakryiko andrii@kernel.org Signed-off-by: Steven Rostedt (VMware) rostedt@goodmis.org Conflicts: include/linux/kprobes.h kernel/kprobes.c [Reimplement kretprobe_find_ret_addr() and is_kretprobe_trampoline() without the dependcy commit d741bf41d7c7 ("kprobes: Remove kretprobe hash") and other refactors since those are too many changes] Signed-off-by: Zheng Yejian zhengyejian1@huawei.com --- include/linux/kprobes.h | 16 ++++++++++++++++ kernel/kprobes.c | 23 +++++++++++++++++++++++ 2 files changed, 39 insertions(+)
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index e2713fe9c100..28a6e871dac6 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -200,6 +200,12 @@ extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs); extern int arch_trampoline_kprobe(struct kprobe *p);
+void kretprobe_trampoline(void); +static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr) +{ + return !in_nmi() && (void *)addr == &kretprobe_trampoline; +} + /* If the trampoline handler called from a kprobe, use this version */ unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs, void *trampoline_address, @@ -223,6 +229,7 @@ unsigned long kretprobe_trampoline_handler(struct pt_regs *regs, return ret; }
+unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp); #else /* CONFIG_KRETPROBES */ static inline void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs) @@ -232,6 +239,15 @@ static inline int arch_trampoline_kprobe(struct kprobe *p) { return 0; } +static nokprobe_inline bool is_kretprobe_trampoline(unsigned long addr) +{ + return false; +} +static nokprobe_inline +unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp) +{ + return 0; +} #endif /* CONFIG_KRETPROBES */
extern struct kretprobe_blackpoint kretprobe_blacklist[]; diff --git a/kernel/kprobes.c b/kernel/kprobes.c index f83b8b6b829f..0ad524beaba2 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1984,6 +1984,29 @@ unsigned long __weak arch_deref_entry_point(void *entry)
#ifdef CONFIG_KRETPROBES
+unsigned long kretprobe_find_ret_addr(struct task_struct *tsk, void *fp) +{ + struct kretprobe_instance *ri = NULL; + struct hlist_head *head; + unsigned long flags; + kprobe_opcode_t *correct_ret_addr = NULL; + + kretprobe_hash_lock(tsk, &head, &flags); + hlist_for_each_entry(ri, head, hlist) { + if (ri->task != tsk) + continue; + if (ri->fp != fp) + continue; + if (!is_kretprobe_trampoline((unsigned long)ri->ret_addr)) { + correct_ret_addr = ri->ret_addr; + break; + } + } + kretprobe_hash_unlock(tsk, &flags); + return (unsigned long)correct_ret_addr; +} +NOKPROBE_SYMBOL(kretprobe_find_ret_addr); + unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs, void *trampoline_address, void *frame_pointer)