aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2013-07-23 11:26:10 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-29 12:47:32 -0400
commit7272711a2fc64dd6ef980630e129d8731897ee56 (patch)
tree58dd0de2f65dc3700aed83808f1c5f3ecbc2eef8 /kernel
parente5dd03c411713c066b94e1d448359e5216115c1c (diff)
tracing: Change tracing_fops/snapshot_fops to rely on tracing_get_cpu()
commit 6484c71cbc170634fa131b6d022d86d61686b88b upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel')
-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 83fba3c576e8..0582a01a81e3 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2853,9 +2853,9 @@ static const struct seq_operations tracer_seq_ops = {
2853}; 2853};
2854 2854
2855static struct trace_iterator * 2855static struct trace_iterator *
2856__tracing_open(struct trace_array *tr, struct trace_cpu *tc, 2856__tracing_open(struct inode *inode, struct file *file, bool snapshot)
2857 struct inode *inode, struct file *file, bool snapshot)
2858{ 2857{
2858 struct trace_array *tr = inode->i_private;
2859 struct trace_iterator *iter; 2859 struct trace_iterator *iter;
2860 int cpu; 2860 int cpu;
2861 2861
@@ -2896,8 +2896,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
2896 iter->trace_buffer = &tr->trace_buffer; 2896 iter->trace_buffer = &tr->trace_buffer;
2897 iter->snapshot = snapshot; 2897 iter->snapshot = snapshot;
2898 iter->pos = -1; 2898 iter->pos = -1;
2899 iter->cpu_file = tracing_get_cpu(inode);
2899 mutex_init(&iter->mutex); 2900 mutex_init(&iter->mutex);
2900 iter->cpu_file = tc->cpu;
2901 2901
2902 /* Notify the tracer early; before we stop tracing. */ 2902 /* Notify the tracer early; before we stop tracing. */
2903 if (iter->trace && iter->trace->open) 2903 if (iter->trace && iter->trace->open)
@@ -2977,22 +2977,18 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp)
2977 2977
2978static int tracing_release(struct inode *inode, struct file *file) 2978static int tracing_release(struct inode *inode, struct file *file)
2979{ 2979{
2980 struct trace_array *tr = inode->i_private;
2980 struct seq_file *m = file->private_data; 2981 struct seq_file *m = file->private_data;
2981 struct trace_iterator *iter; 2982 struct trace_iterator *iter;
2982 struct trace_array *tr;
2983 int cpu; 2983 int cpu;
2984 2984
2985 /* Writes do not use seq_file, need to grab tr from inode */
2986 if (!(file->f_mode & FMODE_READ)) { 2985 if (!(file->f_mode & FMODE_READ)) {
2987 struct trace_cpu *tc = inode->i_private; 2986 trace_array_put(tr);
2988
2989 trace_array_put(tc->tr);
2990 return 0; 2987 return 0;
2991 } 2988 }
2992 2989
2990 /* Writes do not use seq_file */
2993 iter = m->private; 2991 iter = m->private;
2994 tr = iter->tr;
2995
2996 mutex_lock(&trace_types_lock); 2992 mutex_lock(&trace_types_lock);
2997 2993
2998 for_each_tracing_cpu(cpu) { 2994 for_each_tracing_cpu(cpu) {
@@ -3039,8 +3035,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
3039 3035
3040static int tracing_open(struct inode *inode, struct file *file) 3036static int tracing_open(struct inode *inode, struct file *file)
3041{ 3037{
3042 struct trace_cpu *tc = inode->i_private; 3038 struct trace_array *tr = inode->i_private;
3043 struct trace_array *tr = tc->tr;
3044 struct trace_iterator *iter; 3039 struct trace_iterator *iter;
3045 int ret = 0; 3040 int ret = 0;
3046 3041
@@ -3048,16 +3043,17 @@ static int tracing_open(struct inode *inode, struct file *file)
3048 return -ENODEV; 3043 return -ENODEV;
3049 3044
3050 /* If this file was open for write, then erase contents */ 3045 /* If this file was open for write, then erase contents */
3051 if ((file->f_mode & FMODE_WRITE) && 3046 if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
3052 (file->f_flags & O_TRUNC)) { 3047 int cpu = tracing_get_cpu(inode);
3053 if (tc->cpu == RING_BUFFER_ALL_CPUS) 3048
3049 if (cpu == RING_BUFFER_ALL_CPUS)
3054 tracing_reset_online_cpus(&tr->trace_buffer); 3050 tracing_reset_online_cpus(&tr->trace_buffer);
3055 else 3051 else
3056 tracing_reset(&tr->trace_buffer, tc->cpu); 3052 tracing_reset(&tr->trace_buffer, cpu);
3057 } 3053 }
3058 3054
3059 if (file->f_mode & FMODE_READ) { 3055 if (file->f_mode & FMODE_READ) {
3060 iter = __tracing_open(tr, tc, inode, file, false); 3056 iter = __tracing_open(inode, file, false);
3061 if (IS_ERR(iter)) 3057 if (IS_ERR(iter))
3062 ret = PTR_ERR(iter); 3058 ret = PTR_ERR(iter);
3063 else if (trace_flags & TRACE_ITER_LATENCY_FMT) 3059 else if (trace_flags & TRACE_ITER_LATENCY_FMT)
@@ -4672,8 +4668,7 @@ struct ftrace_buffer_info {
4672#ifdef CONFIG_TRACER_SNAPSHOT 4668#ifdef CONFIG_TRACER_SNAPSHOT
4673static int tracing_snapshot_open(struct inode *inode, struct file *file) 4669static int tracing_snapshot_open(struct inode *inode, struct file *file)
4674{ 4670{
4675 struct trace_cpu *tc = inode->i_private; 4671 struct trace_array *tr = inode->i_private;
4676 struct trace_array *tr = tc->tr;
4677 struct trace_iterator *iter; 4672 struct trace_iterator *iter;
4678 struct seq_file *m; 4673 struct seq_file *m;
4679 int ret = 0; 4674 int ret = 0;
@@ -4682,7 +4677,7 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
4682 return -ENODEV; 4677 return -ENODEV;
4683 4678
4684 if (file->f_mode & FMODE_READ) { 4679 if (file->f_mode & FMODE_READ) {
4685 iter = __tracing_open(tr, tc, inode, file, true); 4680 iter = __tracing_open(inode, file, true);
4686 if (IS_ERR(iter)) 4681 if (IS_ERR(iter))
4687 ret = PTR_ERR(iter); 4682 ret = PTR_ERR(iter);
4688 } else { 4683 } else {
@@ -4699,8 +4694,8 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
4699 ret = 0; 4694 ret = 0;
4700 4695
4701 iter->tr = tr; 4696 iter->tr = tr;
4702 iter->trace_buffer = &tc->tr->max_buffer; 4697 iter->trace_buffer = &tr->max_buffer;
4703 iter->cpu_file = tc->cpu; 4698 iter->cpu_file = tracing_get_cpu(inode);
4704 m->private = iter; 4699 m->private = iter;
4705 file->private_data = m; 4700 file->private_data = m;
4706 } 4701 }
@@ -5517,7 +5512,6 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
5517static void 5512static void
5518tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) 5513tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5519{ 5514{
5520 struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
5521 struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu); 5515 struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
5522 struct dentry *d_cpu; 5516 struct dentry *d_cpu;
5523 char cpu_dir[30]; /* 30 characters should be more than enough */ 5517 char cpu_dir[30]; /* 30 characters should be more than enough */
@@ -5538,7 +5532,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5538 5532
5539 /* per cpu trace */ 5533 /* per cpu trace */
5540 trace_create_cpu_file("trace", 0644, d_cpu, 5534 trace_create_cpu_file("trace", 0644, d_cpu,
5541 &data->trace_cpu, cpu, &tracing_fops); 5535 tr, cpu, &tracing_fops);
5542 5536
5543 trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu, 5537 trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
5544 tr, cpu, &tracing_buffers_fops); 5538 tr, cpu, &tracing_buffers_fops);
@@ -5551,7 +5545,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
5551 5545
5552#ifdef CONFIG_TRACER_SNAPSHOT 5546#ifdef CONFIG_TRACER_SNAPSHOT
5553 trace_create_cpu_file("snapshot", 0644, d_cpu, 5547 trace_create_cpu_file("snapshot", 0644, d_cpu,
5554 &data->trace_cpu, cpu, &snapshot_fops); 5548 tr, cpu, &snapshot_fops);
5555 5549
5556 trace_create_cpu_file("snapshot_raw", 0444, d_cpu, 5550 trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
5557 tr, cpu, &snapshot_raw_fops); 5551 tr, cpu, &snapshot_raw_fops);
@@ -6117,7 +6111,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
6117 tr, &tracing_iter_fops); 6111 tr, &tracing_iter_fops);
6118 6112
6119 trace_create_file("trace", 0644, d_tracer, 6113 trace_create_file("trace", 0644, d_tracer,
6120 (void *)&tr->trace_cpu, &tracing_fops); 6114 tr, &tracing_fops);
6121 6115
6122 trace_create_file("trace_pipe", 0444, d_tracer, 6116 trace_create_file("trace_pipe", 0444, d_tracer,
6123 tr, &tracing_pipe_fops); 6117 tr, &tracing_pipe_fops);
@@ -6138,11 +6132,11 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
6138 &trace_clock_fops); 6132 &trace_clock_fops);
6139 6133
6140 trace_create_file("tracing_on", 0644, d_tracer, 6134 trace_create_file("tracing_on", 0644, d_tracer,
6141 tr, &rb_simple_fops); 6135 tr, &rb_simple_fops);
6142 6136
6143#ifdef CONFIG_TRACER_SNAPSHOT 6137#ifdef CONFIG_TRACER_SNAPSHOT
6144 trace_create_file("snapshot", 0644, d_tracer, 6138 trace_create_file("snapshot", 0644, d_tracer,
6145 (void *)&tr->trace_cpu, &snapshot_fops); 6139 tr, &snapshot_fops);
6146#endif 6140#endif
6147 6141
6148 for_each_tracing_cpu(cpu) 6142 for_each_tracing_cpu(cpu)