aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-07-01 22:50:29 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-07-02 09:58:11 -0400
commitff451961a8b2a17667a7bfa39c86fb9b351445db (patch)
tree03f82366f860605664b4a7fe11a97f57fc0632a8 /kernel/trace/trace.c
parenta82274151af2b075163e3c42c828529dee311487 (diff)
tracing: Add trace_array_get/put() to handle instance refs better
Commit a695cb58162 "tracing: Prevent deleting instances when they are being read" tried to fix a race between deleting a trace instance and reading contents of a trace file. But it wasn't good enough. The following could crash the kernel: # cd /sys/kernel/debug/tracing/instances # ( while :; do mkdir foo; rmdir foo; done ) & # ( while :; do cat foo/trace &> /dev/null; done ) & Luckily this can only be done by root user, but it should be fixed regardless. The problem is that a delete of the file can happen after the reader starts to open the file but before it grabs the trace_types_mutex. The solution is to validate the trace array before using it. If the trace array does not exist in the list of trace arrays, then it returns -ENODEV. There's a possibility that a trace_array could be deleted and a new one created and the open would open its file instead. But that is very minor as it will just return the data of the new trace array, it may confuse the user but it will not crash the system. As this can only be done by root anyway, the race will only occur if root is deleting what its trying to read at the same time. Cc: stable@vger.kernel.org # 3.10 Reported-by: Alexander Lam <azl@google.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c83
1 files changed, 65 insertions, 18 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index e36da7ff59bf..6be9df1aa513 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -204,6 +204,37 @@ static struct trace_array global_trace;
204 204
205LIST_HEAD(ftrace_trace_arrays); 205LIST_HEAD(ftrace_trace_arrays);
206 206
207int trace_array_get(struct trace_array *this_tr)
208{
209 struct trace_array *tr;
210 int ret = -ENODEV;
211
212 mutex_lock(&trace_types_lock);
213 list_for_each_entry(tr, &ftrace_trace_arrays, list) {
214 if (tr == this_tr) {
215 tr->ref++;
216 ret = 0;
217 break;
218 }
219 }
220 mutex_unlock(&trace_types_lock);
221
222 return ret;
223}
224
225static void __trace_array_put(struct trace_array *this_tr)
226{
227 WARN_ON(!this_tr->ref);
228 this_tr->ref--;
229}
230
231void trace_array_put(struct trace_array *this_tr)
232{
233 mutex_lock(&trace_types_lock);
234 __trace_array_put(this_tr);
235 mutex_unlock(&trace_types_lock);
236}
237
207int filter_current_check_discard(struct ring_buffer *buffer, 238int filter_current_check_discard(struct ring_buffer *buffer,
208 struct ftrace_event_call *call, void *rec, 239 struct ftrace_event_call *call, void *rec,
209 struct ring_buffer_event *event) 240 struct ring_buffer_event *event)
@@ -2831,10 +2862,9 @@ static const struct seq_operations tracer_seq_ops = {
2831}; 2862};
2832 2863
2833static struct trace_iterator * 2864static struct trace_iterator *
2834__tracing_open(struct inode *inode, struct file *file, bool snapshot) 2865__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
2866 struct inode *inode, struct file *file, bool snapshot)
2835{ 2867{
2836 struct trace_cpu *tc = inode->i_private;
2837 struct trace_array *tr = tc->tr;
2838 struct trace_iterator *iter; 2868 struct trace_iterator *iter;
2839 int cpu; 2869 int cpu;
2840 2870
@@ -2913,8 +2943,6 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot)
2913 tracing_iter_reset(iter, cpu); 2943 tracing_iter_reset(iter, cpu);
2914 } 2944 }
2915 2945
2916 tr->ref++;
2917
2918 mutex_unlock(&trace_types_lock); 2946 mutex_unlock(&trace_types_lock);
2919 2947
2920 return iter; 2948 return iter;
@@ -2944,17 +2972,20 @@ static int tracing_release(struct inode *inode, struct file *file)
2944 struct trace_array *tr; 2972 struct trace_array *tr;
2945 int cpu; 2973 int cpu;
2946 2974
2947 if (!(file->f_mode & FMODE_READ)) 2975 /* Writes do not use seq_file, need to grab tr from inode */
2976 if (!(file->f_mode & FMODE_READ)) {
2977 struct trace_cpu *tc = inode->i_private;
2978
2979 trace_array_put(tc->tr);
2948 return 0; 2980 return 0;
2981 }
2949 2982
2950 iter = m->private; 2983 iter = m->private;
2951 tr = iter->tr; 2984 tr = iter->tr;
2985 trace_array_put(tr);
2952 2986
2953 mutex_lock(&trace_types_lock); 2987 mutex_lock(&trace_types_lock);
2954 2988
2955 WARN_ON(!tr->ref);
2956 tr->ref--;
2957
2958 for_each_tracing_cpu(cpu) { 2989 for_each_tracing_cpu(cpu) {
2959 if (iter->buffer_iter[cpu]) 2990 if (iter->buffer_iter[cpu])
2960 ring_buffer_read_finish(iter->buffer_iter[cpu]); 2991 ring_buffer_read_finish(iter->buffer_iter[cpu]);
@@ -2973,20 +3004,23 @@ static int tracing_release(struct inode *inode, struct file *file)
2973 kfree(iter->trace); 3004 kfree(iter->trace);
2974 kfree(iter->buffer_iter); 3005 kfree(iter->buffer_iter);
2975 seq_release_private(inode, file); 3006 seq_release_private(inode, file);
3007
2976 return 0; 3008 return 0;
2977} 3009}
2978 3010
2979static int tracing_open(struct inode *inode, struct file *file) 3011static int tracing_open(struct inode *inode, struct file *file)
2980{ 3012{
3013 struct trace_cpu *tc = inode->i_private;
3014 struct trace_array *tr = tc->tr;
2981 struct trace_iterator *iter; 3015 struct trace_iterator *iter;
2982 int ret = 0; 3016 int ret = 0;
2983 3017
3018 if (trace_array_get(tr) < 0)
3019 return -ENODEV;
3020
2984 /* If this file was open for write, then erase contents */ 3021 /* If this file was open for write, then erase contents */
2985 if ((file->f_mode & FMODE_WRITE) && 3022 if ((file->f_mode & FMODE_WRITE) &&
2986 (file->f_flags & O_TRUNC)) { 3023 (file->f_flags & O_TRUNC)) {
2987 struct trace_cpu *tc = inode->i_private;
2988 struct trace_array *tr = tc->tr;
2989
2990 if (tc->cpu == RING_BUFFER_ALL_CPUS) 3024 if (tc->cpu == RING_BUFFER_ALL_CPUS)
2991 tracing_reset_online_cpus(&tr->trace_buffer); 3025 tracing_reset_online_cpus(&tr->trace_buffer);
2992 else 3026 else
@@ -2994,12 +3028,16 @@ static int tracing_open(struct inode *inode, struct file *file)
2994 } 3028 }
2995 3029
2996 if (file->f_mode & FMODE_READ) { 3030 if (file->f_mode & FMODE_READ) {
2997 iter = __tracing_open(inode, file, false); 3031 iter = __tracing_open(tr, tc, inode, file, false);
2998 if (IS_ERR(iter)) 3032 if (IS_ERR(iter))
2999 ret = PTR_ERR(iter); 3033 ret = PTR_ERR(iter);
3000 else if (trace_flags & TRACE_ITER_LATENCY_FMT) 3034 else if (trace_flags & TRACE_ITER_LATENCY_FMT)
3001 iter->iter_flags |= TRACE_FILE_LAT_FMT; 3035 iter->iter_flags |= TRACE_FILE_LAT_FMT;
3002 } 3036 }
3037
3038 if (ret < 0)
3039 trace_array_put(tr);
3040
3003 return ret; 3041 return ret;
3004} 3042}
3005 3043
@@ -4575,12 +4613,16 @@ struct ftrace_buffer_info {
4575static int tracing_snapshot_open(struct inode *inode, struct file *file) 4613static int tracing_snapshot_open(struct inode *inode, struct file *file)
4576{ 4614{
4577 struct trace_cpu *tc = inode->i_private; 4615 struct trace_cpu *tc = inode->i_private;
4616 struct trace_array *tr = tc->tr;
4578 struct trace_iterator *iter; 4617 struct trace_iterator *iter;
4579 struct seq_file *m; 4618 struct seq_file *m;
4580 int ret = 0; 4619 int ret = 0;
4581 4620
4621 if (trace_array_get(tr) < 0)
4622 return -ENODEV;
4623
4582 if (file->f_mode & FMODE_READ) { 4624 if (file->f_mode & FMODE_READ) {
4583 iter = __tracing_open(inode, file, true); 4625 iter = __tracing_open(tr, tc, inode, file, true);
4584 if (IS_ERR(iter)) 4626 if (IS_ERR(iter))
4585 ret = PTR_ERR(iter); 4627 ret = PTR_ERR(iter);
4586 } else { 4628 } else {
@@ -4593,13 +4635,16 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
4593 kfree(m); 4635 kfree(m);
4594 return -ENOMEM; 4636 return -ENOMEM;
4595 } 4637 }
4596 iter->tr = tc->tr; 4638 iter->tr = tr;
4597 iter->trace_buffer = &tc->tr->max_buffer; 4639 iter->trace_buffer = &tc->tr->max_buffer;
4598 iter->cpu_file = tc->cpu; 4640 iter->cpu_file = tc->cpu;
4599 m->private = iter; 4641 m->private = iter;
4600 file->private_data = m; 4642 file->private_data = m;
4601 } 4643 }
4602 4644
4645 if (ret < 0)
4646 trace_array_put(tr);
4647
4603 return ret; 4648 return ret;
4604} 4649}
4605 4650
@@ -4680,9 +4725,12 @@ out:
4680static int tracing_snapshot_release(struct inode *inode, struct file *file) 4725static int tracing_snapshot_release(struct inode *inode, struct file *file)
4681{ 4726{
4682 struct seq_file *m = file->private_data; 4727 struct seq_file *m = file->private_data;
4728 int ret;
4729
4730 ret = tracing_release(inode, file);
4683 4731
4684 if (file->f_mode & FMODE_READ) 4732 if (file->f_mode & FMODE_READ)
4685 return tracing_release(inode, file); 4733 return ret;
4686 4734
4687 /* If write only, the seq_file is just a stub */ 4735 /* If write only, the seq_file is just a stub */
4688 if (m) 4736 if (m)
@@ -4927,8 +4975,7 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)
4927 4975
4928 mutex_lock(&trace_types_lock); 4976 mutex_lock(&trace_types_lock);
4929 4977
4930 WARN_ON(!iter->tr->ref); 4978 __trace_array_put(iter->tr);
4931 iter->tr->ref--;
4932 4979
4933 if (info->spare) 4980 if (info->spare)
4934 ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare); 4981 ring_buffer_free_read_page(iter->trace_buffer->buffer, info->spare);