Thread (8 messages) read the whole thread 8 messages, 4 authors, 2025-02-25

Re: [PATCH v3 tip/perf/core 2/2] uprobes: SRCU-protect uretprobe lifetime (with timeout)

From: "Paul E. McKenney" <paulmck@kernel.org>
Date: 2025-02-25 15:13:55
Also in: bpf, lkml

On Tue, Feb 25, 2025 at 03:46:53AM -0800, Breno Leitao wrote:
Hello Andrii,

On Mon, Feb 24, 2025 at 02:23:51PM -0800, Andrii Nakryiko wrote:
quoted
On Mon, Feb 24, 2025 at 4:23 AM Breno Leitao [off-list ref] wrote:
quoted
Hello Andrii,

On Wed, Oct 23, 2024 at 09:41:59PM -0700, Andrii Nakryiko wrote:
quoted
+static struct uprobe* hprobe_expire(struct hprobe *hprobe, bool get)
+{
+     enum hprobe_state hstate;
+
+     /*
+      * return_instance's hprobe is protected by RCU.
+      * Underlying uprobe is itself protected from reuse by SRCU.
+      */
+     lockdep_assert(rcu_read_lock_held() && srcu_read_lock_held(&uretprobes_srcu));
I am hitting this warning in d082ecbc71e9e ("Linux 6.14-rc4") on
aarch64. I suppose this might happen on x86 as well, but I haven't
tested.

        WARNING: CPU: 28 PID: 158906 at kernel/events/uprobes.c:768 hprobe_expire (kernel/events/uprobes.c:825)

        Call trace:
        hprobe_expire (kernel/events/uprobes.c:825) (P)
        uprobe_copy_process (kernel/events/uprobes.c:691 kernel/events/uprobes.c:2103 kernel/events/uprobes.c:2142)
        copy_process (kernel/fork.c:2636)
        kernel_clone (kernel/fork.c:2815)
        __arm64_sys_clone (kernel/fork.c:? kernel/fork.c:2926 kernel/fork.c:2926)
        invoke_syscall (arch/arm64/kernel/syscall.c:35 arch/arm64/kernel/syscall.c:49)
        do_el0_svc (arch/arm64/kernel/syscall.c:139 arch/arm64/kernel/syscall.c:151)
        el0_svc (arch/arm64/kernel/entry-common.c:165 arch/arm64/kernel/entry-common.c:178 arch/arm64/kernel/entry-common.c:745)
        el0t_64_sync_handler (arch/arm64/kernel/entry-common.c:797)
        el0t_64_sync (arch/arm64/kernel/entry.S:600)

I broke down that warning, and the problem is on related to
rcu_read_lock_held(), since RCU read lock does not seem to be held in
this path.

Reading this code, RCU read lock seems to protect old hprobe, which
doesn't seem so.

I am wondering if we need to protect it properly, something as:

        @@ -2089,7 +2092,9 @@ static int dup_utask(struct task_struct *t, struct uprobe_task *o_utask)
                                return -ENOMEM;

                        /* if uprobe is non-NULL, we'll have an extra refcount for uprobe */
        +               rcu_read_lock();
                        uprobe = hprobe_expire(&o->hprobe, true);
        +               rcu_write_lock();
I think this is not good enough. rcu_read_lock/unlock should be around
the entire for loop, because, technically, that return_instance can be
freed before we even get to hprobe_expire.
re you suggesting that we should use an RCU read lock to protect the
"traversal" of return_instances? In other words, is it currently being
traversed unsafely, given that return_instance can be freed at any time?
quoted
So, just like we have guard(srcu)(&uretprobes_srcu); we should have
guard(rcu)();

Except, there is that kmemdup() hidden inside dup_return_instance(),
so we can't really do that.
Right. kmemdup() is using GFP_KERNEL, which might sleep, so, it cannot
be called using rcu read lock.
There is always SRCU?

							Thanx, Paul
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help