On Thu, Jun 18, 2026 at 5:27 PM Tamir Duberstein <[email protected]> wrote: > > User ring buffer positions are unsigned long counters, but > __bpf_user_ringbuf_peek() widens them to u64 before comparing and > subtracting them. On 32-bit systems, producer_pos wrapping below > consumer_pos therefore appears to move backwards and permanently stalls > the ring. The widened subtraction can also bypass the advertised-window > check. > > Keep the positions word-sized and derive the available data with > word-sized subtraction so the arithmetic wraps with the counters. Treat > a zero span as empty and reject spans larger than the ring before > reading a record header. > > Fixes: 205715673844 ("bpf: Add bpf_user_ringbuf_drain() helper") > Reported-by: Sashiko <[email protected]> > Closes: > https://lore.kernel.org/bpf/[email protected]/ > Assisted-by: Codex:gpt-5.5 > Signed-off-by: Tamir Duberstein <[email protected]> > --- > kernel/bpf/ringbuf.c | 9 ++++++--- > 1 file changed, 6 insertions(+), 3 deletions(-) > > diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c > index 909880031fd3..19cbb9b74ee7 100644 > --- a/kernel/bpf/ringbuf.c > +++ b/kernel/bpf/ringbuf.c > @@ -748,9 +748,9 @@ const struct bpf_func_proto > bpf_ringbuf_discard_dynptr_proto = { > > static int __bpf_user_ringbuf_peek(struct bpf_ringbuf *rb, void **sample, > u32 *size) > { > + unsigned long avail, cons_pos, prod_pos; > int err; > u32 hdr_len, sample_len, total_len, flags, *hdr; > - u64 cons_pos, prod_pos; > > /* Synchronizes with smp_store_release() in user-space producer. */ > prod_pos = smp_load_acquire(&rb->producer_pos); > @@ -759,8 +759,11 @@ 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) > + avail = prod_pos - cons_pos; > + if (!avail) > return -ENODATA; > + if (avail > ringbuf_total_data_sz(rb)) > + return -EINVAL;
hm, should we use long and then replace cons_pos >= prod_pos checks with `cons_pos - prod_pos >= 0`, this will handle wrap correctly > > hdr = (u32 *)((uintptr_t)rb->data + (uintptr_t)(cons_pos & rb->mask)); > /* Synchronizes with smp_store_release() in user-space producer. */ > @@ -770,7 +773,7 @@ static int __bpf_user_ringbuf_peek(struct bpf_ringbuf > *rb, void **sample, u32 *s > total_len = round_up(sample_len + BPF_RINGBUF_HDR_SZ, 8); > > /* The sample must fit within the region advertised by the producer > position. */ > - if (total_len > prod_pos - cons_pos) > + if (total_len > avail) > return -EINVAL; > > /* The sample must fit within the data region of the ring buffer. */ > > -- > 2.55.0.rc0.159.gbe5d7338c2 >

