Re: [PATCH bpf v2] bpf: fix NULL pointer dereference in bpf_task_from_vpid()

From: Yonghong Song

Date: Fri Jun 05 2026 - 23:14:14 EST




On 6/5/26 1:04 PM, Sechang Lim wrote:
bpf_task_from_vpid() looks up a task in the pid namespace of the
current task, via find_task_by_vpid():

find_task_by_vpid(vpid)
find_task_by_pid_ns(vpid, task_active_pid_ns(current))
find_pid_ns(nr, ns) -> idr_find(&ns->idr, nr)

cgroup_skb programs run in softirq, which may interrupt a task that is
itself in do_exit(). Once that task has passed
exit_notify() -> release_task() -> __unhash_process(), its thread_pid is
cleared, so task_active_pid_ns(current) returns NULL and find_pid_ns()
dereferences &NULL->idr:

BUG: kernel NULL pointer dereference, address: 0000000000000050
RIP: 0010:idr_find+0x11/0x30 lib/idr.c:176
Call Trace:
<IRQ>
find_pid_ns kernel/pid.c:370 [inline]
find_task_by_pid_ns+0x3b/0xe0 kernel/pid.c:485
bpf_task_from_vpid+0x5b/0x200 kernel/bpf/helpers.c:2916
bpf_prog_run_array_cg+0x17e/0x530 kernel/bpf/cgroup.c:81
__cgroup_bpf_run_filter_skb+0x12b/0x250 kernel/bpf/cgroup.c:1612
sk_filter_trim_cap+0x1dc/0x4c0 net/core/filter.c:148
tcp_v4_rcv+0x18d1/0x2200 net/ipv4/tcp_ipv4.c:2223
</IRQ>
<TASK>
do_exit+0xa63/0x1270 kernel/exit.c:1010
get_signal+0x141c/0x1530 kernel/signal.c:3037

Return NULL when called from interrupt context.

Suggested-by: Yonghong Song <yonghong.song@xxxxxxxxx>
Fixes: 675c3596ff32 ("bpf: Add bpf_task_from_vpid() kfunc")
Signed-off-by: Sechang Lim <rhkrqnwk98@xxxxxxxxx>
---
v2:
- Reject calls from interrupt context (Yonghong Song)

v1:
- https://lore.kernel.org/bpf/20260603204206.773482-1-rhkrqnwk98@xxxxxxxxx/

kernel/bpf/helpers.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b5314c9fed3c..890202361b53 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -2912,6 +2912,9 @@ __bpf_kfunc struct task_struct *bpf_task_from_vpid(s32 vpid)
{
struct task_struct *p;
+ if (in_interrupt())
+ return NULL;
+

AI suggested we should have

rcu_read_lock();
+ if (!task_active_pid_ns(current)) { + rcu_read_unlock(); + return NULL; + } p = find_task_by_vpid(vpid);

too. I was aware of this in v1 and throught it is very unlikely
as the tracing prog will need to hook into a few functions
after current->thread_pid to be NULL and we may skip it.

But the unlikely does not mean it won't happen, so let us
just add your change in v1 as well. With this,

Acked-by: Yonghong Song <yonghong.song@xxxxxxxxx>

rcu_read_lock();
p = find_task_by_vpid(vpid);
if (p)