Commit 88fef946 authored by Zheng Yejian's avatar Zheng Yejian
Browse files

kprobes: Add kretprobe_find_ret_addr() for searching return address

mainline inclusion
from mainline-v5.16-rc1
commit 03bac0df
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I9R2TB

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=03bac0df2886882c43e6d0bfff9dee84a184fc7e



------------------------------------------------------

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: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Tested-by: default avatarAndrii Nakryiko <andrii@kernel.org>
Signed-off-by: default avatarSteven 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 d741bf41 ("kprobes: Remove kretprobe
hash") and other refactors since those are too many changes]
Signed-off-by: default avatarZheng Yejian <zhengyejian1@huawei.com>
parent fe25ad14
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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[];
+23 −0
Original line number Diff line number Diff line
@@ -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)