diff --git a/kernel/bpf/wakeup_source_iter.c b/kernel/bpf/wakeup_source_iter.c new file mode 100644 index 000000000000..ab83d212a1f9 --- /dev/null +++ b/kernel/bpf/wakeup_source_iter.c
[ ... ]
+static void *wakeup_source_iter_seq_start(struct seq_file *seq, loff_t *pos) +{
- int *srcuidx = seq->private;
- struct wakeup_source *ws;
- loff_t i;
- *srcuidx = wakeup_sources_read_lock();
- ws = wakeup_sources_walk_start();
- for (i = 0; ws && i < *pos; i++)
ws = wakeup_sources_walk_next(ws);- return ws;
+}
What happens when the wakeup_sources list is empty?
wakeup_sources_walk_start() uses list_entry_rcu(ws_head->next, ...) which does not check for an empty list. When the list is empty, ws_head->next points back to ws_head itself, so list_entry_rcu() computes a pointer to memory before the static list head, resulting in an invalid pointer.
The loop condition (ws && i < *pos) does not execute when *pos is 0, so this invalid pointer is returned directly. Unlike the existing debugfs implementation wakeup_sources_stats_seq_start() which uses list_for_each_entry_rcu_locked() and properly returns NULL for an empty list, this function returns a non-NULL invalid pointer.
The BPF iterator framework in bpf_seq_read() checks if (!p) goto stop, but since the invalid pointer is non-NULL, this check passes and the show callback is invoked with the invalid pointer. Could this pass garbage memory to the BPF program?
The for_each_wakeup_source() macro might mask this issue because wakeup_sources_walk_next() on this invalid pointer will return NULL, but the seq_file framework calls show() before next(), so the first invocation receives the invalid pointer.
--- 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/20835022582