A few tracing fixes:

- Removed locked down from tracefs itself and moved it to the trace
    directory. Having the open functions there do the lockdown checks.
 
  - Fixed a few races with opening an instance file and the instance being
    deleted (Discovered during the locked down updates). Kept separate
    from the clean up code such that they can be backported to stable
    easier.
 
  - Cleaned up and consolidated the checks done when opening a trace
    file, as there were multiple checks that need to be done, and it
    did not make sense having them done in each open instance.
 
  - Fixed a regression in the record mcount code.
 
  - Small hw_lat detector tracer fixes.
 
  - A trace_pipe read fix due to not initializing trace_seq.
 -----BEGIN PGP SIGNATURE-----
 
 iIoEABYIADIWIQRRSw7ePDh/lE+zeZMp5XQQmuv6qgUCXaNhphQccm9zdGVkdEBn
 b29kbWlzLm9yZwAKCRAp5XQQmuv6quDIAP4v08ARNdIh+r+c4AOBm3xsOuE/d9GB
 I56ydnskm+x2JQD6Ap9ivXe9yDBIErFeHNtCoq7pM8YDI4YoYIB30N0GfwM=
 =7oAu
 -----END PGP SIGNATURE-----

Merge tag 'trace-v5.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:
 "A few tracing fixes:

   - Remove lockdown from tracefs itself and moved it to the trace
     directory. Have the open functions there do the lockdown checks.

   - Fix a few races with opening an instance file and the instance
     being deleted (Discovered during the lockdown updates). Kept
     separate from the clean up code such that they can be backported to
     stable easier.

   - Clean up and consolidated the checks done when opening a trace
     file, as there were multiple checks that need to be done, and it
     did not make sense having them done in each open instance.

   - Fix a regression in the record mcount code.

   - Small hw_lat detector tracer fixes.

   - A trace_pipe read fix due to not initializing trace_seq"

* tag 'trace-v5.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
  tracing: Initialize iter->seq after zeroing in tracing_read_pipe()
  tracing/hwlat: Don't ignore outer-loop duration when calculating max_latency
  tracing/hwlat: Report total time spent in all NMIs during the sample
  recordmcount: Fix nop_mcount() function
  tracing: Do not create tracefs files if tracefs lockdown is in effect
  tracing: Add locked_down checks to the open calls of files created for tracefs
  tracing: Add tracing_check_open_get_tr()
  tracing: Have trace events system open call tracing_open_generic_tr()
  tracing: Get trace_array reference for available_tracers files
  ftrace: Get a reference counter for the trace_array on filter files
  tracefs: Revert ccbd54ff54 ("tracefs: Restrict tracefs when the kernel is locked down")
This commit is contained in:
Linus Torvalds 2019-10-13 14:47:10 -07:00
commit d4615e5a46
15 changed files with 224 additions and 133 deletions

View File

@ -16,11 +16,11 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/tracefs.h> #include <linux/tracefs.h>
#include <linux/fsnotify.h> #include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/security.h>
#define TRACEFS_DEFAULT_MODE 0700 #define TRACEFS_DEFAULT_MODE 0700
@ -28,25 +28,6 @@ static struct vfsmount *tracefs_mount;
static int tracefs_mount_count; static int tracefs_mount_count;
static bool tracefs_registered; static bool tracefs_registered;
static int default_open_file(struct inode *inode, struct file *filp)
{
struct dentry *dentry = filp->f_path.dentry;
struct file_operations *real_fops;
int ret;
if (!dentry)
return -EINVAL;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
real_fops = dentry->d_fsdata;
if (!real_fops->open)
return 0;
return real_fops->open(inode, filp);
}
static ssize_t default_read_file(struct file *file, char __user *buf, static ssize_t default_read_file(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
@ -241,12 +222,6 @@ static int tracefs_apply_options(struct super_block *sb)
return 0; return 0;
} }
static void tracefs_destroy_inode(struct inode *inode)
{
if (S_ISREG(inode->i_mode))
kfree(inode->i_fop);
}
static int tracefs_remount(struct super_block *sb, int *flags, char *data) static int tracefs_remount(struct super_block *sb, int *flags, char *data)
{ {
int err; int err;
@ -283,7 +258,6 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root)
static const struct super_operations tracefs_super_operations = { static const struct super_operations tracefs_super_operations = {
.statfs = simple_statfs, .statfs = simple_statfs,
.remount_fs = tracefs_remount, .remount_fs = tracefs_remount,
.destroy_inode = tracefs_destroy_inode,
.show_options = tracefs_show_options, .show_options = tracefs_show_options,
}; };
@ -414,10 +388,12 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data, struct dentry *parent, void *data,
const struct file_operations *fops) const struct file_operations *fops)
{ {
struct file_operations *proxy_fops;
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
if (security_locked_down(LOCKDOWN_TRACEFS))
return NULL;
if (!(mode & S_IFMT)) if (!(mode & S_IFMT))
mode |= S_IFREG; mode |= S_IFREG;
BUG_ON(!S_ISREG(mode)); BUG_ON(!S_ISREG(mode));
@ -430,20 +406,8 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
if (unlikely(!inode)) if (unlikely(!inode))
return failed_creating(dentry); return failed_creating(dentry);
proxy_fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
if (unlikely(!proxy_fops)) {
iput(inode);
return failed_creating(dentry);
}
if (!fops)
fops = &tracefs_file_operations;
dentry->d_fsdata = (void *)fops;
memcpy(proxy_fops, fops, sizeof(*proxy_fops));
proxy_fops->open = default_open_file;
inode->i_mode = mode; inode->i_mode = mode;
inode->i_fop = proxy_fops; inode->i_fop = fops ? fops : &tracefs_file_operations;
inode->i_private = data; inode->i_private = data;
d_instantiate(dentry, inode); d_instantiate(dentry, inode);
fsnotify_create(dentry->d_parent->d_inode, dentry); fsnotify_create(dentry->d_parent->d_inode, dentry);

View File

@ -18,6 +18,7 @@
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/sched/task.h> #include <linux/sched/task.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/security.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/tracefs.h> #include <linux/tracefs.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
@ -3486,6 +3487,11 @@ static int
ftrace_avail_open(struct inode *inode, struct file *file) ftrace_avail_open(struct inode *inode, struct file *file)
{ {
struct ftrace_iterator *iter; struct ftrace_iterator *iter;
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
if (unlikely(ftrace_disabled)) if (unlikely(ftrace_disabled))
return -ENODEV; return -ENODEV;
@ -3505,6 +3511,15 @@ ftrace_enabled_open(struct inode *inode, struct file *file)
{ {
struct ftrace_iterator *iter; 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)); iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
if (!iter) if (!iter)
return -ENOMEM; return -ENOMEM;
@ -3540,21 +3555,22 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
struct ftrace_hash *hash; struct ftrace_hash *hash;
struct list_head *mod_head; struct list_head *mod_head;
struct trace_array *tr = ops->private; struct trace_array *tr = ops->private;
int ret = 0; int ret = -ENOMEM;
ftrace_ops_init(ops); ftrace_ops_init(ops);
if (unlikely(ftrace_disabled)) if (unlikely(ftrace_disabled))
return -ENODEV; return -ENODEV;
if (tracing_check_open_get_tr(tr))
return -ENODEV;
iter = kzalloc(sizeof(*iter), GFP_KERNEL); iter = kzalloc(sizeof(*iter), GFP_KERNEL);
if (!iter) if (!iter)
return -ENOMEM; goto out;
if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX)) { if (trace_parser_get_init(&iter->parser, FTRACE_BUFF_MAX))
kfree(iter); goto out;
return -ENOMEM;
}
iter->ops = ops; iter->ops = ops;
iter->flags = flag; iter->flags = flag;
@ -3584,13 +3600,13 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
if (!iter->hash) { if (!iter->hash) {
trace_parser_put(&iter->parser); trace_parser_put(&iter->parser);
kfree(iter);
ret = -ENOMEM;
goto out_unlock; goto out_unlock;
} }
} else } else
iter->hash = hash; iter->hash = hash;
ret = 0;
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
iter->pg = ftrace_pages_start; iter->pg = ftrace_pages_start;
@ -3602,7 +3618,6 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
/* Failed */ /* Failed */
free_ftrace_hash(iter->hash); free_ftrace_hash(iter->hash);
trace_parser_put(&iter->parser); trace_parser_put(&iter->parser);
kfree(iter);
} }
} else } else
file->private_data = iter; file->private_data = iter;
@ -3610,6 +3625,13 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
out_unlock: out_unlock:
mutex_unlock(&ops->func_hash->regex_lock); mutex_unlock(&ops->func_hash->regex_lock);
out:
if (ret) {
kfree(iter);
if (tr)
trace_array_put(tr);
}
return ret; return ret;
} }
@ -3618,6 +3640,7 @@ ftrace_filter_open(struct inode *inode, struct file *file)
{ {
struct ftrace_ops *ops = inode->i_private; struct ftrace_ops *ops = inode->i_private;
/* Checks for tracefs lockdown */
return ftrace_regex_open(ops, return ftrace_regex_open(ops,
FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES, FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES,
inode, file); inode, file);
@ -3628,6 +3651,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file)
{ {
struct ftrace_ops *ops = inode->i_private; struct ftrace_ops *ops = inode->i_private;
/* Checks for tracefs lockdown */
return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE, return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE,
inode, file); inode, file);
} }
@ -5037,6 +5061,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
mutex_unlock(&iter->ops->func_hash->regex_lock); mutex_unlock(&iter->ops->func_hash->regex_lock);
free_ftrace_hash(iter->hash); free_ftrace_hash(iter->hash);
if (iter->tr)
trace_array_put(iter->tr);
kfree(iter); kfree(iter);
return 0; return 0;
@ -5194,9 +5220,13 @@ static int
__ftrace_graph_open(struct inode *inode, struct file *file, __ftrace_graph_open(struct inode *inode, struct file *file,
struct ftrace_graph_data *fgd) struct ftrace_graph_data *fgd)
{ {
int ret = 0; int ret;
struct ftrace_hash *new_hash = NULL; struct ftrace_hash *new_hash = NULL;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
if (file->f_mode & FMODE_WRITE) { if (file->f_mode & FMODE_WRITE) {
const int size_bits = FTRACE_HASH_DEFAULT_BITS; 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; struct seq_file *m;
int ret = 0; int ret = 0;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC)) (file->f_flags & O_TRUNC))

View File

@ -17,6 +17,7 @@
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/writeback.h> #include <linux/writeback.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/security.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/irqflags.h> #include <linux/irqflags.h>
@ -304,6 +305,23 @@ void trace_array_put(struct trace_array *this_tr)
mutex_unlock(&trace_types_lock); 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, int call_filter_check_discard(struct trace_event_call *call, void *rec,
struct ring_buffer *buffer, struct ring_buffer *buffer,
struct ring_buffer_event *event) struct ring_buffer_event *event)
@ -4140,8 +4158,11 @@ release:
int tracing_open_generic(struct inode *inode, struct file *filp) int tracing_open_generic(struct inode *inode, struct file *filp)
{ {
if (tracing_disabled) int ret;
return -ENODEV;
ret = tracing_check_open_get_tr(NULL);
if (ret)
return ret;
filp->private_data = inode->i_private; filp->private_data = inode->i_private;
return 0; return 0;
@ -4156,15 +4177,14 @@ bool tracing_is_disabled(void)
* Open and update trace_array ref count. * Open and update trace_array ref count.
* Must have the current trace_array passed to it. * 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; struct trace_array *tr = inode->i_private;
int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr) < 0)
return -ENODEV;
filp->private_data = inode->i_private; 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_array *tr = inode->i_private;
struct trace_iterator *iter; struct trace_iterator *iter;
int ret = 0; int ret;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
/* If this file was open for write, then erase contents */ /* If this file was open for write, then erase contents */
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
@ -4352,19 +4373,30 @@ static int show_traces_open(struct inode *inode, struct file *file)
struct seq_file *m; struct seq_file *m;
int ret; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV;
ret = seq_open(file, &show_traces_seq_ops);
if (ret) if (ret)
return ret; return ret;
ret = seq_open(file, &show_traces_seq_ops);
if (ret) {
trace_array_put(tr);
return ret;
}
m = file->private_data; m = file->private_data;
m->private = tr; m->private = tr;
return 0; 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 static ssize_t
tracing_write_stub(struct file *filp, const char __user *ubuf, tracing_write_stub(struct file *filp, const char __user *ubuf,
size_t count, loff_t *ppos) 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 = { static const struct file_operations show_traces_fops = {
.open = show_traces_open, .open = show_traces_open,
.read = seq_read, .read = seq_read,
.release = seq_release,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = show_traces_release,
}; };
static ssize_t 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; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr) < 0)
return -ENODEV;
ret = single_open(file, tracing_trace_options_show, inode->i_private); ret = single_open(file, tracing_trace_options_show, inode->i_private);
if (ret < 0) 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) static int tracing_saved_tgids_open(struct inode *inode, struct file *filp)
{ {
if (tracing_disabled) int ret;
return -ENODEV;
ret = tracing_check_open_get_tr(NULL);
if (ret)
return ret;
return seq_open(filp, &tracing_saved_tgids_seq_ops); 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) static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp)
{ {
if (tracing_disabled) int ret;
return -ENODEV;
ret = tracing_check_open_get_tr(NULL);
if (ret)
return ret;
return seq_open(filp, &tracing_saved_cmdlines_seq_ops); 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) static int tracing_eval_map_open(struct inode *inode, struct file *filp)
{ {
if (tracing_disabled) int ret;
return -ENODEV;
ret = tracing_check_open_get_tr(NULL);
if (ret)
return ret;
return seq_open(filp, &tracing_eval_map_seq_ops); 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_array *tr = inode->i_private;
struct trace_iterator *iter; struct trace_iterator *iter;
int ret = 0; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr) < 0)
return -ENODEV;
mutex_lock(&trace_types_lock); mutex_lock(&trace_types_lock);
@ -5999,6 +6036,7 @@ waitagain:
sizeof(struct trace_iterator) - sizeof(struct trace_iterator) -
offsetof(struct trace_iterator, seq)); offsetof(struct trace_iterator, seq));
cpumask_clear(iter->started); cpumask_clear(iter->started);
trace_seq_init(&iter->seq);
iter->pos = -1; iter->pos = -1;
trace_event_read_lock(); 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; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr))
return -ENODEV;
ret = single_open(file, tracing_clock_show, inode->i_private); ret = single_open(file, tracing_clock_show, inode->i_private);
if (ret < 0) 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; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr))
return -ENODEV;
ret = single_open(file, tracing_time_stamp_mode_show, inode->i_private); ret = single_open(file, tracing_time_stamp_mode_show, inode->i_private);
if (ret < 0) 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_array *tr = inode->i_private;
struct trace_iterator *iter; struct trace_iterator *iter;
struct seq_file *m; struct seq_file *m;
int ret = 0; int ret;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
iter = __tracing_open(inode, file, true); 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; struct ftrace_buffer_info *info;
int ret; int ret;
/* The following checks for tracefs lockdown */
ret = tracing_buffers_open(inode, filp); ret = tracing_buffers_open(inode, filp);
if (ret < 0) if (ret < 0)
return ret; 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; struct trace_array *tr = inode->i_private;
int ret = 0; int ret = 0;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
/* If this file was opened for write, then erase contents */ /* If this file was opened for write, then erase contents */
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) 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; struct ftrace_buffer_info *info;
int ret; int ret;
if (tracing_disabled) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if (trace_array_get(tr) < 0)
return -ENODEV;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info) { if (!info) {

View File

@ -338,6 +338,7 @@ extern struct mutex trace_types_lock;
extern int trace_array_get(struct trace_array *tr); extern int trace_array_get(struct trace_array *tr);
extern void trace_array_put(struct trace_array *tr); extern void trace_array_put(struct trace_array *tr);
extern int tracing_check_open_get_tr(struct trace_array *tr);
extern int tracing_set_time_stamp_abs(struct trace_array *tr, bool abs); extern int tracing_set_time_stamp_abs(struct trace_array *tr, bool abs);
extern int tracing_set_clock(struct trace_array *tr, const char *clockstr); extern int tracing_set_clock(struct trace_array *tr, const char *clockstr);
@ -681,6 +682,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf);
void tracing_reset_current(int cpu); void tracing_reset_current(int cpu);
void tracing_reset_all_online_cpus(void); void tracing_reset_all_online_cpus(void);
int tracing_open_generic(struct inode *inode, struct file *filp); int tracing_open_generic(struct inode *inode, struct file *filp);
int tracing_open_generic_tr(struct inode *inode, struct file *filp);
bool tracing_is_disabled(void); bool tracing_is_disabled(void);
bool tracer_tracing_is_on(struct trace_array *tr); bool tracer_tracing_is_on(struct trace_array *tr);
void tracer_tracing_on(struct trace_array *tr); void tracer_tracing_on(struct trace_array *tr);

View File

@ -174,6 +174,10 @@ static int dyn_event_open(struct inode *inode, struct file *file)
{ {
int ret; int ret;
ret = tracing_check_open_get_tr(NULL);
if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
ret = dyn_events_release_all(NULL); ret = dyn_events_release_all(NULL);
if (ret < 0) if (ret < 0)

View File

@ -12,6 +12,7 @@
#define pr_fmt(fmt) fmt #define pr_fmt(fmt) fmt
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/security.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/tracefs.h> #include <linux/tracefs.h>
@ -1294,6 +1295,8 @@ static int trace_format_open(struct inode *inode, struct file *file)
struct seq_file *m; struct seq_file *m;
int ret; int ret;
/* Do we want to hide event format files on tracefs lockdown? */
ret = seq_open(file, &trace_format_seq_ops); ret = seq_open(file, &trace_format_seq_ops);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1440,28 +1443,17 @@ static int system_tr_open(struct inode *inode, struct file *filp)
struct trace_array *tr = inode->i_private; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (tracing_is_disabled())
return -ENODEV;
if (trace_array_get(tr) < 0)
return -ENODEV;
/* Make a temporary dir that has no system but points to tr */ /* Make a temporary dir that has no system but points to tr */
dir = kzalloc(sizeof(*dir), GFP_KERNEL); dir = kzalloc(sizeof(*dir), GFP_KERNEL);
if (!dir) { if (!dir)
trace_array_put(tr);
return -ENOMEM; return -ENOMEM;
}
dir->tr = tr; ret = tracing_open_generic_tr(inode, filp);
ret = tracing_open_generic(inode, filp);
if (ret < 0) { if (ret < 0) {
trace_array_put(tr);
kfree(dir); kfree(dir);
return ret; return ret;
} }
dir->tr = tr;
filp->private_data = dir; filp->private_data = dir;
return 0; return 0;
@ -1771,6 +1763,10 @@ ftrace_event_open(struct inode *inode, struct file *file,
struct seq_file *m; struct seq_file *m;
int ret; int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
ret = seq_open(file, seq_ops); ret = seq_open(file, seq_ops);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -1795,6 +1791,7 @@ ftrace_event_avail_open(struct inode *inode, struct file *file)
{ {
const struct seq_operations *seq_ops = &show_event_seq_ops; const struct seq_operations *seq_ops = &show_event_seq_ops;
/* Checks for tracefs lockdown */
return ftrace_event_open(inode, file, seq_ops); return ftrace_event_open(inode, file, seq_ops);
} }
@ -1805,8 +1802,9 @@ ftrace_event_set_open(struct inode *inode, struct file *file)
struct trace_array *tr = inode->i_private; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC)) (file->f_flags & O_TRUNC))
@ -1825,8 +1823,9 @@ ftrace_event_set_pid_open(struct inode *inode, struct file *file)
struct trace_array *tr = inode->i_private; struct trace_array *tr = inode->i_private;
int ret; int ret;
if (trace_array_get(tr) < 0) ret = tracing_check_open_get_tr(tr);
return -ENODEV; if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && if ((file->f_mode & FMODE_WRITE) &&
(file->f_flags & O_TRUNC)) (file->f_flags & O_TRUNC))

View File

@ -7,6 +7,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/security.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
@ -1448,6 +1449,10 @@ static int synth_events_open(struct inode *inode, struct file *file)
{ {
int ret; int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
ret = dyn_events_release_all(&synth_event_ops); ret = dyn_events_release_all(&synth_event_ops);
if (ret < 0) if (ret < 0)
@ -1680,7 +1685,7 @@ static int save_hist_vars(struct hist_trigger_data *hist_data)
if (var_data) if (var_data)
return 0; return 0;
if (trace_array_get(tr) < 0) if (tracing_check_open_get_tr(tr))
return -ENODEV; return -ENODEV;
var_data = kzalloc(sizeof(*var_data), GFP_KERNEL); var_data = kzalloc(sizeof(*var_data), GFP_KERNEL);
@ -5515,6 +5520,12 @@ static int hist_show(struct seq_file *m, void *v)
static int event_hist_open(struct inode *inode, struct file *file) static int event_hist_open(struct inode *inode, struct file *file)
{ {
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
return single_open(file, hist_show, file); return single_open(file, hist_show, file);
} }

View File

@ -5,6 +5,7 @@
* Copyright (C) 2013 Tom Zanussi <tom.zanussi@linux.intel.com> * Copyright (C) 2013 Tom Zanussi <tom.zanussi@linux.intel.com>
*/ */
#include <linux/security.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/mutex.h> #include <linux/mutex.h>
@ -173,7 +174,11 @@ static const struct seq_operations event_triggers_seq_ops = {
static int event_trigger_regex_open(struct inode *inode, struct file *file) static int event_trigger_regex_open(struct inode *inode, struct file *file)
{ {
int ret = 0; int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
mutex_lock(&event_mutex); mutex_lock(&event_mutex);
@ -292,6 +297,7 @@ event_trigger_write(struct file *filp, const char __user *ubuf,
static int static int
event_trigger_open(struct inode *inode, struct file *filp) event_trigger_open(struct inode *inode, struct file *filp)
{ {
/* Checks for tracefs lockdown */
return event_trigger_regex_open(inode, filp); return event_trigger_regex_open(inode, filp);
} }

View File

@ -150,7 +150,7 @@ void trace_hwlat_callback(bool enter)
if (enter) if (enter)
nmi_ts_start = time_get(); nmi_ts_start = time_get();
else else
nmi_total_ts = time_get() - nmi_ts_start; nmi_total_ts += time_get() - nmi_ts_start;
} }
if (enter) if (enter)
@ -256,6 +256,8 @@ static int get_sample(void)
/* Keep a running maximum ever recorded hardware latency */ /* Keep a running maximum ever recorded hardware latency */
if (sample > tr->max_latency) if (sample > tr->max_latency)
tr->max_latency = sample; tr->max_latency = sample;
if (outer_sample > tr->max_latency)
tr->max_latency = outer_sample;
} }
out: out:

View File

@ -7,11 +7,11 @@
*/ */
#define pr_fmt(fmt) "trace_kprobe: " fmt #define pr_fmt(fmt) "trace_kprobe: " fmt
#include <linux/security.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/error-injection.h> #include <linux/error-injection.h>
#include <linux/security.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */ #include <asm/setup.h> /* for COMMAND_LINE_SIZE */
@ -936,6 +936,10 @@ static int probes_open(struct inode *inode, struct file *file)
{ {
int ret; int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
ret = dyn_events_release_all(&trace_kprobe_ops); ret = dyn_events_release_all(&trace_kprobe_ops);
if (ret < 0) if (ret < 0)
@ -988,6 +992,12 @@ static const struct seq_operations profile_seq_op = {
static int profile_open(struct inode *inode, struct file *file) static int profile_open(struct inode *inode, struct file *file)
{ {
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
return seq_open(file, &profile_seq_op); return seq_open(file, &profile_seq_op);
} }

View File

@ -6,6 +6,7 @@
* *
*/ */
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/security.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
@ -348,6 +349,12 @@ static const struct seq_operations show_format_seq_ops = {
static int static int
ftrace_formats_open(struct inode *inode, struct file *file) ftrace_formats_open(struct inode *inode, struct file *file)
{ {
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
return seq_open(file, &show_format_seq_ops); return seq_open(file, &show_format_seq_ops);
} }

View File

@ -5,6 +5,7 @@
*/ */
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <linux/stacktrace.h> #include <linux/stacktrace.h>
#include <linux/security.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -470,6 +471,12 @@ static const struct seq_operations stack_trace_seq_ops = {
static int stack_trace_open(struct inode *inode, struct file *file) static int stack_trace_open(struct inode *inode, struct file *file)
{ {
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
return seq_open(file, &stack_trace_seq_ops); return seq_open(file, &stack_trace_seq_ops);
} }
@ -487,6 +494,7 @@ stack_trace_filter_open(struct inode *inode, struct file *file)
{ {
struct ftrace_ops *ops = inode->i_private; struct ftrace_ops *ops = inode->i_private;
/* Checks for tracefs lockdown */
return ftrace_regex_open(ops, FTRACE_ITER_FILTER, return ftrace_regex_open(ops, FTRACE_ITER_FILTER,
inode, file); inode, file);
} }

View File

@ -9,7 +9,7 @@
* *
*/ */
#include <linux/security.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
@ -238,6 +238,10 @@ static int tracing_stat_open(struct inode *inode, struct file *file)
struct seq_file *m; struct seq_file *m;
struct stat_session *session = inode->i_private; struct stat_session *session = inode->i_private;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
ret = stat_seq_init(session); ret = stat_seq_init(session);
if (ret) if (ret)
return ret; return ret;

View File

@ -7,6 +7,7 @@
*/ */
#define pr_fmt(fmt) "trace_uprobe: " fmt #define pr_fmt(fmt) "trace_uprobe: " fmt
#include <linux/security.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
@ -769,6 +770,10 @@ static int probes_open(struct inode *inode, struct file *file)
{ {
int ret; int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
ret = dyn_events_release_all(&trace_uprobe_ops); ret = dyn_events_release_all(&trace_uprobe_ops);
if (ret) if (ret)
@ -818,6 +823,12 @@ static const struct seq_operations profile_seq_op = {
static int profile_open(struct inode *inode, struct file *file) static int profile_open(struct inode *inode, struct file *file)
{ {
int ret;
ret = security_locked_down(LOCKDOWN_TRACEFS);
if (ret)
return ret;
return seq_open(file, &profile_seq_op); return seq_open(file, &profile_seq_op);
} }

View File

@ -389,11 +389,8 @@ static int nop_mcount(Elf_Shdr const *const relhdr,
mcountsym = get_mcountsym(sym0, relp, str0); mcountsym = get_mcountsym(sym0, relp, str0);
if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) { if (mcountsym == Elf_r_sym(relp) && !is_fake_mcount(relp)) {
if (make_nop) { if (make_nop)
ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset)); ret = make_nop((void *)ehdr, _w(shdr->sh_offset) + _w(relp->r_offset));
if (ret < 0)
return -1;
}
if (warn_on_notrace_sect && !once) { if (warn_on_notrace_sect && !once) {
printf("Section %s has mcount callers being ignored\n", printf("Section %s has mcount callers being ignored\n",
txtname); txtname);