diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-07-23 11:26:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-08-29 12:47:32 -0400 |
commit | 7272711a2fc64dd6ef980630e129d8731897ee56 (patch) | |
tree | 58dd0de2f65dc3700aed83808f1c5f3ecbc2eef8 /kernel | |
parent | e5dd03c411713c066b94e1d448359e5216115c1c (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.c | 50 |
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 | ||
2855 | static struct trace_iterator * | 2855 | static 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 | ||
2978 | static int tracing_release(struct inode *inode, struct file *file) | 2978 | static 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 | ||
3040 | static int tracing_open(struct inode *inode, struct file *file) | 3036 | static 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 |
4673 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4669 | static 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, | |||
5517 | static void | 5512 | static void |
5518 | tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) | 5513 | tracing_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) |