aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-12-27 16:06:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-12-27 16:06:57 -0500
commit5f520fc318764df800789edd202b5e3b55130613 (patch)
tree6cdcbd38866f66c86e9397a06b6ef7415442febc
parent9b9577948f64edc1c967d80deb6910c811abb8fc (diff)
parent4397f04575c44e1440ec2e49b6302785c95fd2f8 (diff)
Merge tag 'trace-v4.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing fixes from Steven Rostedt: "While doing tests on tracing over the network, I found that the packets were getting corrupted. In the process I found three bugs. One was the culprit, but the other two scared me. After deeper investigation, they were not as major as I thought they were, due to a signed compared to an unsigned that prevented a negative number from doing actual harm. The two bigger bugs: - Mask the ring buffer data page length. There are data flags at the high bits of the length field. These were not cleared via the length function, and the length could return a negative number. (Although the number returned was unsigned, but was assigned to a signed number) Luckily, this value was compared to PAGE_SIZE which is unsigned and kept it from entering the path that could have caused damage. - Check the page usage before reusing the ring buffer reader page. TCP increments the page ref when passing the page off to the network. The page is passed back to the ring buffer for use on free. But the page could still be in use by the TCP stack. Minor bugs: - Related to the first bug. No need to clear out the unused ring buffer data before sending to user space. It is now done by the ring buffer code itself. - Reset pointers after free on error path. There were some cases in the error path that pointers were freed but not set to NULL, and could have them freed again, having a pointer freed twice" * tag 'trace-v4.15-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: tracing: Fix possible double free on failure of allocating trace buffer tracing: Fix crash when it fails to alloc ring buffer ring-buffer: Do no reuse reader page if still in use tracing: Remove extra zeroing out of the ring buffer page ring-buffer: Mask out the info bits when returning buffer page length
-rw-r--r--kernel/trace/ring_buffer.c12
-rw-r--r--kernel/trace/trace.c13
2 files changed, 15 insertions, 10 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c87766c1c204..9ab18995ff1e 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -280,6 +280,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data);
280/* Missed count stored at end */ 280/* Missed count stored at end */
281#define RB_MISSED_STORED (1 << 30) 281#define RB_MISSED_STORED (1 << 30)
282 282
283#define RB_MISSED_FLAGS (RB_MISSED_EVENTS|RB_MISSED_STORED)
284
283struct buffer_data_page { 285struct buffer_data_page {
284 u64 time_stamp; /* page time stamp */ 286 u64 time_stamp; /* page time stamp */
285 local_t commit; /* write committed index */ 287 local_t commit; /* write committed index */
@@ -331,7 +333,9 @@ static void rb_init_page(struct buffer_data_page *bpage)
331 */ 333 */
332size_t ring_buffer_page_len(void *page) 334size_t ring_buffer_page_len(void *page)
333{ 335{
334 return local_read(&((struct buffer_data_page *)page)->commit) 336 struct buffer_data_page *bpage = page;
337
338 return (local_read(&bpage->commit) & ~RB_MISSED_FLAGS)
335 + BUF_PAGE_HDR_SIZE; 339 + BUF_PAGE_HDR_SIZE;
336} 340}
337 341
@@ -4400,8 +4404,13 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data)
4400{ 4404{
4401 struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; 4405 struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
4402 struct buffer_data_page *bpage = data; 4406 struct buffer_data_page *bpage = data;
4407 struct page *page = virt_to_page(bpage);
4403 unsigned long flags; 4408 unsigned long flags;
4404 4409
4410 /* If the page is still in use someplace else, we can't reuse it */
4411 if (page_ref_count(page) > 1)
4412 goto out;
4413
4405 local_irq_save(flags); 4414 local_irq_save(flags);
4406 arch_spin_lock(&cpu_buffer->lock); 4415 arch_spin_lock(&cpu_buffer->lock);
4407 4416
@@ -4413,6 +4422,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data)
4413 arch_spin_unlock(&cpu_buffer->lock); 4422 arch_spin_unlock(&cpu_buffer->lock);
4414 local_irq_restore(flags); 4423 local_irq_restore(flags);
4415 4424
4425 out:
4416 free_page((unsigned long)bpage); 4426 free_page((unsigned long)bpage);
4417} 4427}
4418EXPORT_SYMBOL_GPL(ring_buffer_free_read_page); 4428EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 59518b8126d0..2a8d8a294345 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6769,7 +6769,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
6769 .spd_release = buffer_spd_release, 6769 .spd_release = buffer_spd_release,
6770 }; 6770 };
6771 struct buffer_ref *ref; 6771 struct buffer_ref *ref;
6772 int entries, size, i; 6772 int entries, i;
6773 ssize_t ret = 0; 6773 ssize_t ret = 0;
6774 6774
6775#ifdef CONFIG_TRACER_MAX_TRACE 6775#ifdef CONFIG_TRACER_MAX_TRACE
@@ -6823,14 +6823,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
6823 break; 6823 break;
6824 } 6824 }
6825 6825
6826 /*
6827 * zero out any left over data, this is going to
6828 * user land.
6829 */
6830 size = ring_buffer_page_len(ref->page);
6831 if (size < PAGE_SIZE)
6832 memset(ref->page + size, 0, PAGE_SIZE - size);
6833
6834 page = virt_to_page(ref->page); 6826 page = virt_to_page(ref->page);
6835 6827
6836 spd.pages[i] = page; 6828 spd.pages[i] = page;
@@ -7588,6 +7580,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
7588 buf->data = alloc_percpu(struct trace_array_cpu); 7580 buf->data = alloc_percpu(struct trace_array_cpu);
7589 if (!buf->data) { 7581 if (!buf->data) {
7590 ring_buffer_free(buf->buffer); 7582 ring_buffer_free(buf->buffer);
7583 buf->buffer = NULL;
7591 return -ENOMEM; 7584 return -ENOMEM;
7592 } 7585 }
7593 7586
@@ -7611,7 +7604,9 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)
7611 allocate_snapshot ? size : 1); 7604 allocate_snapshot ? size : 1);
7612 if (WARN_ON(ret)) { 7605 if (WARN_ON(ret)) {
7613 ring_buffer_free(tr->trace_buffer.buffer); 7606 ring_buffer_free(tr->trace_buffer.buffer);
7607 tr->trace_buffer.buffer = NULL;
7614 free_percpu(tr->trace_buffer.data); 7608 free_percpu(tr->trace_buffer.data);
7609 tr->trace_buffer.data = NULL;
7615 return -ENOMEM; 7610 return -ENOMEM;
7616 } 7611 }
7617 tr->allocated_snapshot = allocate_snapshot; 7612 tr->allocated_snapshot = allocate_snapshot;