[PATCH bpf 2/2] bpf: Fix user ringbuf empty check on 32-bit position wrap
From: Igor Malovitsa
Date: Thu Oct 15 2026 - 20:35:27 EST
__bpf_user_ringbuf_peek() copies the unsigned long producer_pos and
consumer_pos into u64 locals and tests cons_pos >= prod_pos for an
empty ring. On 32-bit, once producer_pos wraps past 2^32 and
consumer_pos has not, every drain sees an empty ring and the user-space
producer gets -ENOSPC from then on. The fit check total_len >
prod_pos - cons_pos is wrong in the same state.
Keep the positions in unsigned long and test emptiness through their
difference, as the kernel-producer side does since commit 6ff5b56a50c5
("bpf: Fix pending_pos walk on 32-bit ring position wrap"). On 64-bit
nothing changes: unsigned long is u64, and the signed test differs from
cons_pos >= prod_pos only for positions 2^63 bytes apart.
Fixes: 205715673844 ("bpf: Add bpf_user_ringbuf_drain() helper")
Assisted-by: LLM
Signed-off-by: Igor Malovitsa <igor.malovitsa@xxxxxxxxx>
---
kernel/bpf/ringbuf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
index 6b86c4db5108..b79cc433d2c6 100644
--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -750,7 +750,7 @@ static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, u32 *s
{
int err;
u32 hdr_len, sample_len, total_len, flags, *hdr;
- u64 cons_pos, prod_pos;
+ unsigned long cons_pos, prod_pos;
/* Synchronizes with smp_store_release() in user-space producer. */
prod_pos = smp_load_acquire(&rb->producer_pos);
@@ -759,7 +759,7 @@ static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, u32 *s
/* Synchronizes with smp_store_release() in __bpf_user_ringbuf_sample_release() */
cons_pos = smp_load_acquire(&rb->consumer_pos);
- if (cons_pos >= prod_pos)
+ if ((long)(prod_pos - cons_pos) <= 0)
return -ENODATA;
hdr = (u32 *)((uintptr_t)rb->data + (uintptr_t)(cons_pos & rb->mask));
--
2.53.0