Forwarded: [PATCH] bpf: Fix use-after-free in bpf_raw_tp_link_release

From: syzbot

Date: Sat Feb 21 2026 - 05:45:34 EST


For archival purposes, forwarding an incoming command email to
linux-kernel@xxxxxxxxxxxxxxx, syzkaller-bugs@xxxxxxxxxxxxxxxx.

***

Subject: [PATCH] bpf: Fix use-after-free in bpf_raw_tp_link_release
Author: kartikey406@xxxxxxxxx

#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master


When a BPF raw tracepoint link is released, bpf_raw_tp_link_release()
calls bpf_probe_unregister(), which internally calls
tracepoint_probe_unregister(). This function performs an RCU-deferred
swap of the tracepoint's funcs array via call_rcu(), so that existing
readers can finish observing the old array before it is replaced.

However, the subsequent call_rcu() in bpf_link_put_direct() that
invokes bpf_raw_tp_link_dealloc() can complete concurrently with the
tracepoint's internal grace period. When this happens, kfree(raw_tp)
runs while RCU readers can still reach the link via the old funcs
array, causing a use-after-free in __bpf_trace_run() when it
dereferences link->link.prog.

Fix this by calling synchronize_rcu() after bpf_probe_unregister() in
bpf_raw_tp_link_release(). This ensures all pre-existing readers that
may still be executing __bpf_trace_run() with a pointer to this link
have finished before we return. The subsequent call_rcu() for dealloc
will then fire only after the link is truly unreachable, making the
kfree() safe.

Reported-by: syzbot+59701a78e84b0bccfe1b@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=59701a78e84b0bccfe1b
Signed-off-by: Deepanshu Kartikey <kartikey406@xxxxxxxxx>
---
kernel/bpf/syscall.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index dd89bf809772..e636a2022e54 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -3782,6 +3782,7 @@ static void bpf_raw_tp_link_release(struct bpf_link *link)
container_of(link, struct bpf_raw_tp_link, link);

bpf_probe_unregister(raw_tp->btp, raw_tp);
+ synchronize_rcu();
bpf_put_raw_tracepoint(raw_tp->btp);
}

--
2.43.0