Re: [PATCH v4 1/9] ring-buffer: Free cpu_buffer->free_page with subbuf_order

Vincent Donnefort <[email protected]>
Newsgroups org.kernel.vger.linux-trace-kernel,dev.linux.lists.sashiko-reviews
Message-ID <[email protected]>
On Wed, Aug 12, 2026 at 03:50:37PM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [Critical] Concurrent execution of sub-buffer order resizing (`ring_buffer_subbuf_order_set`) and read operations (`ring_buffer_alloc_read_page`, `ring_buffer_read_page`) can lead to out-of-bounds writes, use-after-free, and page allocator corruption due to mismatched synchronization.
> --
> 
> --- Patch [1]: [PATCH v4 1/9] ring-buffer: Free cpu_buffer->free_page with subbuf_order ---
> commit 4100674474d6bd293fb872fecb17fc781ca58502
> Author: Vincent Donnefort <[email protected]>
> 
> ring-buffer: Free cpu_buffer->free_page with subbuf_order
>     
> When sub-buffers use an order greater than 0, cpu_buffer->free_page is
> allocated with subbuf_order. Use the correct order for
> cpu_buffer->free_page.
> 
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index 2667992f0aa29..a3d28b2e2c94a 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> > @@ -2631,7 +2631,7 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
> >  		free_buffer_page(bpage);
> >  	}
> >  
> > -	free_page((unsigned long)cpu_buffer->free_page);
> > +	free_pages((unsigned long)cpu_buffer->free_page, cpu_buffer->buffer->subbuf_order);
> 
> [Severity: Critical]
> This isn't a bug introduced by this patch, but is it possible for a race
> condition between resizing and reading to lead to memory corruption?
> 
> If thread A changes the sub-buffer size via
> /sys/kernel/tracing/buffer_subbuf_size_kb, ring_buffer_subbuf_order_set()
> updates buffer->subbuf_order locklessly globally before tearing down the CPU
> buffers and clearing their free_page.
> 
> If thread B concurrently reads /sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw
> via tracing_buffers_read(), it observes the new order and calls
> ring_buffer_alloc_read_page().
> 
> Because ring_buffer_subbuf_order_set() hasn't yet cleared
> cpu_buffer->free_page for this CPU (they use distinct locks), thread B pops
> the old page from free_page but tags it with the new order:
> 
> kernel/trace/ring_buffer.c:ring_buffer_alloc_read_page() {
>     ...
>     bpage->order = buffer->subbuf_order;
>     ...
>     if (cpu_buffer->free_page) {
>         bpage->data = cpu_buffer->free_page;
>         cpu_buffer->free_page = NULL;
>     }
>     ...
> }
> 
> Thread B then calls ring_buffer_read_page(). The lockless check passes
> because both match the new order:
> 
> kernel/trace/ring_buffer.c:ring_buffer_read_page() {
>     ...
>     if (data_page->order != buffer->subbuf_order)
>         return -1;
>     ...
>     reader->page = data_page->data;
> }
> 
> Could this allow the undersized old page to be swapped into the ring buffer
> as the reader_page, leading to an out-of-bounds write when a writer attempts
> to write large events? 
> 
> It seems it could also cause page allocator corruption when a smaller page
> is later passed to free_pages() with a larger order.
> 
> >  	kfree(cpu_buffer);
> >  }
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1

All that is hopefully fixed in one of the later patch of the series

-- 
Vincent
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.