When livepatch is attached to the same function as bpf trampoline with
a fexit program, bpf trampoline code calls register_ftrace_direct()
twice. The first time will fail with -EAGAIN, and the second time it
will succeed. This requires register_ftrace_direct() to unregister
the address on the first attempt. Otherwise, the bpf trampoline cannot
attach. Here is an easy way to reproduce this issue:

  insmod samples/livepatch/livepatch-sample.ko
  bpftrace -e 'fexit:cmdline_proc_show {}'
  ERROR: Unable to attach probe: fexit:vmlinux:cmdline_proc_show...

Fix this by cleaning up the hash when register_ftrace_function_nolock hits
errors.

Also, move the code that resets ops->func and ops->trampoline to
the error path of register_ftrace_direct().

Fixes: d05cb470663a ("ftrace: Fix modification of direct_function hash while in 
use")
Cc: [email protected] # v6.6+
Reported-by: Andrey Grodzovsky <[email protected]>
Closes: 
https://lore.kernel.org/live-patching/[email protected]/
Cc: Steven Rostedt (Google) <[email protected]>
Cc: Masami Hiramatsu (Google) <[email protected]>
Acked-and-tested-by: Andrey Grodzovsky <[email protected]>
Signed-off-by: Song Liu <[email protected]>
---
 kernel/bpf/trampoline.c | 5 -----
 kernel/trace/ftrace.c   | 6 ++++++
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 5949095e51c3..f2cb0b097093 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -479,11 +479,6 @@ static int bpf_trampoline_update(struct bpf_trampoline 
*tr, bool lock_direct_mut
                 * BPF_TRAMP_F_SHARE_IPMODIFY is set, we can generate the
                 * trampoline again, and retry register.
                 */
-               /* reset fops->func and fops->trampoline for re-register */
-               tr->fops->func = NULL;
-               tr->fops->trampoline = 0;
-
-               /* free im memory and reallocate later */
                bpf_tramp_image_free(im);
                goto again;
        }
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 42bd2ba68a82..725c224fb4e6 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6048,6 +6048,12 @@ int register_ftrace_direct(struct ftrace_ops *ops, 
unsigned long addr)
        ops->direct_call = addr;
 
        err = register_ftrace_function_nolock(ops);
+       if (err) {
+               /* cleanup for possible another register call */
+               ops->func = NULL;
+               ops->trampoline = 0;
+               remove_direct_functions_hash(hash, addr);
+       }
 
  out_unlock:
        mutex_unlock(&direct_mutex);
-- 
2.47.3


Reply via email to