[PATCH v2 bpf 0/4] bpf: Fix ring buffer position wrap handling on 32-bit
Israel Téllez García <[email protected]>
| Newsgroups | org.kernel.vger.bpf,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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/[email protected]/ 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