Patch 1 is v1 with the (long) cast dropped, as requested: pending_pos never
runs ahead of producer_pos, so the unsigned difference is the real distance.
While looking for other places where these positions are compared as values
rather than as distances, three more turned up; patches 2-4 fix those. All
four are the same class of bug: the positions are unsigned long, they wrap at
2^32 on 32-bit architectures, Documentation/bpf/ringbuf.rst says that wrap is
expected, and therefore every comparison between them has to be written as a
difference.
Patch 1 is the one that bites in the field: four armv7 devices stopped
delivering events after exactly 4295491360 bytes had passed through a 512 KiB
ring, and with it applied one of them has since taken 10 GiB through the same
ring with no stall.
Patches 2 and 3 are both in ringbuf_avail_data_sz(). The first replaces the
max() of two positions with a comparison of their distances to producer_pos;
the second reads producer_pos before overwrite_pos, which is the order that
__bpf_ringbuf_reserve() documents as the one the consumer must use. Patch 4 is
the userspace counterpart of patch 1, in libbpf's consumer loop.
The review also pointed at __bpf_user_ringbuf_peek(), where cons_pos and
prod_pos are u64 locals loaded from unsigned long fields, so on 32-bit they
never wrap and 'cons_pos >= prod_pos' stops working. That one is not part of
this series: it is the user-space-producer ring, where producer_pos is
untrusted input, so making it wrap-safe also means re-deriving the bounds
checks that keep the kernel safe there, which is a change of a different
nature from these four.
v1: https://lore.kernel.org/bpf/20260806130214.66028-1-i.tellez@btesa.com/
v2:
- patch 1: drop the (long) cast (Andrii Nakryiko)
- patches 2-4: new, the other 32-bit wrap sites found while reviewing the
rest of the file and libbpf
Israel Téllez García (4):
bpf: Fix pending_pos walk on 32-bit ring position wrap
bpf: Fix available-data accounting on 32-bit wrap in overwrite mode
bpf: Read producer_pos before overwrite_pos in ringbuf_avail_data_sz()
libbpf: Fix ring buffer consumer loop on 32-bit position wrap
kernel/bpf/ringbuf.c | 12 +++++++++---
tools/lib/bpf/ringbuf.c | 2 +-
2 files changed, 10 insertions(+), 4 deletions(-)
--
2.39.5