Commit 5f520fc3 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 9b957794 4397f045
...@@ -280,6 +280,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data); ...@@ -280,6 +280,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data);
/* Missed count stored at end */ /* Missed count stored at end */
#define RB_MISSED_STORED (1 << 30) #define RB_MISSED_STORED (1 << 30)
#define RB_MISSED_FLAGS (RB_MISSED_EVENTS|RB_MISSED_STORED)
struct buffer_data_page { struct buffer_data_page {
u64 time_stamp; /* page time stamp */ u64 time_stamp; /* page time stamp */
local_t commit; /* write committed index */ local_t commit; /* write committed index */
...@@ -331,7 +333,9 @@ static void rb_init_page(struct buffer_data_page *bpage) ...@@ -331,7 +333,9 @@ static void rb_init_page(struct buffer_data_page *bpage)
*/ */
size_t ring_buffer_page_len(void *page) size_t ring_buffer_page_len(void *page)
{ {
return local_read(&((struct buffer_data_page *)page)->commit) struct buffer_data_page *bpage = page;
return (local_read(&bpage->commit) & ~RB_MISSED_FLAGS)
+ BUF_PAGE_HDR_SIZE; + BUF_PAGE_HDR_SIZE;
} }
...@@ -4400,8 +4404,13 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data) ...@@ -4400,8 +4404,13 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data)
{ {
struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu]; struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
struct buffer_data_page *bpage = data; struct buffer_data_page *bpage = data;
struct page *page = virt_to_page(bpage);
unsigned long flags; unsigned long flags;
/* If the page is still in use someplace else, we can't reuse it */
if (page_ref_count(page) > 1)
goto out;
local_irq_save(flags); local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock); arch_spin_lock(&cpu_buffer->lock);
...@@ -4413,6 +4422,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data) ...@@ -4413,6 +4422,7 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, int cpu, void *data)
arch_spin_unlock(&cpu_buffer->lock); arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags); local_irq_restore(flags);
out:
free_page((unsigned long)bpage); free_page((unsigned long)bpage);
} }
EXPORT_SYMBOL_GPL(ring_buffer_free_read_page); EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
......
...@@ -6769,7 +6769,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, ...@@ -6769,7 +6769,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
.spd_release = buffer_spd_release, .spd_release = buffer_spd_release,
}; };
struct buffer_ref *ref; struct buffer_ref *ref;
int entries, size, i; int entries, i;
ssize_t ret = 0; ssize_t ret = 0;
#ifdef CONFIG_TRACER_MAX_TRACE #ifdef CONFIG_TRACER_MAX_TRACE
...@@ -6823,14 +6823,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, ...@@ -6823,14 +6823,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
break; break;
} }
/*
* zero out any left over data, this is going to
* user land.
*/
size = ring_buffer_page_len(ref->page);
if (size < PAGE_SIZE)
memset(ref->page + size, 0, PAGE_SIZE - size);
page = virt_to_page(ref->page); page = virt_to_page(ref->page);
spd.pages[i] = page; spd.pages[i] = page;
...@@ -7588,6 +7580,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size ...@@ -7588,6 +7580,7 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size
buf->data = alloc_percpu(struct trace_array_cpu); buf->data = alloc_percpu(struct trace_array_cpu);
if (!buf->data) { if (!buf->data) {
ring_buffer_free(buf->buffer); ring_buffer_free(buf->buffer);
buf->buffer = NULL;
return -ENOMEM; return -ENOMEM;
} }
...@@ -7611,7 +7604,9 @@ static int allocate_trace_buffers(struct trace_array *tr, int size) ...@@ -7611,7 +7604,9 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)
allocate_snapshot ? size : 1); allocate_snapshot ? size : 1);
if (WARN_ON(ret)) { if (WARN_ON(ret)) {
ring_buffer_free(tr->trace_buffer.buffer); ring_buffer_free(tr->trace_buffer.buffer);
tr->trace_buffer.buffer = NULL;
free_percpu(tr->trace_buffer.data); free_percpu(tr->trace_buffer.data);
tr->trace_buffer.data = NULL;
return -ENOMEM; return -ENOMEM;
} }
tr->allocated_snapshot = allocate_snapshot; tr->allocated_snapshot = allocate_snapshot;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment