diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 139 | 
1 files changed, 87 insertions, 52 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 252f79c435f8..6a0ee9178365 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -17,6 +17,7 @@  #include <linux/stacktrace.h>  #include <linux/writeback.h>  #include <linux/kallsyms.h> +#include <linux/security.h>  #include <linux/seq_file.h>  #include <linux/notifier.h>  #include <linux/irqflags.h> @@ -304,6 +305,23 @@ void trace_array_put(struct trace_array *this_tr)  	mutex_unlock(&trace_types_lock);  } +int tracing_check_open_get_tr(struct trace_array *tr) +{ +	int ret; + +	ret = security_locked_down(LOCKDOWN_TRACEFS); +	if (ret) +		return ret; + +	if (tracing_disabled) +		return -ENODEV; + +	if (tr && trace_array_get(tr) < 0) +		return -ENODEV; + +	return 0; +} +  int call_filter_check_discard(struct trace_event_call *call, void *rec,  			      struct ring_buffer *buffer,  			      struct ring_buffer_event *event) @@ -4140,8 +4158,11 @@ release:  int tracing_open_generic(struct inode *inode, struct file *filp)  { -	if (tracing_disabled) -		return -ENODEV; +	int ret; + +	ret = tracing_check_open_get_tr(NULL); +	if (ret) +		return ret;  	filp->private_data = inode->i_private;  	return 0; @@ -4156,15 +4177,14 @@ bool tracing_is_disabled(void)   * Open and update trace_array ref count.   * Must have the current trace_array passed to it.   */ -static int tracing_open_generic_tr(struct inode *inode, struct file *filp) +int tracing_open_generic_tr(struct inode *inode, struct file *filp)  {  	struct trace_array *tr = inode->i_private; +	int ret; -	if (tracing_disabled) -		return -ENODEV; - -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	filp->private_data = inode->i_private; @@ -4233,10 +4253,11 @@ static int tracing_open(struct inode *inode, struct file *file)  {  	struct trace_array *tr = inode->i_private;  	struct trace_iterator *iter; -	int ret = 0; +	int ret; -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	/* If this file was open for write, then erase contents */  	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { @@ -4352,12 +4373,15 @@ static int show_traces_open(struct inode *inode, struct file *file)  	struct seq_file *m;  	int ret; -	if (tracing_disabled) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	ret = seq_open(file, &show_traces_seq_ops); -	if (ret) +	if (ret) { +		trace_array_put(tr);  		return ret; +	}  	m = file->private_data;  	m->private = tr; @@ -4365,6 +4389,14 @@ static int show_traces_open(struct inode *inode, struct file *file)  	return 0;  } +static int show_traces_release(struct inode *inode, struct file *file) +{ +	struct trace_array *tr = inode->i_private; + +	trace_array_put(tr); +	return seq_release(inode, file); +} +  static ssize_t  tracing_write_stub(struct file *filp, const char __user *ubuf,  		   size_t count, loff_t *ppos) @@ -4395,8 +4427,8 @@ static const struct file_operations tracing_fops = {  static const struct file_operations show_traces_fops = {  	.open		= show_traces_open,  	.read		= seq_read, -	.release	= seq_release,  	.llseek		= seq_lseek, +	.release	= show_traces_release,  };  static ssize_t @@ -4697,11 +4729,9 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)  	struct trace_array *tr = inode->i_private;  	int ret; -	if (tracing_disabled) -		return -ENODEV; - -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	ret = single_open(file, tracing_trace_options_show, inode->i_private);  	if (ret < 0) @@ -5038,8 +5068,11 @@ static const struct seq_operations tracing_saved_tgids_seq_ops = {  static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)  { -	if (tracing_disabled) -		return -ENODEV; +	int ret; + +	ret = tracing_check_open_get_tr(NULL); +	if (ret) +		return ret;  	return seq_open(filp, &tracing_saved_tgids_seq_ops);  } @@ -5115,8 +5148,11 @@ static const struct seq_operations tracing_saved_cmdlines_seq_ops = {  static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp)  { -	if (tracing_disabled) -		return -ENODEV; +	int ret; + +	ret = tracing_check_open_get_tr(NULL); +	if (ret) +		return ret;  	return seq_open(filp, &tracing_saved_cmdlines_seq_ops);  } @@ -5280,8 +5316,11 @@ static const struct seq_operations tracing_eval_map_seq_ops = {  static int tracing_eval_map_open(struct inode *inode, struct file *filp)  { -	if (tracing_disabled) -		return -ENODEV; +	int ret; + +	ret = tracing_check_open_get_tr(NULL); +	if (ret) +		return ret;  	return seq_open(filp, &tracing_eval_map_seq_ops);  } @@ -5804,13 +5843,11 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)  {  	struct trace_array *tr = inode->i_private;  	struct trace_iterator *iter; -	int ret = 0; - -	if (tracing_disabled) -		return -ENODEV; +	int ret; -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	mutex_lock(&trace_types_lock); @@ -5999,6 +6036,7 @@ waitagain:  	       sizeof(struct trace_iterator) -  	       offsetof(struct trace_iterator, seq));  	cpumask_clear(iter->started); +	trace_seq_init(&iter->seq);  	iter->pos = -1;  	trace_event_read_lock(); @@ -6547,11 +6585,9 @@ static int tracing_clock_open(struct inode *inode, struct file *file)  	struct trace_array *tr = inode->i_private;  	int ret; -	if (tracing_disabled) -		return -ENODEV; - -	if (trace_array_get(tr)) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	ret = single_open(file, tracing_clock_show, inode->i_private);  	if (ret < 0) @@ -6581,11 +6617,9 @@ static int tracing_time_stamp_mode_open(struct inode *inode, struct file *file)  	struct trace_array *tr = inode->i_private;  	int ret; -	if (tracing_disabled) -		return -ENODEV; - -	if (trace_array_get(tr)) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	ret = single_open(file, tracing_time_stamp_mode_show, inode->i_private);  	if (ret < 0) @@ -6638,10 +6672,11 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)  	struct trace_array *tr = inode->i_private;  	struct trace_iterator *iter;  	struct seq_file *m; -	int ret = 0; +	int ret; -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	if (file->f_mode & FMODE_READ) {  		iter = __tracing_open(inode, file, true); @@ -6786,6 +6821,7 @@ static int snapshot_raw_open(struct inode *inode, struct file *filp)  	struct ftrace_buffer_info *info;  	int ret; +	/* The following checks for tracefs lockdown */  	ret = tracing_buffers_open(inode, filp);  	if (ret < 0)  		return ret; @@ -7105,8 +7141,9 @@ static int tracing_err_log_open(struct inode *inode, struct file *file)  	struct trace_array *tr = inode->i_private;  	int ret = 0; -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	/* If this file was opened for write, then erase contents */  	if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) @@ -7157,11 +7194,9 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)  	struct ftrace_buffer_info *info;  	int ret; -	if (tracing_disabled) -		return -ENODEV; - -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	info = kzalloc(sizeof(*info), GFP_KERNEL);  	if (!info) {  | 
