From: sashiko-bot@kernel.org
To: "Vincent Donnefort" <vdonnefort@google.com>
Cc: linux-trace-kernel@vger.kernel.org
Subject: Re: [PATCH v4 3/9] ring-buffer: Fix subbuf resize race with ring buffer readers
Date: Wed, 12 Aug 2026 15:53:12 +0000 [thread overview]
Message-ID: <20260812155312.ADF031F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260812153311.2328812-4-vdonnefort@google.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
New issues:
- [High] Use-After-Free dereference of `reader_page` in `ring_buffer_read_start()` when bypassing buffer mutex.
Pre-existing issues:
- [High] 32-bit integer overflow in ring buffer capacity calculation truncates large trace buffers.
- [High] Out-of-bounds kernel memory write and VMAP flush in `ring_buffer_map_get_reader()` due to global capacity TOCTOU race.
--
--- Patch [3]: [PATCH v4 3/9] ring-buffer: Fix subbuf resize race with ring buffer readers ---
commit 9618f28d9a6939c645e7579fa798c42557eb075c
Author: Vincent Donnefort <vdonnefort@google.com>
ring-buffer: Fix subbuf resize race with ring buffer readers
This commit changes the trace_buffer to use bpage order instead of
trace_buffer::subbuf_size in ring_buffer_read_start() and
ring_buffer_read_page(). It also removes trace_buffer::subbuf_size and
introduces capacity accessors.
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index ec4f5a0c93e85..97449423d3a68 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
[ ... ]
> @@ -6380,36 +6417,44 @@ EXPORT_SYMBOL_GPL(ring_buffer_consume);
> struct ring_buffer_iter *
> ring_buffer_read_start(struct trace_buffer *buffer, int cpu, gfp_t flags)
> {
> + struct ring_buffer_iter *iter __free(kfree) = kzalloc_obj(*iter, flags);
> struct ring_buffer_per_cpu *cpu_buffer;
> - struct ring_buffer_iter *iter;
> -
> - if (!cpumask_test_cpu(cpu, buffer->cpumask))
> - return NULL;
>
> - iter = kzalloc_obj(*iter, flags);
> if (!iter)
> return NULL;
>
> - /* Holds the entire event: data and meta data */
> - iter->event_size = buffer->subbuf_size;
> - iter->event = kmalloc(iter->event_size, flags);
> - if (!iter->event) {
> - kfree(iter);
> + if (!cpumask_test_cpu(cpu, buffer->cpumask))
> return NULL;
> - }
>
> cpu_buffer = buffer->buffers[cpu];
>
> - iter->cpu_buffer = cpu_buffer;
> + /*
> + * Only KDB is using GFP_ATOMIC, for the others, lock the buffer to
> + * prevent concurrent resizing.
> + */
> + if (gfpflags_allow_blocking(flags))
> + mutex_lock(&buffer->mutex);
>
> atomic_inc(&cpu_buffer->resize_disabled);
>
> + if (gfpflags_allow_blocking(flags))
> + mutex_unlock(&buffer->mutex);
> +
> + /* Holds the entire event: data and meta data. */
> + iter->event_size = rb_page_capacity(READ_ONCE(cpu_buffer->reader_page));
[Severity: High]
Can this result in a use-after-free dereference of the reader page?
When ring_buffer_read_start() is called with GFP_ATOMIC, it skips acquiring
buffer->mutex and only increments cpu_buffer->resize_disabled.
If a concurrent ring_buffer_subbuf_order_set() has already passed its
resize_disabled check, it will proceed to allocate new pages and free the old
reader page.
A thread executing ring_buffer_read_start() could load the old reader page
pointer just before it is freed by the other CPU, dereferencing freed memory
when accessing the order field.
> + iter->event = kmalloc(iter->event_size, flags);
> + if (!iter->event) {
> + atomic_dec(&cpu_buffer->resize_disabled);
> + return NULL;
> + }
[ ... ]
> @@ -7367,8 +7413,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
> }
>
> /* Update the number of pages to match the new size */
> - nr_pages = old_size * buffer->buffers[cpu]->nr_pages;
> - nr_pages = DIV_ROUND_UP(nr_pages, buffer->subbuf_size);
> + nr_pages = old_capacity * buffer->buffers[cpu]->nr_pages;
[Severity: High]
This is a pre-existing issue, but can this 32-bit integer capacity calculation
truncate large trace buffers?
For buffers larger than 4GB, the multiplication of old_capacity and
buffer->buffers[cpu]->nr_pages can exceed 32 bits. Because nr_pages is a
32-bit signed integer, the result is truncated, and the buffer is shrunk to a
tiny fraction of its intended size during a resize operation.
> + nr_pages = DIV_ROUND_UP(nr_pages, rb_subbuf_capacity(buffer));
>
> /* we need a minimum of two pages */
> if (nr_pages < 2)
[ ... ]
> @@ -7896,7 +7941,7 @@ int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu)
> * missed events, then record it there.
> */
> commit = rb_page_size(reader);
> - if (buffer->subbuf_size - commit >= sizeof(missed_events)) {
> + if (rb_subbuf_capacity(buffer) - commit >= sizeof(missed_events)) {
[Severity: High]
This is a pre-existing issue, but does this create a time-of-check to
time-of-use race leading to an out-of-bounds kernel memory write and
VMAP flush?
During a sub-buffer order resize, ring_buffer_subbuf_order_set() modifies
buffer->subbuf_order globally before verifying if resize_disabled is set. If
the buffer is currently mapped, the resize aborts and restores the old order.
In that race window, a concurrent ring_buffer_map_get_reader() call will see
the new, larger capacity via rb_subbuf_capacity(buffer) here. It could then
write missed_events past the end of the old, smaller reader page, and
subsequently flush memory beyond the mapped VMAP range.
> memcpy(&dpage->data[commit], &missed_events,
> sizeof(missed_events));
> local_add(RB_MISSED_STORED, &dpage->commit);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260812153311.2328812-1-vdonnefort@google.com?part=3
next prev parent reply other threads:[~2026-08-12 15:53 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-12 15:33 [PATCH v4 0/9] ring-buffer: Fixes for subbuf resizing and persistent buffers Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 1/9] ring-buffer: Free cpu_buffer->free_page with subbuf_order Vincent Donnefort
2026-08-12 15:50 ` sashiko-bot
2026-08-12 16:37 ` Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 2/9] ring-buffer: Hold cpu_buffer::lock when resizing a subbuf Vincent Donnefort
2026-08-12 15:46 ` sashiko-bot
2026-08-12 16:41 ` Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 3/9] ring-buffer: Fix subbuf resize race with ring buffer readers Vincent Donnefort
2026-08-12 15:53 ` sashiko-bot [this message]
2026-08-12 16:44 ` Vincent Donnefort
2026-08-12 17:24 ` Steven Rostedt
2026-08-12 15:33 ` [PATCH v4 4/9] ring-buffer: Fix subbuf resize race in ring_buffer_alloc_read_page() Vincent Donnefort
2026-08-12 15:46 ` sashiko-bot
2026-08-12 16:50 ` Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 5/9] tracing: Fix subbuf resize races in trace_pipe_raw readers Vincent Donnefort
2026-08-12 15:47 ` sashiko-bot
2026-08-12 16:57 ` Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 6/9] ring-buffer: Dynamically calculate max_data_size Vincent Donnefort
2026-08-12 15:56 ` sashiko-bot
2026-08-12 17:12 ` Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 7/9] ring-buffer: Remove trace_buffer::cpus Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 8/9] ring-buffer: Remove ring_buffer_per_cpu::mapped Vincent Donnefort
2026-08-12 15:33 ` [PATCH v4 9/9] ring-buffer: Make nr_pages unsigned int Vincent Donnefort
2026-08-12 15:47 ` sashiko-bot
2026-08-12 17:15 ` 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=20260812155312.ADF031F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
--cc=vdonnefort@google.com \
/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.