Re: [PATCH v6 2/2] ring-buffer: Improve nr_pages type

Vincent Donnefort <[email protected]>
Newsgroups org.kernel.vger.linux-trace-kernel,dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>
On Fri, Aug 14, 2026 at 03:59:44PM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
> 
> New issues:
> - [High] When `nr_pages` is exactly `U32_MAX - 1`, the expression `meta->nr_subbufs + 1` overflows to 0, silently skipping persistent ring buffer validation and wiping data.
> 
> Pre-existing issues:
> - [Critical] Loop counters iterating over `meta->nr_subbufs` are typed as `signed int`, which wrap to negative values for extremely large buffers, leading to out-of-bounds memory accesses.
> - [Critical] The `meta->nr_subbufs` field is read from potentially corrupted persistent memory and used without validation against `nr_pages`, causing a heap out-of-bounds write in `bitmap_clear()`.
> - [High] Multiplication of `subbuf_size` and `idx` overflows 32 bits for ring buffers > 4GB, causing severe memory aliasing.
> --
> 
> --- Patch [2]: [PATCH v6 2/2] ring-buffer: Improve nr_pages type ---
> commit 030ec6a7ceec6e71123077bd1fc64e0cf5c27cc8
> Author: Vincent Donnefort <[email protected]>
> 
> ring-buffer: Improve nr_pages type
> 
> If ring_buffer_per_cpu::nr_pages is defined as unsigned long, it is
> capped to 32-bits in a few places, limiting the operations possible on a
> very large buffer.
> 
> [ ... ]
> 
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index ec13779922ffb..ec127e2ad0527 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> 
> [ ... ]
> 
> > @@ -1746,8 +1745,8 @@ static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
> >  static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
> >  {
> >  	struct ring_buffer_cpu_meta *meta;
> > +	unsigned int subbuf_size;
> >  	unsigned long ptr;
> > -	int subbuf_size;
> >  
> >  	meta = rb_range_meta(cpu_buffer->buffer, 0, cpu_buffer->cpu);
> >  	if (!meta)
> 
> [Severity: High]
> This is a pre-existing issue, but does the multiplication of subbuf_size and
> idx overflow 32 bits for ring buffers larger than 4GB?
> 
> In rb_range_buffer(), we have:
> 
>     subbuf_size = meta->subbuf_size;
>     idx = meta->buffers[idx];
>     ptr = (unsigned long)rb_subbufs_from_meta(meta);
>     ptr += subbuf_size * idx;
> 
> Since subbuf_size is an unsigned int and idx is an int, the multiplication
> evaluates as a 32-bit unsigned integer. For ring buffers over 4GB, this can
> overflow and wrap around before being zero-extended and added to the 64-bit
> ptr, causing memory aliasing by overwriting earlier subbuffers.

I can add this to this patch/

> 
> [ ... ]
> 
> > @@ -1840,10 +1839,10 @@ static bool rb_meta_init(struct trace_buffer *buffer, int scratch_size)
> >   * must be the same.
> >   */
> >  static bool rb_cpu_meta_valid(struct ring_buffer_cpu_meta *meta, int cpu,
> > -			      struct trace_buffer *buffer, int nr_pages,
> > +			      struct trace_buffer *buffer, unsigned long nr_pages,
> >  			      unsigned long *subbuf_mask)
> >  {
> > -	int subbuf_size = PAGE_SIZE;
> > +	unsigned int subbuf_size = PAGE_SIZE;
> >  	unsigned long buffers_start;
> >  	unsigned long buffers_end;
> >  	int i;
> 
> [Severity: Critical]
> This is a pre-existing issue, but will loop counters iterating over
> meta->nr_subbufs wrap to negative values for extremely large buffers?
> 
> In rb_cpu_meta_valid():
> 
>     for (i = 0; i < meta->nr_subbufs; i++) {
>         if (meta->buffers[i] < 0 || ...
> 
> And in rb_range_meta_init():
> 
>     for (i = 0; i < meta->nr_subbufs; i++) {
>         meta->buffers[i] = i;
> 
> The loop counter i is a signed int. Since nr_pages can now go up to
> U32_MAX - 1, if the buffer size pushes meta->nr_subbufs past INT_MAX, i
> will wrap to negative. i < meta->nr_subbufs will promote i to unsigned,
> evaluating to true, and the negative index will be sign-extended on 64-bit
> architectures, causing out-of-bounds reads and writes.

Yeah sure, I'll make it unsigned int... doesn't sound too critical though!

> 
> [Severity: Critical]
> This is a pre-existing issue, but could meta->nr_subbufs cause a heap
> out-of-bounds write if it doesn't match nr_pages?
> 
> In rb_cpu_meta_valid():
> 
>     bitmap_clear(subbuf_mask, 0, meta->nr_subbufs);
> 
>     for (i = 0; i < meta->nr_subbufs; i++) {
>         ...
>         set_bit(meta->buffers[i], subbuf_mask);
> 
> meta->nr_subbufs is read directly from persistent memory and used without
> being validated against the dynamically allocated subbuf_mask size, which is
> based on nr_pages + 1. If meta->nr_subbufs is maliciously or accidentally set
> larger than nr_pages + 1, bitmap_clear() and set_bit() will write zeroes and
> ones past the end of the bitmap allocation.

Sure, but that'll be another patch.

> 
> [ ... ]
> 
> > @@ -2837,6 +2837,10 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
> >  		 */
> >  		nr_pages = (size - sizeof(struct ring_buffer_cpu_meta)) /
> >  			(subbuf_size + sizeof(int));
> > +
> > +		/* limited by ring_buffer_cpu_meta::nr_subbufs */
> > +		if (nr_pages > U32_MAX - 1)
> > +			goto fail_free_buffers;
> >  		/* Need at least two pages plus the reader page */
> >  		if (nr_pages < 3)
> >  			goto fail_free_buffers;
> 
> [Severity: High]
> Does meta->nr_subbufs + 1 overflow when nr_pages is exactly U32_MAX - 1?
> 
> If nr_pages is exactly U32_MAX - 1, meta->nr_subbufs becomes U32_MAX.
> In rb_meta_validate_events(), there are loops with this condition:
> 
>     for (i = 0; i < meta->nr_subbufs + 1; i++, rb_dec_page(&head_page)) {
> 
> U32_MAX + 1 overflows to 0 in 32-bit unsigned arithmetic. This makes the loop
> condition i < 0, causing the loops to terminate immediately without rewinding
> and validating the persistent ring buffer from a previous boot.

Sure, this can be  unsigned it as well...

And there are plenty of other functions that need fixing then.
rb_meta_subbuf_idx, rb_cpu_meta_valid, __rb_get_reader_page, rb_iter_peek... 

I need a bit more time to audit what must be modified.

-- 
Vincent

> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
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.