Re: [PATCH v2 12/39] x86/ibt,ftrace: Search for __fentry__ location

From: Naveen N. Rao
Date: Thu Mar 03 2022 - 04:46:01 EST


Peter Zijlstra wrote:
On Wed, Mar 02, 2022 at 02:47:16PM -0500, Steven Rostedt wrote:
Note, I just pulled this patch, and I hit this warning:

WARNING: CPU: 0 PID: 6965 at arch/x86/kernel/kprobes/core.c:205 recover_probed_instruction+0x8f/0xa0

static unsigned long
__recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)
{
struct kprobe *kp;
unsigned long faddr;

kp = get_kprobe((void *)addr);
faddr = ftrace_location(addr);
/*
* Addresses inside the ftrace location are refused by
* arch_check_ftrace_location(). Something went terribly wrong
* if such an address is checked here.
*/
if (WARN_ON(faddr && faddr != addr)) <<---- HERE
return 0UL;

Ha! so a bunch of IRC later I figured out how it is possible you hit
this with just the patch on and how I legitimately hit this and what to
do about it.

Your problem seems to be that we got ftrace_location() wrong in that
lookup_rec()'s end argument is inclusive, hence we need:

lookup_rec(ip, ip + size - 1)

Now, the above thing asserts that:

ftrace_location(x) == {0, x}

and that is genuinely false in my case, I get x+4 as additional possible
output. So I think I need the below change to go on top of all I have:


diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 7f0ce42f8ff9..4c13406e0bc4 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -198,13 +198,14 @@ __recover_probed_insn(kprobe_opcode_t *buf, unsigned long addr)

kp = get_kprobe((void *)addr);
faddr = ftrace_location(addr);
+
/*
- * Addresses inside the ftrace location are refused by
- * arch_check_ftrace_location(). Something went terribly wrong
- * if such an address is checked here.
+ * In case addr maps to sym+0 ftrace_location() might return something
+ * other than faddr. In that case consider it the same as !faddr.
*/
- if (WARN_ON(faddr && faddr != addr))
- return 0UL;
+ if (faddr && faddr != addr)
+ faddr = 0;
+
/*
* Use the current code if it is not modified by Kprobe
* and it cannot be modified by ftrace.

I hit this issue yesterday in kprobe generic code in check_ftrace_location(). In both these scenarios, we just want to check if a particular instruction is reserved by ftrace. ftrace_location_range() should still work for that purpose, so that may be the easier fix:

diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 066fa644e9dfa3..ee3cd035403ca2 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -1596,7 +1596,7 @@ static int check_ftrace_location(struct kprobe *p)
{
unsigned long ftrace_addr;

- ftrace_addr = ftrace_location((unsigned long)p->addr);
+ ftrace_addr = ftrace_location_range((unsigned long)p->addr, (unsigned long)p->addr);
if (ftrace_addr) {
#ifdef CONFIG_KPROBES_ON_FTRACE
/* Given address is not on the instruction boundary */



- Naveen