kernel/bpf/cpumap.c | 4 +++- kernel/bpf/devmap.c | 3 ++- net/xdp/xsk.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-)
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
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
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.
> 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
© 2016 - 2026 Red Hat, Inc.