From: Vincent Donnefort <vdonnefort@google.com>
To: rostedt@goodmis.org, mhiramat@kernel.org,
linux-trace-kernel@vger.kernel.org
Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com,
linux-kernel@vger.kernel.org,
Vincent Donnefort <vdonnefort@google.com>
Subject: [PATCH v7 3/3] ring-buffer: Prevent truncation of nr_pages / nr_subbufs
Date: Mon, 17 Aug 2026 14:47:50 +0100 [thread overview]
Message-ID: <20260817134750.3909384-4-vdonnefort@google.com> (raw)
In-Reply-To: <20260817134750.3909384-1-vdonnefort@google.com>
Although 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. Use `unsigned long` where appropriate and
prevent truncation of values using nr_pages (or nr_subbufs).
While at it, subbuf_size must be at least `unsigned int`.
Note that persistent, remote and user-mapped ring buffers are capping
the number of pages to 31 bits already, making "int" safe in many
places.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 5e26eeff588f..7d22f10df3d6 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1678,7 +1678,7 @@ static void rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
* This is used to help find the next per cpu subbuffer within a mapped range.
*/
static unsigned long
-rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
+rb_range_align_subbuf(unsigned long addr, unsigned int subbuf_size, unsigned long nr_subbufs)
{
addr += sizeof(struct ring_buffer_cpu_meta) +
sizeof(int) * nr_subbufs;
@@ -1688,13 +1688,12 @@ rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
/*
* Return the ring_buffer_meta for a given @cpu.
*/
-static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
+static void *rb_range_meta(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
{
- int subbuf_size = rb_subbuf_size(buffer);
+ unsigned int subbuf_size = rb_subbuf_size(buffer);
struct ring_buffer_cpu_meta *meta;
struct ring_buffer_meta *bmeta;
- unsigned long ptr;
- int nr_subbufs;
+ unsigned long ptr, nr_subbufs;
bmeta = buffer->meta;
if (!bmeta)
@@ -1740,7 +1739,7 @@ static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
/* Return the start of subbufs given the meta pointer */
static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
{
- int subbuf_size = meta->subbuf_size;
+ unsigned int subbuf_size = meta->subbuf_size;
unsigned long ptr;
ptr = (unsigned long)meta;
@@ -1752,11 +1751,11 @@ static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
/*
* Return a specific sub-buffer for a given @cpu defined by @idx.
*/
-static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
+static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, unsigned 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)
@@ -1772,7 +1771,7 @@ static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
ptr = (unsigned long)rb_subbufs_from_meta(meta);
- ptr += subbuf_size * idx;
+ ptr += (unsigned long)subbuf_size * idx;
if (ptr + subbuf_size > cpu_buffer->buffer->range_addr_end)
return NULL;
@@ -1849,13 +1848,13 @@ 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 long subbuf_size = PAGE_SIZE;
unsigned long buffers_start;
unsigned long buffers_end;
- int i;
+ unsigned long i;
if (!subbuf_mask)
return false;
@@ -2104,8 +2103,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
struct buffer_page *head_page, *orig_head, *orig_reader;
struct rb_validation_state state = { 0 };
bool skip = false;
+ unsigned long i;
int ret;
- int i;
if (!meta || !meta->head_buffer)
return;
@@ -2156,7 +2155,7 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
rb_validate_buffer(head_page, cpu_buffer, meta, &state, 0, state.ts);
}
if (i)
- pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
+ pr_info("Ring buffer [%d] rewound %lu pages\n", cpu_buffer->cpu, i);
/* The last rewound page must be skipped. */
if (head_page != orig_head)
@@ -2240,7 +2239,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
}
}
-static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages, int scratch_size)
+static void rb_range_meta_init(struct trace_buffer *buffer,
+ unsigned long nr_pages, int scratch_size)
{
struct ring_buffer_cpu_meta *meta;
unsigned long *subbuf_mask;
@@ -2340,8 +2340,8 @@ static int rbm_show(struct seq_file *m, void *v)
rb_meta_subbuf_idx(meta, (void *)meta->head_buffer));
seq_printf(m, "commit_buffer: %d\n",
rb_meta_subbuf_idx(meta, (void *)meta->commit_buffer));
- seq_printf(m, "subbuf_size: %d\n", meta->subbuf_size);
- seq_printf(m, "nr_subbufs: %d\n", meta->nr_subbufs);
+ seq_printf(m, "subbuf_size: %u\n", meta->subbuf_size);
+ seq_printf(m, "nr_subbufs: %u\n", meta->nr_subbufs);
return 0;
}
@@ -2426,7 +2426,7 @@ static void *ring_buffer_desc_page(struct ring_buffer_desc *desc, unsigned int p
}
static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
- long nr_pages, struct list_head *pages)
+ unsigned long nr_pages, struct list_head *pages)
{
struct trace_buffer *buffer = cpu_buffer->buffer;
struct ring_buffer_cpu_meta *meta = NULL;
@@ -2554,7 +2554,7 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
}
static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
+rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
{
struct ring_buffer_per_cpu *cpu_buffer __free(kfree) =
alloc_cpu_buffer(cpu);
@@ -2711,8 +2711,8 @@ static void rb_test_inject_invalid_pages(struct trace_buffer *buffer)
struct ring_buffer_cpu_meta *meta;
struct buffer_data_page *dpage;
unsigned long entry_bytes = 0;
+ unsigned int subbuf_size;
unsigned long ptr;
- int subbuf_size;
int invalid = 0;
int cpu;
int i;
@@ -2782,8 +2782,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
struct ring_buffer_remote *remote)
{
struct trace_buffer *buffer __free(kfree) = NULL;
- long nr_pages;
- int subbuf_size;
+ unsigned int subbuf_size;
+ unsigned long nr_pages;
int bsize;
int cpu;
int ret;
@@ -5867,12 +5867,12 @@ __rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer)
static struct buffer_page *
__rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
{
- int max_loops = cpu_buffer->ring_meta ? cpu_buffer->nr_pages : 3;
+ unsigned long max_loops = cpu_buffer->ring_meta ? cpu_buffer->nr_pages : 3;
struct buffer_page *reader = NULL;
+ unsigned long nr_loops = 0;
unsigned long overwrite;
unsigned long flags;
int missed_events = 0;
- int nr_loops = 0;
bool ret;
local_irq_save(flags);
@@ -6190,8 +6190,8 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
struct trace_buffer *buffer;
struct ring_buffer_per_cpu *cpu_buffer;
struct ring_buffer_event *event;
- int nr_loops = 0;
- int max_loops;
+ unsigned long nr_loops = 0;
+ unsigned long max_loops;
if (ts)
*ts = 0;
@@ -7438,8 +7438,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
struct ring_buffer_per_cpu *cpu_buffer;
struct buffer_page *bpage, *tmp;
unsigned int old_capacity;
+ unsigned long nr_pages;
int old_order;
- int nr_pages;
int psize;
int err;
int cpu;
@@ -7621,10 +7621,10 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
struct buffer_page **subbuf_ids)
{
struct trace_buffer_meta *meta = cpu_buffer->meta_page;
- unsigned int nr_subbufs = cpu_buffer->nr_pages + 1;
+ unsigned long nr_subbufs = cpu_buffer->nr_pages + 1;
struct buffer_page *first_subbuf, *subbuf;
- int cnt = 0;
- int id = 0;
+ unsigned int cnt = 0;
+ unsigned int id = 0;
id = rb_page_id(cpu_buffer, cpu_buffer->reader_page, id);
subbuf_ids[id++] = cpu_buffer->reader_page;
--
2.55.0.691.gc56d675ccc-goog
next prev parent reply other threads:[~2026-08-17 13:48 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-17 13:47 [PATCH v7 0/3] ring-buffer: Fixes for subbuf resizing and persistent buffers Vincent Donnefort
2026-08-17 13:47 ` [PATCH v7 1/3] tracing: Fix subbuf resize races with trace_pipe_raw readers Vincent Donnefort
2026-08-17 14:08 ` sashiko-bot
2026-08-17 13:47 ` [PATCH v7 2/3] ring-buffer: Cap static ring buffer nr_pages Vincent Donnefort
2026-08-17 14:03 ` sashiko-bot
2026-08-17 13:47 ` Vincent Donnefort [this message]
2026-08-17 13:59 ` [PATCH v7 3/3] ring-buffer: Prevent truncation of nr_pages / nr_subbufs sashiko-bot
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=20260817134750.3909384-4-vdonnefort@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox