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

From: Yonghong Song

Date: Fri Jun 05 2026 - 13:06:30 EST




On 6/3/26 1:42 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

Bail out when current has no pid namespace.

Fixes: 675c3596ff32 ("bpf: Add bpf_task_from_vpid() kfunc")
Signed-off-by: Sechang Lim <rhkrqnwk98@xxxxxxxxx>
---
kernel/bpf/helpers.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c
index b5314c9fed3c..4646a915bf98 100644
--- a/kernel/bpf/helpers.c
+++ b/kernel/bpf/helpers.c
@@ -2913,6 +2913,10 @@ __bpf_kfunc struct task_struct *bpf_task_from_vpid(s32 vpid)
struct task_struct *p;
rcu_read_lock();
+ if (!task_active_pid_ns(current)) {
+ rcu_read_unlock();
+ return NULL;
+ }

In softirq context, I think we should return NULL for this kfunc.
Your above fix solves crash problem. But even not crash, the
below task 'p' may not be user expected since the 'current' (and
its namespace) is random.

Maybe we can do:

+ if (in_interrupt())
+ return NULL;
+
rcu_read_lock();
...

In bpf selftest task_kfunc_success.c, all programs are 'syscall'
programs which garantees process context.

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