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
>

Reply via email to