Skip to content

Commit c76883f

Browse files
committed
ring-buffer: Add test if range of boot buffer is valid
Add a test against the ring buffer memory range to see if it has valid data. The ring_buffer_meta structure is given a new field called "first_buffer" which holds the address of the first sub-buffer. This is used to both determine if the other fields are valid as well as finding the offset between the old addresses of the sub-buffer from the previous boot to the new addresses of the current boot. Since the values for nr_subbufs and subbuf_size is to be the same, check if the values in the meta page match the values calculated. Take the range of the first_buffer and the total size of all the buffers and make sure the saved head_buffer and commit_buffer fall in the range. Iterate through all the sub-buffers to make sure that the values in the sub-buffer "commit" field (the field that holds the amount of data on the sub-buffer) is within the end of the sub-buffer. Also check the index array to make sure that all the indexes are within nr_subbufs. Link: https://lkml.kernel.org/r/[email protected] Cc: Masami Hiramatsu <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Vincent Donnefort <[email protected]> Cc: Joel Fernandes <[email protected]> Cc: Daniel Bristot de Oliveira <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vineeth Pillai <[email protected]> Cc: Youssef Esmat <[email protected]> Cc: Beau Belgrave <[email protected]> Cc: Alexander Graf <[email protected]> Cc: Baoquan He <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Cc: David Howells <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Dave Hansen <[email protected]> Cc: Tony Luck <[email protected]> Cc: Guenter Roeck <[email protected]> Cc: Ross Zwisler <[email protected]> Cc: Kees Cook <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 950032f commit c76883f

File tree

1 file changed

+135
-8
lines changed

1 file changed

+135
-8
lines changed

kernel/trace/ring_buffer.c

Lines changed: 135 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
static void update_pages_handler(struct work_struct *work);
4646

4747
struct ring_buffer_meta {
48+
unsigned long first_buffer;
4849
unsigned long head_buffer;
4950
unsigned long commit_buffer;
5051
__u32 subbuf_size;
@@ -1618,21 +1619,103 @@ static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
16181619
return (void *)ptr;
16191620
}
16201621

1622+
/*
1623+
* See if the existing memory contains valid ring buffer data.
1624+
* As the previous kernel must be the same as this kernel, all
1625+
* the calculations (size of buffers and number of buffers)
1626+
* must be the same.
1627+
*/
1628+
static bool rb_meta_valid(struct ring_buffer_meta *meta, int cpu,
1629+
struct trace_buffer *buffer, int nr_pages)
1630+
{
1631+
int subbuf_size = PAGE_SIZE;
1632+
struct buffer_data_page *subbuf;
1633+
unsigned long buffers_start;
1634+
unsigned long buffers_end;
1635+
int i;
1636+
1637+
/* The subbuffer's size and number of subbuffers must match */
1638+
if (meta->subbuf_size != subbuf_size ||
1639+
meta->nr_subbufs != nr_pages + 1) {
1640+
pr_info("Ring buffer boot meta [%d] mismatch of subbuf_size/nr_pages\n", cpu);
1641+
return false;
1642+
}
1643+
1644+
buffers_start = meta->first_buffer;
1645+
buffers_end = meta->first_buffer + (subbuf_size * meta->nr_subbufs);
1646+
1647+
/* Is the head and commit buffers within the range of buffers? */
1648+
if (meta->head_buffer < buffers_start ||
1649+
meta->head_buffer >= buffers_end) {
1650+
pr_info("Ring buffer boot meta [%d] head buffer out of range\n", cpu);
1651+
return false;
1652+
}
1653+
1654+
if (meta->commit_buffer < buffers_start ||
1655+
meta->commit_buffer >= buffers_end) {
1656+
pr_info("Ring buffer boot meta [%d] commit buffer out of range\n", cpu);
1657+
return false;
1658+
}
1659+
1660+
subbuf = rb_subbufs_from_meta(meta);
1661+
1662+
/* Is the meta buffers and the subbufs themselves have correct data? */
1663+
for (i = 0; i < meta->nr_subbufs; i++) {
1664+
if (meta->buffers[i] < 0 ||
1665+
meta->buffers[i] >= meta->nr_subbufs) {
1666+
pr_info("Ring buffer boot meta [%d] array out of range\n", cpu);
1667+
return false;
1668+
}
1669+
1670+
if ((unsigned)local_read(&subbuf->commit) > subbuf_size) {
1671+
pr_info("Ring buffer boot meta [%d] buffer invalid commit\n", cpu);
1672+
return false;
1673+
}
1674+
1675+
subbuf = (void *)subbuf + subbuf_size;
1676+
}
1677+
1678+
pr_info("Ring buffer meta is from previous boot!\n");
1679+
return true;
1680+
}
1681+
16211682
static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages)
16221683
{
16231684
struct ring_buffer_meta *meta;
1685+
unsigned long delta;
16241686
void *subbuf;
16251687
int cpu;
16261688
int i;
16271689

16281690
for (cpu = 0; cpu < nr_cpu_ids; cpu++) {
1691+
void *next_meta;
1692+
16291693
meta = rb_range_meta(buffer, nr_pages, cpu);
16301694

1695+
if (rb_meta_valid(meta, cpu, buffer, nr_pages)) {
1696+
/* Make the mappings match the current address */
1697+
subbuf = rb_subbufs_from_meta(meta);
1698+
delta = (unsigned long)subbuf - meta->first_buffer;
1699+
meta->first_buffer += delta;
1700+
meta->head_buffer += delta;
1701+
meta->commit_buffer += delta;
1702+
continue;
1703+
}
1704+
1705+
if (cpu < nr_cpu_ids - 1)
1706+
next_meta = rb_range_meta(buffer, nr_pages, cpu + 1);
1707+
else
1708+
next_meta = (void *)buffer->range_addr_end;
1709+
1710+
memset(meta, 0, next_meta - (void *)meta);
1711+
16311712
meta->nr_subbufs = nr_pages + 1;
16321713
meta->subbuf_size = PAGE_SIZE;
16331714

16341715
subbuf = rb_subbufs_from_meta(meta);
16351716

1717+
meta->first_buffer = (unsigned long)subbuf;
1718+
16361719
/*
16371720
* The buffers[] array holds the order of the sub-buffers
16381721
* that are after the meta data. The sub-buffers may
@@ -1724,10 +1807,26 @@ int ring_buffer_meta_seq_init(struct file *file, struct trace_buffer *buffer, in
17241807
return 0;
17251808
}
17261809

1810+
/* Map the buffer_pages to the previous head and commit pages */
1811+
static void rb_meta_buffer_update(struct ring_buffer_per_cpu *cpu_buffer,
1812+
struct buffer_page *bpage)
1813+
{
1814+
struct ring_buffer_meta *meta = cpu_buffer->ring_meta;
1815+
1816+
if (meta->head_buffer == (unsigned long)bpage->page)
1817+
cpu_buffer->head_page = bpage;
1818+
1819+
if (meta->commit_buffer == (unsigned long)bpage->page) {
1820+
cpu_buffer->commit_page = bpage;
1821+
cpu_buffer->tail_page = bpage;
1822+
}
1823+
}
1824+
17271825
static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
17281826
long nr_pages, struct list_head *pages)
17291827
{
17301828
struct trace_buffer *buffer = cpu_buffer->buffer;
1829+
struct ring_buffer_meta *meta = NULL;
17311830
struct buffer_page *bpage, *tmp;
17321831
bool user_thread = current->mm != NULL;
17331832
gfp_t mflags;
@@ -1762,6 +1861,10 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
17621861
*/
17631862
if (user_thread)
17641863
set_current_oom_origin();
1864+
1865+
if (buffer->range_addr_start)
1866+
meta = rb_range_meta(buffer, nr_pages, cpu_buffer->cpu);
1867+
17651868
for (i = 0; i < nr_pages; i++) {
17661869
struct page *page;
17671870

@@ -1778,11 +1881,14 @@ static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
17781881
*/
17791882
list_add_tail(&bpage->list, pages);
17801883

1781-
if (buffer->range_addr_start) {
1884+
if (meta) {
17821885
/* A range was given. Use that for the buffer page */
17831886
bpage->page = rb_range_buffer(cpu_buffer, i + 1);
17841887
if (!bpage->page)
17851888
goto free_pages;
1889+
/* If this is valid from a previous boot */
1890+
if (meta->head_buffer)
1891+
rb_meta_buffer_update(cpu_buffer, bpage);
17861892
bpage->range = 1;
17871893
bpage->id = i + 1;
17881894
} else {
@@ -1844,6 +1950,7 @@ static struct ring_buffer_per_cpu *
18441950
rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
18451951
{
18461952
struct ring_buffer_per_cpu *cpu_buffer;
1953+
struct ring_buffer_meta *meta;
18471954
struct buffer_page *bpage;
18481955
struct page *page;
18491956
int ret;
@@ -1884,6 +1991,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
18841991
bpage->page = rb_range_buffer(cpu_buffer, 0);
18851992
if (!bpage->page)
18861993
goto fail_free_reader;
1994+
if (cpu_buffer->ring_meta->head_buffer)
1995+
rb_meta_buffer_update(cpu_buffer, bpage);
18871996
bpage->range = 1;
18881997
} else {
18891998
page = alloc_pages_node(cpu_to_node(cpu),
@@ -1902,14 +2011,32 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
19022011
if (ret < 0)
19032012
goto fail_free_reader;
19042013

1905-
cpu_buffer->head_page
1906-
= list_entry(cpu_buffer->pages, struct buffer_page, list);
1907-
cpu_buffer->tail_page = cpu_buffer->commit_page = cpu_buffer->head_page;
2014+
/* If the boot meta was valid then this has already been updated */
2015+
meta = cpu_buffer->ring_meta;
2016+
if (!meta || !meta->head_buffer ||
2017+
!cpu_buffer->head_page || !cpu_buffer->commit_page || !cpu_buffer->tail_page) {
2018+
if (meta && meta->head_buffer &&
2019+
(cpu_buffer->head_page || cpu_buffer->commit_page || cpu_buffer->tail_page)) {
2020+
pr_warn("Ring buffer meta buffers not all mapped\n");
2021+
if (!cpu_buffer->head_page)
2022+
pr_warn(" Missing head_page\n");
2023+
if (!cpu_buffer->commit_page)
2024+
pr_warn(" Missing commit_page\n");
2025+
if (!cpu_buffer->tail_page)
2026+
pr_warn(" Missing tail_page\n");
2027+
}
19082028

1909-
rb_head_page_activate(cpu_buffer);
1910-
if (cpu_buffer->ring_meta) {
1911-
struct ring_buffer_meta *meta = cpu_buffer->ring_meta;
1912-
meta->commit_buffer = meta->head_buffer;
2029+
cpu_buffer->head_page
2030+
= list_entry(cpu_buffer->pages, struct buffer_page, list);
2031+
cpu_buffer->tail_page = cpu_buffer->commit_page = cpu_buffer->head_page;
2032+
2033+
rb_head_page_activate(cpu_buffer);
2034+
2035+
if (cpu_buffer->ring_meta)
2036+
meta->commit_buffer = meta->head_buffer;
2037+
} else {
2038+
/* The valid meta buffer still needs to activate the head page */
2039+
rb_head_page_activate(cpu_buffer);
19132040
}
19142041

19152042
return cpu_buffer;

0 commit comments

Comments
 (0)