aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-06-10 09:46:00 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-06-10 09:46:00 -0400
commit8b8b36834d0fff67fc8668093f4312dd04dcf21d (patch)
tree7568cd26fbcc3f64168a73a1929088df42c57701 /kernel
parenta9fcaaac37b3baba1343f906f52aeb65c4d4e356 (diff)
ring-buffer: Check if buffer exists before polling
The per_cpu buffers are created one per possible CPU. But these do not mean that those CPUs are online, nor do they even exist. With the addition of the ring buffer polling, it assumes that the caller polls on an existing buffer. But this is not the case if the user reads trace_pipe from a CPU that does not exist, and this causes the kernel to crash. Simple fix is to check the cpu against buffer bitmask against to see if the buffer was allocated or not and return -ENODEV if it is not. More updates were done to pass the -ENODEV back up to userspace. Link: http://lkml.kernel.org/r/5393DB61.6060707@oracle.com Reported-by: Sasha Levin <sasha.levin@oracle.com> Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ring_buffer.c5
-rw-r--r--kernel/trace/trace.c22
2 files changed, 20 insertions, 7 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index c634868c2921..7c56c3d06943 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -543,7 +543,7 @@ static void rb_wake_up_waiters(struct irq_work *work)
543 * as data is added to any of the @buffer's cpu buffers. Otherwise 543 * as data is added to any of the @buffer's cpu buffers. Otherwise
544 * it will wait for data to be added to a specific cpu buffer. 544 * it will wait for data to be added to a specific cpu buffer.
545 */ 545 */
546void ring_buffer_wait(struct ring_buffer *buffer, int cpu) 546int ring_buffer_wait(struct ring_buffer *buffer, int cpu)
547{ 547{
548 struct ring_buffer_per_cpu *cpu_buffer; 548 struct ring_buffer_per_cpu *cpu_buffer;
549 DEFINE_WAIT(wait); 549 DEFINE_WAIT(wait);
@@ -557,6 +557,8 @@ void ring_buffer_wait(struct ring_buffer *buffer, int cpu)
557 if (cpu == RING_BUFFER_ALL_CPUS) 557 if (cpu == RING_BUFFER_ALL_CPUS)
558 work = &buffer->irq_work; 558 work = &buffer->irq_work;
559 else { 559 else {
560 if (!cpumask_test_cpu(cpu, buffer->cpumask))
561 return -ENODEV;
560 cpu_buffer = buffer->buffers[cpu]; 562 cpu_buffer = buffer->buffers[cpu];
561 work = &cpu_buffer->irq_work; 563 work = &cpu_buffer->irq_work;
562 } 564 }
@@ -591,6 +593,7 @@ void ring_buffer_wait(struct ring_buffer *buffer, int cpu)
591 schedule(); 593 schedule();
592 594
593 finish_wait(&work->waiters, &wait); 595 finish_wait(&work->waiters, &wait);
596 return 0;
594} 597}
595 598
596/** 599/**
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 16f7038d1f4d..56422f1decba 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1085,13 +1085,13 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
1085} 1085}
1086#endif /* CONFIG_TRACER_MAX_TRACE */ 1086#endif /* CONFIG_TRACER_MAX_TRACE */
1087 1087
1088static void wait_on_pipe(struct trace_iterator *iter) 1088static int wait_on_pipe(struct trace_iterator *iter)
1089{ 1089{
1090 /* Iterators are static, they should be filled or empty */ 1090 /* Iterators are static, they should be filled or empty */
1091 if (trace_buffer_iter(iter, iter->cpu_file)) 1091 if (trace_buffer_iter(iter, iter->cpu_file))
1092 return; 1092 return 0;
1093 1093
1094 ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file); 1094 return ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file);
1095} 1095}
1096 1096
1097#ifdef CONFIG_FTRACE_STARTUP_TEST 1097#ifdef CONFIG_FTRACE_STARTUP_TEST
@@ -4378,6 +4378,7 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table)
4378static int tracing_wait_pipe(struct file *filp) 4378static int tracing_wait_pipe(struct file *filp)
4379{ 4379{
4380 struct trace_iterator *iter = filp->private_data; 4380 struct trace_iterator *iter = filp->private_data;
4381 int ret;
4381 4382
4382 while (trace_empty(iter)) { 4383 while (trace_empty(iter)) {
4383 4384
@@ -4399,10 +4400,13 @@ static int tracing_wait_pipe(struct file *filp)
4399 4400
4400 mutex_unlock(&iter->mutex); 4401 mutex_unlock(&iter->mutex);
4401 4402
4402 wait_on_pipe(iter); 4403 ret = wait_on_pipe(iter);
4403 4404
4404 mutex_lock(&iter->mutex); 4405 mutex_lock(&iter->mutex);
4405 4406
4407 if (ret)
4408 return ret;
4409
4406 if (signal_pending(current)) 4410 if (signal_pending(current))
4407 return -EINTR; 4411 return -EINTR;
4408 } 4412 }
@@ -5327,8 +5331,12 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
5327 goto out_unlock; 5331 goto out_unlock;
5328 } 5332 }
5329 mutex_unlock(&trace_types_lock); 5333 mutex_unlock(&trace_types_lock);
5330 wait_on_pipe(iter); 5334 ret = wait_on_pipe(iter);
5331 mutex_lock(&trace_types_lock); 5335 mutex_lock(&trace_types_lock);
5336 if (ret) {
5337 size = ret;
5338 goto out_unlock;
5339 }
5332 if (signal_pending(current)) { 5340 if (signal_pending(current)) {
5333 size = -EINTR; 5341 size = -EINTR;
5334 goto out_unlock; 5342 goto out_unlock;
@@ -5538,8 +5546,10 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
5538 goto out; 5546 goto out;
5539 } 5547 }
5540 mutex_unlock(&trace_types_lock); 5548 mutex_unlock(&trace_types_lock);
5541 wait_on_pipe(iter); 5549 ret = wait_on_pipe(iter);
5542 mutex_lock(&trace_types_lock); 5550 mutex_lock(&trace_types_lock);
5551 if (ret)
5552 goto out;
5543 if (signal_pending(current)) { 5553 if (signal_pending(current)) {
5544 ret = -EINTR; 5554 ret = -EINTR;
5545 goto out; 5555 goto out;