aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-07-23 11:26:10 -0400
committerSteven Rostedt <rostedt@rostedt.homelinux.com>2013-07-24 11:22:53 -0400
commit6484c71cbc170634fa131b6d022d86d61686b88b (patch)
tree68f696f4985f368a2fa7f93a2d474fea2c7585db
parent0bc392ee46d0fd8e6b678457ef71f074f19a03c5 (diff)
tracing: Change tracing_fops/snapshot_fops to rely on tracing_get_cpu()
tracing_open() and tracing_snapshot_open() are racy, the memory inode->i_private points to can be already freed. Convert these last users of "inode->i_private == trace_cpu" to use "i_private = trace_array" and rely on tracing_get_cpu(). v2: incorporate the fix from Steven, tracing_release() must not blindly dereference file->private_data unless we know that the file was opened for reading. Link: http://lkml.kernel.org/r/20130723152610.GA23737@redhat.com Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--kernel/trace/trace.c50
1 files changed, 22 insertions, 28 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 68b46851666f..dd7780ddde08 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2862,9 +2862,9 @@ static const struct seq_operations tracer_seq_ops = {
2862}; 2862};
2863 2863
2864static struct trace_iterator * 2864static struct trace_iterator *
2865__tracing_open(struct trace_array *tr, struct trace_cpu *tc, 2865__tracing_open(struct inode *inode, struct file *file, bool snapshot)
2866 struct inode *inode, struct file *file, bool snapshot)
2867{ 2866{
2867 struct trace_array *tr = inode->i_private;
2868 struct trace_iterator *iter; 2868 struct trace_iterator *iter;
2869 int cpu; 2869 int cpu;
2870 2870
@@ -2905,8 +2905,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
2905 iter->trace_buffer = &tr->trace_buffer; 2905 iter->trace_buffer = &tr->trace_buffer;
2906 iter->snapshot = snapshot; 2906 iter->snapshot = snapshot;
2907 iter->pos = -1; 2907 iter->pos = -1;
2908 iter->cpu_file = tracing_get_cpu(inode);
2908 mutex_init(&iter->mutex); 2909 mutex_init(&iter->mutex);
2909 iter->cpu_file = tc->cpu;
2910 2910
2911 /* Notify the tracer early; before we stop tracing. */ 2911 /* Notify the tracer early; before we stop tracing. */
2912 if (iter->trace && iter->trace->open) 2912 if (iter->trace && iter->trace->open)
@@ -2986,22 +2986,18 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
2986 2986
2987static int tracing_release(struct inode *inode, struct file *file) 2987static int tracing_release(struct inode *inode, struct file *file)
2988{ 2988{
2989 struct trace_array *tr = inode->i_private;
2989 struct seq_file *m = file->private_data; 2990 struct seq_file *m = file->private_data;
2990 struct trace_iterator *iter; 2991 struct trace_iterator *iter;
2991 struct trace_array *tr;
2992 int cpu; 2992 int cpu;
2993 2993
2994 /* Writes do not use seq_file, need to grab tr from inode */
2995 if (!(file->f_mode & FMODE_READ)) { 2994 if (!(file->f_mode & FMODE_READ)) {
2996 struct trace_cpu *tc = inode->i_private; 2995 trace_array_put(tr);
2997
2998 trace_array_put(tc->tr);
2999 return 0; 2996 return 0;
3000 } 2997 }
3001 2998
2999 /* Writes do not use seq_file */
3002 iter = m->private; 3000 iter = m->private;
3003 tr = iter->tr;
3004
3005 mutex_lock(&trace_types_lock); 3001 mutex_lock(&trace_types_lock);
3006 3002
3007 for_each_tracing_cpu(cpu) { 3003 for_each_tracing_cpu(cpu) {
@@ -3048,8 +3044,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
3048 3044
3049static int tracing_open(struct inode *inode, struct file *file) 3045static int tracing_open(struct inode *inode, struct file *file)
3050{ 3046{
3051 struct trace_cpu *tc = inode->i_private; 3047 struct trace_array *tr = inode->i_private;
3052 struct trace_array *tr = tc->tr;
3053 struct trace_iterator *iter; 3048 struct trace_iterator *iter;
3054 int ret = 0; 3049 int ret = 0;
3055 3050
@@ -3057,16 +3052,17 @@ static int tracing_open(struct inode *inode, struct file *file)
3057 return -ENODEV; 3052 return -ENODEV;
3058 3053
3059 /* If this file was open for write, then erase contents */ 3054 /* If this file was open for write, then erase contents */
3060 if ((file->f_mode & FMODE_WRITE) && 3055 if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
3061 (file->f_flags & O_TRUNC)) { 3056 int cpu = tracing_get_cpu(inode);
3062 if (tc->cpu == RING_BUFFER_ALL_CPUS) 3057
3058 if (cpu == RING_BUFFER_ALL_CPUS)
3063 tracing_reset_online_cpus(&tr->trace_buffer); 3059 tracing_reset_online_cpus(&tr->trace_buffer);
3064 else 3060 else
3065 tracing_reset(&tr->trace_buffer, tc->cpu); 3061 tracing_reset(&tr->trace_buffer, cpu);
3066 } 3062 }
3067 3063
3068 if (file->f_mode & FMODE_READ) { 3064 if (file->f_mode & FMODE_READ) {
3069 iter = __tracing_open(tr, tc, inode, file, false); 3065 iter = __tracing_open(inode, file, false);
3070 if (IS_ERR(iter)) 3066 if (IS_ERR(iter))
3071 ret = PTR_ERR(iter); 3067 ret = PTR_ERR(iter);
3072 else if (trace_flags & TRACE_ITER_LATENCY_FMT) 3068 else if (trace_flags & TRACE_ITER_LATENCY_FMT)
@@ -4680,8 +4676,7 @@ struct ftrace_buffer_info {
4680#ifdef CONFIG_TRACER_SNAPSHOT 4676#ifdef CONFIG_TRACER_SNAPSHOT
4681static int tracing_snapshot_open(struct inode *inode, struct file *file) 4677static int tracing_snapshot_open(struct inode *inode, struct file *file)
4682{ 4678{
4683 struct trace_cpu *tc = inode->i_private; 4679 struct trace_array *tr = inode->i_private;
4684 struct trace_array *tr = tc->tr;
4685 struct trace_iterator *iter; 4680 struct trace_iterator *iter;
4686 struct seq_file *m; 4681 struct seq_file *m;
4687 int ret = 0; 4682 int ret = 0;
@@ -4690,7 +4685,7 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
4690 return -ENODEV; 4685 return -ENODEV;
4691 4686
4692 if (file->f_mode & FMODE_READ) { 4687 if (file->f_mode & FMODE_READ) {
4693 iter = __tracing_open(tr, tc, inode, file, true); 4688 iter = __tracing_open(inode, file, true);
4694 if (IS_ERR(iter)) 4689 if (IS_ERR(iter))
4695 ret = PTR_ERR(iter); 4690 ret = PTR_ERR(iter);
4696 } else { 4691 } else {
@@ -4707,8 +4702,8 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
4707 ret = 0; 4702 ret = 0;
4708 4703
4709 iter->tr = tr; 4704 iter->tr = tr;
4710 iter->trace_buffer = &tc->tr->max_buffer; 4705 iter->trace_buffer = &tr->max_buffer;
4711 iter->cpu_file = tc->cpu; 4706 iter->cpu_file = tracing_get_cpu(inode);
4712 m->private = iter; 4707 m->private = iter;
4713 file->private_data = m; 4708 file->private_data = m;
4714 } 4709 }
@@ -5525,7 +5520,6 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
5525static void 5520static void
5526tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) 5521tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5527{ 5522{
5528 struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
5529 struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu); 5523 struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
5530 struct dentry *d_cpu; 5524 struct dentry *d_cpu;
5531 char cpu_dir[30]; /* 30 characters should be more than enough */ 5525 char cpu_dir[30]; /* 30 characters should be more than enough */
@@ -5546,7 +5540,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5546 5540
5547 /* per cpu trace */ 5541 /* per cpu trace */
5548 trace_create_cpu_file("trace", 0644, d_cpu, 5542 trace_create_cpu_file("trace", 0644, d_cpu,
5549 &data->trace_cpu, cpu, &tracing_fops); 5543 tr, cpu, &tracing_fops);
5550 5544
5551 trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu, 5545 trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
5552 tr, cpu, &tracing_buffers_fops); 5546 tr, cpu, &tracing_buffers_fops);
@@ -5559,7 +5553,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5559 5553
5560#ifdef CONFIG_TRACER_SNAPSHOT 5554#ifdef CONFIG_TRACER_SNAPSHOT
5561 trace_create_cpu_file("snapshot", 0644, d_cpu, 5555 trace_create_cpu_file("snapshot", 0644, d_cpu,
5562 &data->trace_cpu, cpu, &snapshot_fops); 5556 tr, cpu, &snapshot_fops);
5563 5557
5564 trace_create_cpu_file("snapshot_raw", 0444, d_cpu, 5558 trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
5565 tr, cpu, &snapshot_raw_fops); 5559 tr, cpu, &snapshot_raw_fops);
@@ -6125,7 +6119,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
6125 tr, &tracing_iter_fops); 6119 tr, &tracing_iter_fops);
6126 6120
6127 trace_create_file("trace", 0644, d_tracer, 6121 trace_create_file("trace", 0644, d_tracer,
6128 (void *)&tr->trace_cpu, &tracing_fops); 6122 tr, &tracing_fops);
6129 6123
6130 trace_create_file("trace_pipe", 0444, d_tracer, 6124 trace_create_file("trace_pipe", 0444, d_tracer,
6131 tr, &tracing_pipe_fops); 6125 tr, &tracing_pipe_fops);
@@ -6146,11 +6140,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
6146 &trace_clock_fops); 6140 &trace_clock_fops);
6147 6141
6148 trace_create_file("tracing_on", 0644, d_tracer, 6142 trace_create_file("tracing_on", 0644, d_tracer,
6149 tr, &rb_simple_fops); 6143 tr, &rb_simple_fops);
6150 6144
6151#ifdef CONFIG_TRACER_SNAPSHOT 6145#ifdef CONFIG_TRACER_SNAPSHOT
6152 trace_create_file("snapshot", 0644, d_tracer, 6146 trace_create_file("snapshot", 0644, d_tracer,
6153 (void *)&tr->trace_cpu, &snapshot_fops); 6147 tr, &snapshot_fops);
6154#endif 6148#endif
6155 6149
6156 for_each_tracing_cpu(cpu) 6150 for_each_tracing_cpu(cpu)