[PATCH] bpf: Fix NULL deref in __list_del_clearprev for flush_node

donglaipang@126.com posted 1 patch 1 month, 3 weeks ago
kernel/bpf/cpumap.c | 4 +++-
kernel/bpf/devmap.c | 3 ++-
net/xdp/xsk.c       | 3 ++-
3 files changed, 7 insertions(+), 3 deletions(-)
[PATCH] bpf: Fix NULL deref in __list_del_clearprev for flush_node
Posted by donglaipang@126.com 1 month, 3 weeks ago
From: DLpang <donglaipang@126.com>

#syz test

Hi,

This patch fixes a NULL pointer dereference in the BPF subsystem that occurs
when __list_del_clearprev() is called on an already-cleared flush_node list_head.

The fix includes two parts:
1. Properly initialize the flush_node list_head during per-CPU bulk queue allocation
   using INIT_LIST_HEAD(&bq->flush_node)
2. Add defensive checks before calling __list_del_clearprev() to ensure the node
   is actually in the list by checking if (bq->flush_node.prev)

According to the __list_del_clearprev documentation in include/linux/list.h,
'The code that uses this needs to check the node 'prev' pointer instead of calling list_empty()'.

This patch fixes the following syzbot-reported issue:
https://syzkaller.appspot.com/bug?extid=2b3391f44313b3983e91

Reported-by: syzbot+2b3391f44313b3983e91@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=2b3391f44313b3983e91
Signed-off-by: DLpang <donglaipang@126.com>
---
 kernel/bpf/cpumap.c | 4 +++-
 kernel/bpf/devmap.c | 3 ++-
 net/xdp/xsk.c       | 3 ++-
 3 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
index 703e5df1f4ef..248336df591a 100644
--- a/kernel/bpf/cpumap.c
+++ b/kernel/bpf/cpumap.c
@@ -450,6 +450,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
 
 	for_each_possible_cpu(i) {
 		bq = per_cpu_ptr(rcpu->bulkq, i);
+		INIT_LIST_HEAD(&bq->flush_node);
 		bq->obj = rcpu;
 	}
 
@@ -737,7 +738,8 @@ static void bq_flush_to_queue(struct xdp_bulk_queue *bq)
 	bq->count = 0;
 	spin_unlock(&q->producer_lock);
 
-	__list_del_clearprev(&bq->flush_node);
+	if (bq->flush_node.prev)
+		__list_del_clearprev(&bq->flush_node);
 
 	/* Feedback loop via tracepoints */
 	trace_xdp_cpumap_enqueue(rcpu->map_id, processed, drops, to_cpu);
diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
index 2625601de76e..7a7347e709cc 100644
--- a/kernel/bpf/devmap.c
+++ b/kernel/bpf/devmap.c
@@ -428,7 +428,8 @@ void __dev_flush(struct list_head *flush_list)
 		bq_xmit_all(bq, XDP_XMIT_FLUSH);
 		bq->dev_rx = NULL;
 		bq->xdp_prog = NULL;
-		__list_del_clearprev(&bq->flush_node);
+		if (bq->flush_node.prev)
+			__list_del_clearprev(&bq->flush_node);
 	}
 }
 
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index f093c3453f64..052b8583542d 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -406,7 +406,8 @@ void __xsk_map_flush(struct list_head *flush_list)
 
 	list_for_each_entry_safe(xs, tmp, flush_list, flush_node) {
 		xsk_flush(xs);
-		__list_del_clearprev(&xs->flush_node);
+		if (xs->flush_node.prev)
+			__list_del_clearprev(&xs->flush_node);
 	}
 }
 
-- 
2.43.0
Re: [PATCH] bpf: Fix NULL deref in __list_del_clearprev for flush_node
Posted by Alexei Starovoitov 1 month, 3 weeks ago
On Mon, Dec 15, 2025 at 7:14 PM <donglaipang@126.com> wrote:
>
> From: DLpang <donglaipang@126.com>
>
> #syz test
>
> Hi,
>
> This patch fixes a NULL pointer dereference in the BPF subsystem that occurs
> when __list_del_clearprev() is called on an already-cleared flush_node list_head.
>
> The fix includes two parts:
> 1. Properly initialize the flush_node list_head during per-CPU bulk queue allocation
>    using INIT_LIST_HEAD(&bq->flush_node)
> 2. Add defensive checks before calling __list_del_clearprev() to ensure the node
>    is actually in the list by checking if (bq->flush_node.prev)
>
> According to the __list_del_clearprev documentation in include/linux/list.h,
> 'The code that uses this needs to check the node 'prev' pointer instead of calling list_empty()'.
>
> This patch fixes the following syzbot-reported issue:
> https://syzkaller.appspot.com/bug?extid=2b3391f44313b3983e91
>
> Reported-by: syzbot+2b3391f44313b3983e91@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=2b3391f44313b3983e91
> Signed-off-by: DLpang <donglaipang@126.com>

If you're going to throw AI slop at us, please do your homework
and root cause the issue.
Nothing in this AI generated commit log explains the bug.

pw-bot: cr
Re: [syzbot] [net?] [bpf?] general protection fault in bq_flush_to_queue (2)
Posted by syzbot 1 month, 3 weeks ago
Hello,

syzbot has tested the proposed patch and the reproducer did not trigger any issue:

Reported-by: syzbot+2b3391f44313b3983e91@syzkaller.appspotmail.com
Tested-by: syzbot+2b3391f44313b3983e91@syzkaller.appspotmail.com

Tested on:

commit:         8f0b4cce Linux 6.19-rc1
git tree:       upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=137ab91a580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=412fc3ec22077a03
dashboard link: https://syzkaller.appspot.com/bug?extid=2b3391f44313b3983e91
compiler:       Debian clang version 20.1.8 (++20250708063551+0c9f909b7976-1~exp1~20250708183702.136), Debian LLD 20.1.8
patch:          https://syzkaller.appspot.com/x/patch.diff?x=10be172c580000

Note: testing is done by a robot and is best-effort only.
Re: [PATCH] bpf: Fix NULL deref in __list_del_clearprev for flush_node
Posted by bot+bpf-ci@kernel.org 1 month, 3 weeks ago
> diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c
> index 04171fbc39cb..6ab6eae31989 100644
> --- a/kernel/bpf/cpumap.c
> +++ b/kernel/bpf/cpumap.c
> @@ -450,6 +450,7 @@ __cpu_map_entry_alloc(struct bpf_map *map, struct bpf_cpumap_val *value,
>
>  	for_each_possible_cpu(i) {
>  		bq = per_cpu_ptr(rcpu->bulkq, i);
> +		INIT_LIST_HEAD(&bq->flush_node);
>  		bq->obj = rcpu;
>  	}
>

[ ... ]

> diff --git a/kernel/bpf/devmap.c b/kernel/bpf/devmap.c
> index 2625601de76e..7a7347e709cc 100644
> --- a/kernel/bpf/devmap.c
> +++ b/kernel/bpf/devmap.c
> @@ -428,7 +428,8 @@ void __dev_flush(struct list_head *flush_list)
>  		bq_xmit_all(bq, XDP_XMIT_FLUSH);
>  		bq->dev_rx = NULL;
>  		bq->xdp_prog = NULL;
> -		__list_del_clearprev(&bq->flush_node);
> +		if (bq->flush_node.prev)
> +			__list_del_clearprev(&bq->flush_node);
                ^^^^

The devmap code adds the same defensive check but doesn't initialize
flush_node the way cpumap does. Looking at dev_map_notification(), when
NETDEV_REGISTER occurs, it calls:

    alloc_percpu(struct xdp_dev_bulk_queue)

And then only initializes the dev field:

    per_cpu_ptr(netdev->xdp_bulkq, cpu)->dev = netdev;

Without INIT_LIST_HEAD(&bq->flush_node), if alloc_percpu() returns
memory with non-zero bytes, bq->flush_node.prev could contain garbage.

The enqueue path in bq_enqueue() uses:

    if (!bq->dev_rx)
        list_add(&bq->flush_node, flush_list);

So if dev_rx contains non-zero garbage, the node never gets added to the
list. But this flush code checks bq->flush_node.prev which could also be
garbage, causing __list_del_clearprev() to be called with invalid
pointers.

Does devmap need INIT_LIST_HEAD(&bq->flush_node) similar to cpumap? The
commit message states that initialization is part of the fix, but only
cpumap gets it.

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/20255377282