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

From: Peter Zijlstra
Date: Wed Mar 02 2022 - 15:52:23 EST


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.