[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.