On Thu, Nov 12, 2026 at 7:57 PM Kang Chen k.chen@smail.nju.edu.cn wrote:
bpf_iter_dmabuf_next() uses kit->dmabuf == NULL to mean "iteration has not started". dma_buf_iter_next() also returns NULL at the end of the list, so a next() call after exhaustion restarts from the list head.
The verifier relies on the iterator contract that once next() returns NULL it keeps returning NULL: process_iter_next_call() marks the iterator DRAINED and treats the result of later next() calls as the constant zero. A restarted dmabuf iteration therefore hands the BPF program a kernel pointer while the verifier believes R0 == 0.
NULL now means drained. Initialize the state to DMABUF_ITER_START and translate it to dma_buf_iter_begin() on the first next(). The iterator state is BPF-visible ABI (one pointer wide), so use an invalid pointer sentinel instead of growing it.
Fixes: 6eab7ac7c5ee ("bpf: Add open coded dmabuf iterator") Signed-off-by: Kang Chen k.chen@smail.nju.edu.cn
Reviewed-by: T.J. Mercier tjmercier@google.com
v3:
- No change from v2; reposted with the updated 2/2 attribution.
kernel/bpf/dmabuf_iter.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/dmabuf_iter.c b/kernel/bpf/dmabuf_iter.c index cd500248abd9..390f6d730a67 100644 --- a/kernel/bpf/dmabuf_iter.c +++ b/kernel/bpf/dmabuf_iter.c @@ -156,6 +156,9 @@ struct bpf_iter_dmabuf_kern { struct dma_buf *dmabuf; } __aligned(8);
+/* NULL means drained; START means "not started yet". */ +#define DMABUF_ITER_START ((struct dma_buf *)1L)
__bpf_kfunc_start_defs();
__bpf_kfunc int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it) @@ -165,7 +168,7 @@ __bpf_kfunc int bpf_iter_dmabuf_new(struct bpf_iter_dmabuf *it) BUILD_BUG_ON(sizeof(*kit) > sizeof(*it)); BUILD_BUG_ON(__alignof__(*kit) != __alignof__(*it));
kit->dmabuf = NULL;
kit->dmabuf = DMABUF_ITER_START; return 0;}
@@ -173,10 +176,14 @@ __bpf_kfunc struct dma_buf *bpf_iter_dmabuf_next(struct bpf_iter_dmabuf *it) { struct bpf_iter_dmabuf_kern *kit = (void *)it;
if (kit->dmabuf)kit->dmabuf = dma_buf_iter_next(kit->dmabuf);else
/* Once NULL is returned, next() has to keep returning NULL. */if (!kit->dmabuf)return NULL;if (kit->dmabuf == DMABUF_ITER_START) kit->dmabuf = dma_buf_iter_begin();elsekit->dmabuf = dma_buf_iter_next(kit->dmabuf); return kit->dmabuf;} @@ -185,7 +192,7 @@ __bpf_kfunc void bpf_iter_dmabuf_destroy(struct bpf_iter_dmabuf *it) { struct bpf_iter_dmabuf_kern *kit = (void *)it;
if (kit->dmabuf)
if (kit->dmabuf && kit->dmabuf != DMABUF_ITER_START) dma_buf_put(kit->dmabuf);}
-- 2.34.1