diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-23 11:26:10 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@rostedt.homelinux.com> | 2013-07-24 11:22:53 -0400 |
commit | 6484c71cbc170634fa131b6d022d86d61686b88b (patch) | |
tree | 68f696f4985f368a2fa7f93a2d474fea2c7585db | |
parent | 0bc392ee46d0fd8e6b678457ef71f074f19a03c5 (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.c | 50 |
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 | ||
2864 | static struct trace_iterator * | 2864 | static 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 | ||
2987 | static int tracing_release(struct inode *inode, struct file *file) | 2987 | static 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 | ||
3049 | static int tracing_open(struct inode *inode, struct file *file) | 3045 | static 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 |
4681 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4677 | static 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, | |||
5525 | static void | 5520 | static void |
5526 | tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) | 5521 | tracing_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) |