mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-11 15:49:56 +00:00
tracing: Change tracing_fops/snapshot_fops to rely on tracing_get_cpu()
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>
This commit is contained in:
parent
0bc392ee46
commit
6484c71cbc
@ -2862,9 +2862,9 @@ static const struct seq_operations tracer_seq_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct trace_iterator *
|
static struct trace_iterator *
|
||||||
__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
|
__tracing_open(struct inode *inode, struct file *file, bool snapshot)
|
||||||
struct inode *inode, struct file *file, bool snapshot)
|
|
||||||
{
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
struct trace_iterator *iter;
|
struct trace_iterator *iter;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
@ -2905,8 +2905,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
|
|||||||
iter->trace_buffer = &tr->trace_buffer;
|
iter->trace_buffer = &tr->trace_buffer;
|
||||||
iter->snapshot = snapshot;
|
iter->snapshot = snapshot;
|
||||||
iter->pos = -1;
|
iter->pos = -1;
|
||||||
|
iter->cpu_file = tracing_get_cpu(inode);
|
||||||
mutex_init(&iter->mutex);
|
mutex_init(&iter->mutex);
|
||||||
iter->cpu_file = tc->cpu;
|
|
||||||
|
|
||||||
/* Notify the tracer early; before we stop tracing. */
|
/* Notify the tracer early; before we stop tracing. */
|
||||||
if (iter->trace && iter->trace->open)
|
if (iter->trace && iter->trace->open)
|
||||||
@ -2986,22 +2986,18 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
|
|||||||
|
|
||||||
static int tracing_release(struct inode *inode, struct file *file)
|
static int tracing_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
struct seq_file *m = file->private_data;
|
struct seq_file *m = file->private_data;
|
||||||
struct trace_iterator *iter;
|
struct trace_iterator *iter;
|
||||||
struct trace_array *tr;
|
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
/* Writes do not use seq_file, need to grab tr from inode */
|
|
||||||
if (!(file->f_mode & FMODE_READ)) {
|
if (!(file->f_mode & FMODE_READ)) {
|
||||||
struct trace_cpu *tc = inode->i_private;
|
trace_array_put(tr);
|
||||||
|
|
||||||
trace_array_put(tc->tr);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Writes do not use seq_file */
|
||||||
iter = m->private;
|
iter = m->private;
|
||||||
tr = iter->tr;
|
|
||||||
|
|
||||||
mutex_lock(&trace_types_lock);
|
mutex_lock(&trace_types_lock);
|
||||||
|
|
||||||
for_each_tracing_cpu(cpu) {
|
for_each_tracing_cpu(cpu) {
|
||||||
@ -3048,8 +3044,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
static int tracing_open(struct inode *inode, struct file *file)
|
static int tracing_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct trace_cpu *tc = inode->i_private;
|
struct trace_array *tr = inode->i_private;
|
||||||
struct trace_array *tr = tc->tr;
|
|
||||||
struct trace_iterator *iter;
|
struct trace_iterator *iter;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@ -3057,16 +3052,17 @@ static int tracing_open(struct inode *inode, struct file *file)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* 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) &&
|
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
|
||||||
(file->f_flags & O_TRUNC)) {
|
int cpu = tracing_get_cpu(inode);
|
||||||
if (tc->cpu == RING_BUFFER_ALL_CPUS)
|
|
||||||
|
if (cpu == RING_BUFFER_ALL_CPUS)
|
||||||
tracing_reset_online_cpus(&tr->trace_buffer);
|
tracing_reset_online_cpus(&tr->trace_buffer);
|
||||||
else
|
else
|
||||||
tracing_reset(&tr->trace_buffer, tc->cpu);
|
tracing_reset(&tr->trace_buffer, cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file->f_mode & FMODE_READ) {
|
if (file->f_mode & FMODE_READ) {
|
||||||
iter = __tracing_open(tr, tc, inode, file, false);
|
iter = __tracing_open(inode, file, false);
|
||||||
if (IS_ERR(iter))
|
if (IS_ERR(iter))
|
||||||
ret = PTR_ERR(iter);
|
ret = PTR_ERR(iter);
|
||||||
else if (trace_flags & TRACE_ITER_LATENCY_FMT)
|
else if (trace_flags & TRACE_ITER_LATENCY_FMT)
|
||||||
@ -4680,8 +4676,7 @@ struct ftrace_buffer_info {
|
|||||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||||
static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct trace_cpu *tc = inode->i_private;
|
struct trace_array *tr = inode->i_private;
|
||||||
struct trace_array *tr = tc->tr;
|
|
||||||
struct trace_iterator *iter;
|
struct trace_iterator *iter;
|
||||||
struct seq_file *m;
|
struct seq_file *m;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -4690,7 +4685,7 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
if (file->f_mode & FMODE_READ) {
|
if (file->f_mode & FMODE_READ) {
|
||||||
iter = __tracing_open(tr, tc, inode, file, true);
|
iter = __tracing_open(inode, file, true);
|
||||||
if (IS_ERR(iter))
|
if (IS_ERR(iter))
|
||||||
ret = PTR_ERR(iter);
|
ret = PTR_ERR(iter);
|
||||||
} else {
|
} else {
|
||||||
@ -4707,8 +4702,8 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
iter->tr = tr;
|
iter->tr = tr;
|
||||||
iter->trace_buffer = &tc->tr->max_buffer;
|
iter->trace_buffer = &tr->max_buffer;
|
||||||
iter->cpu_file = tc->cpu;
|
iter->cpu_file = tracing_get_cpu(inode);
|
||||||
m->private = iter;
|
m->private = iter;
|
||||||
file->private_data = m;
|
file->private_data = m;
|
||||||
}
|
}
|
||||||
@ -5525,7 +5520,6 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
|
|||||||
static void
|
static void
|
||||||
tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
||||||
{
|
{
|
||||||
struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
|
|
||||||
struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
|
struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
|
||||||
struct dentry *d_cpu;
|
struct dentry *d_cpu;
|
||||||
char cpu_dir[30]; /* 30 characters should be more than enough */
|
char cpu_dir[30]; /* 30 characters should be more than enough */
|
||||||
@ -5546,7 +5540,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
|||||||
|
|
||||||
/* per cpu trace */
|
/* per cpu trace */
|
||||||
trace_create_cpu_file("trace", 0644, d_cpu,
|
trace_create_cpu_file("trace", 0644, d_cpu,
|
||||||
&data->trace_cpu, cpu, &tracing_fops);
|
tr, cpu, &tracing_fops);
|
||||||
|
|
||||||
trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
|
trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
|
||||||
tr, cpu, &tracing_buffers_fops);
|
tr, cpu, &tracing_buffers_fops);
|
||||||
@ -5559,7 +5553,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
|
|||||||
|
|
||||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||||
trace_create_cpu_file("snapshot", 0644, d_cpu,
|
trace_create_cpu_file("snapshot", 0644, d_cpu,
|
||||||
&data->trace_cpu, cpu, &snapshot_fops);
|
tr, cpu, &snapshot_fops);
|
||||||
|
|
||||||
trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
|
trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
|
||||||
tr, cpu, &snapshot_raw_fops);
|
tr, cpu, &snapshot_raw_fops);
|
||||||
@ -6125,7 +6119,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
|
|||||||
tr, &tracing_iter_fops);
|
tr, &tracing_iter_fops);
|
||||||
|
|
||||||
trace_create_file("trace", 0644, d_tracer,
|
trace_create_file("trace", 0644, d_tracer,
|
||||||
(void *)&tr->trace_cpu, &tracing_fops);
|
tr, &tracing_fops);
|
||||||
|
|
||||||
trace_create_file("trace_pipe", 0444, d_tracer,
|
trace_create_file("trace_pipe", 0444, d_tracer,
|
||||||
tr, &tracing_pipe_fops);
|
tr, &tracing_pipe_fops);
|
||||||
@ -6150,7 +6144,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
|
|||||||
|
|
||||||
#ifdef CONFIG_TRACER_SNAPSHOT
|
#ifdef CONFIG_TRACER_SNAPSHOT
|
||||||
trace_create_file("snapshot", 0644, d_tracer,
|
trace_create_file("snapshot", 0644, d_tracer,
|
||||||
(void *)&tr->trace_cpu, &snapshot_fops);
|
tr, &snapshot_fops);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for_each_tracing_cpu(cpu)
|
for_each_tracing_cpu(cpu)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user