Skip to content

Commit 0d547a6

Browse files
rostedtgregkh
authored andcommitted
ring-buffer: Validate the persistent meta data subbuf array
commit f5b95f1 upstream. The meta data for a mapped ring buffer contains an array of indexes of all the subbuffers. The first entry is the reader page, and the rest of the entries lay out the order of the subbuffers in how the ring buffer link list is to be created. The validator currently makes sure that all the entries are within the range of 0 and nr_subbufs. But it does not check if there are any duplicates. While working on the ring buffer, I corrupted this array, where I added duplicates. The validator did not catch it and created the ring buffer link list on top of it. Luckily, the corruption was only that the reader page was also in the writer path and only presented corrupted data but did not crash the kernel. But if there were duplicates in the writer side, then it could corrupt the ring buffer link list and cause a crash. Create a bitmask array with the size of the number of subbuffers. Then clear it. When walking through the subbuf array checking to see if the entries are within the range, test if its bit is already set in the subbuf_mask. If it is, then there is duplicates and fail the validation. If not, set the corresponding bit and continue. Cc: stable@vger.kernel.org Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Vincent Donnefort <vdonnefort@google.com> Link: https://lore.kernel.org/20250214102820.7509ddea@gandalf.local.home Fixes: c76883f ("ring-buffer: Add test if range of boot buffer is valid") Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent cf5aa56 commit 0d547a6

File tree

1 file changed

+20
-2
lines changed

1 file changed

+20
-2
lines changed

kernel/trace/ring_buffer.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,14 +1672,18 @@ static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
16721672
* must be the same.
16731673
*/
16741674
static bool rb_meta_valid(struct ring_buffer_meta *meta, int cpu,
1675-
struct trace_buffer *buffer, int nr_pages)
1675+
struct trace_buffer *buffer, int nr_pages,
1676+
unsigned long *subbuf_mask)
16761677
{
16771678
int subbuf_size = PAGE_SIZE;
16781679
struct buffer_data_page *subbuf;
16791680
unsigned long buffers_start;
16801681
unsigned long buffers_end;
16811682
int i;
16821683

1684+
if (!subbuf_mask)
1685+
return false;
1686+
16831687
/* Check the meta magic and meta struct size */
16841688
if (meta->magic != RING_BUFFER_META_MAGIC ||
16851689
meta->struct_size != sizeof(*meta)) {
@@ -1712,6 +1716,8 @@ static bool rb_meta_valid(struct ring_buffer_meta *meta, int cpu,
17121716

17131717
subbuf = rb_subbufs_from_meta(meta);
17141718

1719+
bitmap_clear(subbuf_mask, 0, meta->nr_subbufs);
1720+
17151721
/* Is the meta buffers and the subbufs themselves have correct data? */
17161722
for (i = 0; i < meta->nr_subbufs; i++) {
17171723
if (meta->buffers[i] < 0 ||
@@ -1725,6 +1731,12 @@ static bool rb_meta_valid(struct ring_buffer_meta *meta, int cpu,
17251731
return false;
17261732
}
17271733

1734+
if (test_bit(meta->buffers[i], subbuf_mask)) {
1735+
pr_info("Ring buffer boot meta [%d] array has duplicates\n", cpu);
1736+
return false;
1737+
}
1738+
1739+
set_bit(meta->buffers[i], subbuf_mask);
17281740
subbuf = (void *)subbuf + subbuf_size;
17291741
}
17301742

@@ -1889,17 +1901,22 @@ static void rb_meta_init_text_addr(struct ring_buffer_meta *meta)
18891901
static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
18901902
{
18911903
struct ring_buffer_meta *meta;
1904+
unsigned long *subbuf_mask;
18921905
unsigned long delta;
18931906
void *subbuf;
18941907
int cpu;
18951908
int i;
18961909

1910+
/* Create a mask to test the subbuf array */
1911+
subbuf_mask = bitmap_alloc(nr_pages + 1, GFP_KERNEL);
1912+
/* If subbuf_mask fails to allocate, then rb_meta_valid() will return false */
1913+
18971914
for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
18981915
void *next_meta;
18991916

19001917
meta = rb_range_meta(buffer, nr_pages, cpu);
19011918

1902-
if (rb_meta_valid(meta, cpu, buffer, nr_pages)) {
1919+
if (rb_meta_valid(meta, cpu, buffer, nr_pages, subbuf_mask)) {
19031920
/* Make the mappings match the current address */
19041921
subbuf = rb_subbufs_from_meta(meta);
19051922
delta = (unsigned long)subbuf - meta->first_buffer;
@@ -1943,6 +1960,7 @@ static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
19431960
subbuf += meta->subbuf_size;
19441961
}
19451962
}
1963+
bitmap_free(subbuf_mask);
19461964
}
19471965

19481966
static void *rbm_start(struct seq_file *m, loff_t *pos)

0 commit comments

Comments
 (0)