All of lore.kernel.org
 help / color / mirror / Atom feed
From: Vincent Donnefort <vdonnefort@google.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
	kernel-team@android.com
Subject: Re: [PATCH] ring-buffer: Fix race between ring_buffer_subbuf_order_set() and readers
Date: Fri, 14 Aug 2026 15:53:43 +0100	[thread overview]
Message-ID: <an8r9yMinscYpmjA@google.com> (raw)
In-Reply-To: <20260814104208.28f47749@gandalf.local.home>

On Fri, Aug 14, 2026 at 10:42:08AM -0400, Steven Rostedt wrote:
> On Fri, 14 Aug 2026 01:16:13 +0900
> "Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> 
> > From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> > 
> > When ring_buffer_subbuf_order_set() updates buffer->subbuf_order, it
> > previously modified buffer->subbuf_order before clearing the cached
> > per-CPU free_page entries. Furthermore, clearing cpu_buffer->free_page
> > was done under cpu_buffer->reader_lock, whereas
> > ring_buffer_alloc_read_page() protects cpu_buffer->free_page using
> > arch_spin_lock(&cpu_buffer->lock).
> > 
> > Because ring_buffer_alloc_read_page(), ring_buffer_free_read_page(),
> > and ring_buffer_read_page() checked buffer->subbuf_order locklessly
> > before accessing reader resources, a TOCTOU race allowed a concurrent
> > reader to obtain, cache, or swap a page allocated under an outdated order
> > while tagging bpage->order with the new order. This allowed undersized
> > pages to be swapped into the ring buffer, leading to heap buffer overflows,
> > or caused free_pages() to be called with an invalid order.
> > 
> > Fix this by:
> > 1. Flushing and freeing all per-CPU cached free_page entries under
> >    arch_spin_lock(&cpu_buffer->lock) using old_order before modifying
> >    buffer->subbuf_order.
> > 2. Protecting bpage->order assignment under
> >    arch_spin_lock(&cpu_buffer->lock) in ring_buffer_alloc_read_page().
> > 3. Moving the buffer->subbuf_order validation inside
> >    arch_spin_lock(&cpu_buffer->lock) in ring_buffer_free_read_page().
> > 4. Re-validating buffer->subbuf_order inside reader_lock in
> >    ring_buffer_read_page().
> > 5. Protecting cpu_buffer->free_page extraction with
> >    arch_spin_lock(&cpu_buffer->lock) in ring_buffer_subbuf_order_set().
> > 
> > Fixes: 2808e31ec12e ("ring-buffer: Add interface for configuring trace sub buffer size")
> > Assisted-by: Antigravity:gemini-3.6-flash
> > Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> > ---
> 
> 
> Please rebase on top of ring-buffer/for-next, as I added Vincent's patches to that.
> 
> >  kernel/trace/ring_buffer.c |   35 +++++++++++++++++++++++++++++------
> >  1 file changed, 29 insertions(+), 6 deletions(-)
> > 
> > diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> > index 2667992f0aa2..6d180689ad59 100644
> > --- a/kernel/trace/ring_buffer.c
> > +++ b/kernel/trace/ring_buffer.c
> > @@ -6957,11 +6957,11 @@ ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
> >  	if (!bpage)
> >  		return ERR_PTR(-ENOMEM);
> >  
> > -	bpage->order = buffer->subbuf_order;
> >  	cpu_buffer = buffer->buffers[cpu];
> >  	local_irq_save(flags);
> >  	arch_spin_lock(&cpu_buffer->lock);
> >  
> > +	bpage->order = buffer->subbuf_order;
> 
> This is still needed.

I am not sure, the lock is per-cpu_buffer but subbuf_order. is global to
trace_buffer?

> 
> >  	if (cpu_buffer->free_page) {
> >  		bpage->data = cpu_buffer->free_page;
> >  		cpu_buffer->free_page = NULL;
> > @@ -7010,13 +7010,13 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
> >  	 * is different from the subbuffer order of the buffer -
> >  	 * we can't reuse it
> >  	 */
> > -	if (page_ref_count(page) > 1 || data_page->order != buffer->subbuf_order)
> > +	if (page_ref_count(page) > 1)
> >  		goto out;
> >  
> >  	local_irq_save(flags);
> >  	arch_spin_lock(&cpu_buffer->lock);
> >  
> > -	if (!cpu_buffer->free_page) {
> > +	if (data_page->order == buffer->subbuf_order && !cpu_buffer->free_page) {
> 
> Swap the order please. It has to check both to continue and if one fails it
> will not continue. Checking for cpu_buffer->free_page to be NULL first is
> the quicker check. And also the more likely one to fail.
> 
> >  		cpu_buffer->free_page = dpage;
> >  		dpage = NULL;
> >  	}
> > @@ -7094,15 +7094,15 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
> >  	if (!data_page || !data_page->data)
> >  		return -1;
> >  
> > -	if (data_page->order != buffer->subbuf_order)
> > -		return -1;
> > -
> >  	dpage = data_page->data;
> >  	if (!dpage)
> >  		return -1;
> >  
> >  	guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock);
> >  
> > +	if (data_page->order != buffer->subbuf_order)
> > +		return -1;
> > +

I have modified this as part of 

tracing: Fix subbuf resize races with trace_pipe_raw readers 

> >  	reader = rb_get_reader_page(cpu_buffer);
> >  	if (!reader)
> >  		return -1;
> > @@ -7350,6 +7350,27 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
> >  	/* Make sure all commits have finished */
> >  	synchronize_rcu();
> >  
> > +	/* Flush any cached free_page allocated with old_order */
> > +	for_each_buffer_cpu(buffer, cpu) {
> > +		struct buffer_data_page *old_free;
> > +		unsigned long flags;
> > +
> > +		if (!cpumask_test_cpu(cpu, buffer->cpumask))
> > +			continue;
> > +
> > +		cpu_buffer = buffer->buffers[cpu];
> > +
> > +		local_irq_save(flags);
> > +		arch_spin_lock(&cpu_buffer->lock);
> > +		old_free = cpu_buffer->free_page;
> > +		cpu_buffer->free_page = NULL;
> > +		arch_spin_unlock(&cpu_buffer->lock);
> > +		local_irq_restore(flags);
> > +
> > +		if (old_free)
> > +			free_pages((unsigned long)old_free, old_order);
> > +	}
> 
> Honestly, this should be a separate patch. The first part of this patch is
> data races with adding and freeing, but this is about changes to the size.
> 
> > +
> >  	buffer->subbuf_order = order;
> >  	buffer->subbuf_size = psize - BUF_PAGE_HDR_SIZE;
> >  
> > @@ -7431,8 +7452,10 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
> >  		cpu_buffer->nr_pages = cpu_buffer->nr_pages_to_update;
> >  		cpu_buffer->nr_pages_to_update = 0;
> >  
> > +		arch_spin_lock(&cpu_buffer->lock);
> >  		old_free_data_page = cpu_buffer->free_page;
> >  		cpu_buffer->free_page = NULL;
> > +		arch_spin_unlock(&cpu_buffer->lock);
> 
> This is already fixed by Vincent (and I would have asked this to be a
> separate patch too if it hadn't).
> 
> -- Steve
> 
> >  
> >  		rb_head_page_activate(cpu_buffer);
> >  
> 

-- 
Vincent

  reply	other threads:[~2026-08-14 14:53 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-13 16:16 [PATCH 0/1] ring-buffer: Fix sub-buffer order updates and free_page leaks Masami Hiramatsu (Google)
2026-08-13 16:16 ` [PATCH] ring-buffer: Fix race between ring_buffer_subbuf_order_set() and readers Masami Hiramatsu (Google)
2026-08-13 16:30   ` sashiko-bot
2026-08-14 14:42   ` Steven Rostedt
2026-08-14 14:53     ` Vincent Donnefort [this message]
2026-08-14 16:00       ` Masami Hiramatsu
2026-08-13 17:25 ` [PATCH 0/1] ring-buffer: Fix sub-buffer order updates and free_page leaks Vincent Donnefort

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=an8r9yMinscYpmjA@google.com \
    --to=vdonnefort@google.com \
    --cc=kernel-team@android.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mhiramat@kernel.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.