diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -rw-r--r-- | kernel/trace/ftrace.c | 55 | 
1 files changed, 43 insertions, 12 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 62a50bf399d6..f296d89be757 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -18,6 +18,7 @@  #include <linux/clocksource.h>  #include <linux/sched/task.h>  #include <linux/kallsyms.h> +#include <linux/security.h>  #include <linux/seq_file.h>  #include <linux/tracefs.h>  #include <linux/hardirq.h> @@ -3486,6 +3487,11 @@ static int  ftrace_avail_open(struct inode *inode, struct file *file)  {  	struct ftrace_iterator *iter; +	int ret; + +	ret = security_locked_down(LOCKDOWN_TRACEFS); +	if (ret) +		return ret;  	if (unlikely(ftrace_disabled))  		return -ENODEV; @@ -3505,6 +3511,15 @@ ftrace_enabled_open(struct inode *inode, struct file *file)  {  	struct ftrace_iterator *iter; +	/* +	 * This shows us what functions are currently being +	 * traced and by what. Not sure if we want lockdown +	 * to hide such critical information for an admin. +	 * Although, perhaps it can show information we don't +	 * want people to see, but if something is tracing +	 * something, we probably want to know about it. +	 */ +  	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));  	if (!iter)  		return -ENOMEM; @@ -3540,21 +3555,22 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  	struct ftrace_hash *hash;  	struct list_head *mod_head;  	struct trace_array *tr = ops->private; -	int ret = 0; +	int ret = -ENOMEM;  	ftrace_ops_init(ops);  	if (unlikely(ftrace_disabled))  		return -ENODEV; +	if (tracing_check_open_get_tr(tr)) +		return -ENODEV; +  	iter = kzalloc(sizeof(*iter), GFP_KERNEL);  	if (!iter) -		return -ENOMEM; +		goto out; -	if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) { -		kfree(iter); -		return -ENOMEM; -	} +	if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) +		goto out;  	iter->ops = ops;  	iter->flags = flag; @@ -3584,13 +3600,13 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  		if (!iter->hash) {  			trace_parser_put(&iter->parser); -			kfree(iter); -			ret = -ENOMEM;  			goto out_unlock;  		}  	} else  		iter->hash = hash; +	ret = 0; +  	if (file->f_mode & FMODE_READ) {  		iter->pg = ftrace_pages_start; @@ -3602,7 +3618,6 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,  			/* Failed */  			free_ftrace_hash(iter->hash);  			trace_parser_put(&iter->parser); -			kfree(iter);  		}  	} else  		file->private_data = iter; @@ -3610,6 +3625,13 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,   out_unlock:  	mutex_unlock(&ops->func_hash->regex_lock); + out: +	if (ret) { +		kfree(iter); +		if (tr) +			trace_array_put(tr); +	} +  	return ret;  } @@ -3618,6 +3640,7 @@ ftrace_filter_open(struct inode *inode, struct file *file)  {  	struct ftrace_ops *ops = inode->i_private; +	/* Checks for tracefs lockdown */  	return ftrace_regex_open(ops,  			FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES,  			inode, file); @@ -3628,6 +3651,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file)  {  	struct ftrace_ops *ops = inode->i_private; +	/* Checks for tracefs lockdown */  	return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE,  				 inode, file);  } @@ -5037,6 +5061,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  	mutex_unlock(&iter->ops->func_hash->regex_lock);  	free_ftrace_hash(iter->hash); +	if (iter->tr) +		trace_array_put(iter->tr);  	kfree(iter);  	return 0; @@ -5194,9 +5220,13 @@ static int  __ftrace_graph_open(struct inode *inode, struct file *file,  		    struct ftrace_graph_data *fgd)  { -	int ret = 0; +	int ret;  	struct ftrace_hash *new_hash = NULL; +	ret = security_locked_down(LOCKDOWN_TRACEFS); +	if (ret) +		return ret; +  	if (file->f_mode & FMODE_WRITE) {  		const int size_bits = FTRACE_HASH_DEFAULT_BITS; @@ -6537,8 +6567,9 @@ ftrace_pid_open(struct inode *inode, struct file *file)  	struct seq_file *m;  	int ret = 0; -	if (trace_array_get(tr) < 0) -		return -ENODEV; +	ret = tracing_check_open_get_tr(tr); +	if (ret) +		return ret;  	if ((file->f_mode & FMODE_WRITE) &&  	    (file->f_flags & O_TRUNC))  | 
