Skip to content

Commit 99214f6

Browse files
committed
Merge tag 'trace-v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull tracing fixes from Steven Rostedt: - Add missing LOCKDOWN checks for eventfs callers When LOCKDOWN is active for tracing, it causes inconsistent state when some functions succeed and others fail. - Use dput() to free the top level eventfs descriptor There was a race between accesses and freeing it. - Fix a long standing bug that eventfs exposed due to changing timings by dynamically creating files. That is, If a event file is opened for an instance, there's nothing preventing the instance from being removed which will make accessing the files cause use-after-free bugs. - Fix a ring buffer race that happens when iterating over the ring buffer while writers are active. Check to make sure not to read the event meta data if it's beyond the end of the ring buffer sub buffer. - Fix the print trigger that disappeared because the test to create it was looking for the event dir field being filled, but now it has the "ef" field filled for the eventfs structure. - Remove the unused "dir" field from the event structure. - Fix the order of the trace_dynamic_info as it had it backwards for the offset and len fields for which one was for which endianess. - Fix NULL pointer dereference with eventfs_remove_rec() If an allocation fails in one of the eventfs_add_*() functions, the caller of it in event_subsystem_dir() or event_create_dir() assigns the result to the structure. But it's assigning the ERR_PTR and not NULL. This was passed to eventfs_remove_rec() which expects either a good pointer or a NULL, not ERR_PTR. The fix is to not assign the ERR_PTR to the structure, but to keep it NULL on error. - Fix list_for_each_rcu() to use list_for_each_srcu() in dcache_dir_open_wrapper(). One iteration of the code used RCU but because it had to call sleepable code, it had to be changed to use SRCU, but one of the iterations was missed. - Fix synthetic event print function to use "as_u64" instead of passing in a pointer to the union. To fix big/little endian issues, the u64 that represented several types was turned into a union to define the types properly. * tag 'trace-v6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: eventfs: Fix the NULL pointer dereference bug in eventfs_remove_rec() tracefs/eventfs: Use list_for_each_srcu() in dcache_dir_open_wrapper() tracing/synthetic: Print out u64 values properly tracing/synthetic: Fix order of struct trace_dynamic_info selftests/ftrace: Fix dependencies for some of the synthetic event tests tracing: Remove unused trace_event_file dir field tracing: Use the new eventfs descriptor for print trigger ring-buffer: Do not attempt to read past "commit" tracefs/eventfs: Free top level files on removal ring-buffer: Avoid softlockup in ring_buffer_resize() tracing: Have event inject files inc the trace array ref count tracing: Have option files inc the trace array ref count tracing: Have current_trace inc the trace array ref count tracing: Have tracing_max_latency inc the trace array ref count tracing: Increase trace array ref count on enable and filter files tracefs/eventfs: Use dput to free the toplevel events directory tracefs/eventfs: Add missing lockdown checks tracefs: Add missing lockdown check to tracefs_create_dir()
2 parents 3669558 + c8414da commit 99214f6

File tree

12 files changed

+152
-46
lines changed

12 files changed

+152
-46
lines changed

fs/tracefs/event_inode.c

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,17 +185,49 @@ static struct dentry *create_dir(const char *name, struct dentry *parent, void *
185185

186186
/**
187187
* eventfs_set_ef_status_free - set the ef->status to free
188+
* @ti: the tracefs_inode of the dentry
188189
* @dentry: dentry who's status to be freed
189190
*
190191
* eventfs_set_ef_status_free will be called if no more
191192
* references remain
192193
*/
193-
void eventfs_set_ef_status_free(struct dentry *dentry)
194+
void eventfs_set_ef_status_free(struct tracefs_inode *ti, struct dentry *dentry)
194195
{
195196
struct tracefs_inode *ti_parent;
196-
struct eventfs_file *ef;
197+
struct eventfs_inode *ei;
198+
struct eventfs_file *ef, *tmp;
199+
200+
/* The top level events directory may be freed by this */
201+
if (unlikely(ti->flags & TRACEFS_EVENT_TOP_INODE)) {
202+
LIST_HEAD(ef_del_list);
203+
204+
mutex_lock(&eventfs_mutex);
205+
206+
ei = ti->private;
207+
208+
/* Record all the top level files */
209+
list_for_each_entry_srcu(ef, &ei->e_top_files, list,
210+
lockdep_is_held(&eventfs_mutex)) {
211+
list_add_tail(&ef->del_list, &ef_del_list);
212+
}
213+
214+
/* Nothing should access this, but just in case! */
215+
ti->private = NULL;
216+
217+
mutex_unlock(&eventfs_mutex);
218+
219+
/* Now safely free the top level files and their children */
220+
list_for_each_entry_safe(ef, tmp, &ef_del_list, del_list) {
221+
list_del(&ef->del_list);
222+
eventfs_remove(ef);
223+
}
224+
225+
kfree(ei);
226+
return;
227+
}
197228

198229
mutex_lock(&eventfs_mutex);
230+
199231
ti_parent = get_tracefs(dentry->d_parent->d_inode);
200232
if (!ti_parent || !(ti_parent->flags & TRACEFS_EVENT_INODE))
201233
goto out;
@@ -420,7 +452,8 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
420452

421453
ei = ti->private;
422454
idx = srcu_read_lock(&eventfs_srcu);
423-
list_for_each_entry_rcu(ef, &ei->e_top_files, list) {
455+
list_for_each_entry_srcu(ef, &ei->e_top_files, list,
456+
srcu_read_lock_held(&eventfs_srcu)) {
424457
create_dentry(ef, dentry, false);
425458
}
426459
srcu_read_unlock(&eventfs_srcu, idx);
@@ -491,6 +524,9 @@ struct dentry *eventfs_create_events_dir(const char *name,
491524
struct tracefs_inode *ti;
492525
struct inode *inode;
493526

527+
if (security_locked_down(LOCKDOWN_TRACEFS))
528+
return NULL;
529+
494530
if (IS_ERR(dentry))
495531
return dentry;
496532

@@ -507,7 +543,7 @@ struct dentry *eventfs_create_events_dir(const char *name,
507543
INIT_LIST_HEAD(&ei->e_top_files);
508544

509545
ti = get_tracefs(inode);
510-
ti->flags |= TRACEFS_EVENT_INODE;
546+
ti->flags |= TRACEFS_EVENT_INODE | TRACEFS_EVENT_TOP_INODE;
511547
ti->private = ei;
512548

513549
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
@@ -538,6 +574,9 @@ struct eventfs_file *eventfs_add_subsystem_dir(const char *name,
538574
struct eventfs_inode *ei_parent;
539575
struct eventfs_file *ef;
540576

577+
if (security_locked_down(LOCKDOWN_TRACEFS))
578+
return NULL;
579+
541580
if (!parent)
542581
return ERR_PTR(-EINVAL);
543582

@@ -569,6 +608,9 @@ struct eventfs_file *eventfs_add_dir(const char *name,
569608
{
570609
struct eventfs_file *ef;
571610

611+
if (security_locked_down(LOCKDOWN_TRACEFS))
612+
return NULL;
613+
572614
if (!ef_parent)
573615
return ERR_PTR(-EINVAL);
574616

@@ -606,6 +648,9 @@ int eventfs_add_events_file(const char *name, umode_t mode,
606648
struct eventfs_inode *ei;
607649
struct eventfs_file *ef;
608650

651+
if (security_locked_down(LOCKDOWN_TRACEFS))
652+
return -ENODEV;
653+
609654
if (!parent)
610655
return -EINVAL;
611656

@@ -654,6 +699,9 @@ int eventfs_add_file(const char *name, umode_t mode,
654699
{
655700
struct eventfs_file *ef;
656701

702+
if (security_locked_down(LOCKDOWN_TRACEFS))
703+
return -ENODEV;
704+
657705
if (!ef_parent)
658706
return -EINVAL;
659707

@@ -791,7 +839,6 @@ void eventfs_remove(struct eventfs_file *ef)
791839
void eventfs_remove_events_dir(struct dentry *dentry)
792840
{
793841
struct tracefs_inode *ti;
794-
struct eventfs_inode *ei;
795842

796843
if (!dentry || !dentry->d_inode)
797844
return;
@@ -800,8 +847,6 @@ void eventfs_remove_events_dir(struct dentry *dentry)
800847
if (!ti || !(ti->flags & TRACEFS_EVENT_INODE))
801848
return;
802849

803-
ei = ti->private;
804850
d_invalidate(dentry);
805851
dput(dentry);
806-
kfree(ei);
807852
}

fs/tracefs/inode.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ static void tracefs_dentry_iput(struct dentry *dentry, struct inode *inode)
385385

386386
ti = get_tracefs(inode);
387387
if (ti && ti->flags & TRACEFS_EVENT_INODE)
388-
eventfs_set_ef_status_free(dentry);
388+
eventfs_set_ef_status_free(ti, dentry);
389389
iput(inode);
390390
}
391391

@@ -673,6 +673,9 @@ static struct dentry *__create_dir(const char *name, struct dentry *parent,
673673
*/
674674
struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
675675
{
676+
if (security_locked_down(LOCKDOWN_TRACEFS))
677+
return NULL;
678+
676679
return __create_dir(name, parent, &simple_dir_inode_operations);
677680
}
678681

fs/tracefs/internal.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
#define _TRACEFS_INTERNAL_H
44

55
enum {
6-
TRACEFS_EVENT_INODE = BIT(1),
6+
TRACEFS_EVENT_INODE = BIT(1),
7+
TRACEFS_EVENT_TOP_INODE = BIT(2),
78
};
89

910
struct tracefs_inode {
@@ -24,6 +25,6 @@ struct inode *tracefs_get_inode(struct super_block *sb);
2425
struct dentry *eventfs_start_creating(const char *name, struct dentry *parent);
2526
struct dentry *eventfs_failed_creating(struct dentry *dentry);
2627
struct dentry *eventfs_end_creating(struct dentry *dentry);
27-
void eventfs_set_ef_status_free(struct dentry *dentry);
28+
void eventfs_set_ef_status_free(struct tracefs_inode *ti, struct dentry *dentry);
2829

2930
#endif /* _TRACEFS_INTERNAL_H */

include/linux/trace_events.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ void trace_event_printf(struct trace_iterator *iter, const char *fmt, ...);
6262
/* Used to find the offset and length of dynamic fields in trace events */
6363
struct trace_dynamic_info {
6464
#ifdef CONFIG_CPU_BIG_ENDIAN
65-
u16 offset;
6665
u16 len;
66+
u16 offset;
6767
#else
68-
u16 len;
6968
u16 offset;
69+
u16 len;
7070
#endif
71-
};
71+
} __packed;
7272

7373
/*
7474
* The trace entry - the most basic unit of tracing. This is what
@@ -650,7 +650,6 @@ struct trace_event_file {
650650
struct trace_event_call *event_call;
651651
struct event_filter __rcu *filter;
652652
struct eventfs_file *ef;
653-
struct dentry *dir;
654653
struct trace_array *tr;
655654
struct trace_subsystem_dir *system;
656655
struct list_head triggers;

kernel/trace/ring_buffer.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,6 +2198,8 @@ int ring_buffer_resize(struct trace_buffer *buffer, unsigned long size,
21982198
err = -ENOMEM;
21992199
goto out_err;
22002200
}
2201+
2202+
cond_resched();
22012203
}
22022204

22032205
cpus_read_lock();
@@ -2388,6 +2390,11 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
23882390
*/
23892391
commit = rb_page_commit(iter_head_page);
23902392
smp_rmb();
2393+
2394+
/* An event needs to be at least 8 bytes in size */
2395+
if (iter->head > commit - 8)
2396+
goto reset;
2397+
23912398
event = __rb_page_index(iter_head_page, iter->head);
23922399
length = rb_event_length(event);
23932400

kernel/trace/trace.c

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,7 @@ static void trace_create_maxlat_file(struct trace_array *tr,
17721772
init_irq_work(&tr->fsnotify_irqwork, latency_fsnotify_workfn_irq);
17731773
tr->d_max_latency = trace_create_file("tracing_max_latency",
17741774
TRACE_MODE_WRITE,
1775-
d_tracer, &tr->max_latency,
1775+
d_tracer, tr,
17761776
&tracing_max_lat_fops);
17771777
}
17781778

@@ -1805,7 +1805,7 @@ void latency_fsnotify(struct trace_array *tr)
18051805

18061806
#define trace_create_maxlat_file(tr, d_tracer) \
18071807
trace_create_file("tracing_max_latency", TRACE_MODE_WRITE, \
1808-
d_tracer, &tr->max_latency, &tracing_max_lat_fops)
1808+
d_tracer, tr, &tracing_max_lat_fops)
18091809

18101810
#endif
18111811

@@ -4973,6 +4973,33 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp)
49734973
return 0;
49744974
}
49754975

4976+
/*
4977+
* The private pointer of the inode is the trace_event_file.
4978+
* Update the tr ref count associated to it.
4979+
*/
4980+
int tracing_open_file_tr(struct inode *inode, struct file *filp)
4981+
{
4982+
struct trace_event_file *file = inode->i_private;
4983+
int ret;
4984+
4985+
ret = tracing_check_open_get_tr(file->tr);
4986+
if (ret)
4987+
return ret;
4988+
4989+
filp->private_data = inode->i_private;
4990+
4991+
return 0;
4992+
}
4993+
4994+
int tracing_release_file_tr(struct inode *inode, struct file *filp)
4995+
{
4996+
struct trace_event_file *file = inode->i_private;
4997+
4998+
trace_array_put(file->tr);
4999+
5000+
return 0;
5001+
}
5002+
49765003
static int tracing_mark_open(struct inode *inode, struct file *filp)
49775004
{
49785005
stream_open(inode, filp);
@@ -6691,14 +6718,18 @@ static ssize_t
66916718
tracing_max_lat_read(struct file *filp, char __user *ubuf,
66926719
size_t cnt, loff_t *ppos)
66936720
{
6694-
return tracing_nsecs_read(filp->private_data, ubuf, cnt, ppos);
6721+
struct trace_array *tr = filp->private_data;
6722+
6723+
return tracing_nsecs_read(&tr->max_latency, ubuf, cnt, ppos);
66956724
}
66966725

66976726
static ssize_t
66986727
tracing_max_lat_write(struct file *filp, const char __user *ubuf,
66996728
size_t cnt, loff_t *ppos)
67006729
{
6701-
return tracing_nsecs_write(filp->private_data, ubuf, cnt, ppos);
6730+
struct trace_array *tr = filp->private_data;
6731+
6732+
return tracing_nsecs_write(&tr->max_latency, ubuf, cnt, ppos);
67026733
}
67036734

67046735
#endif
@@ -7752,18 +7783,20 @@ static const struct file_operations tracing_thresh_fops = {
77527783

77537784
#ifdef CONFIG_TRACER_MAX_TRACE
77547785
static const struct file_operations tracing_max_lat_fops = {
7755-
.open = tracing_open_generic,
7786+
.open = tracing_open_generic_tr,
77567787
.read = tracing_max_lat_read,
77577788
.write = tracing_max_lat_write,
77587789
.llseek = generic_file_llseek,
7790+
.release = tracing_release_generic_tr,
77597791
};
77607792
#endif
77617793

77627794
static const struct file_operations set_tracer_fops = {
7763-
.open = tracing_open_generic,
7795+
.open = tracing_open_generic_tr,
77647796
.read = tracing_set_trace_read,
77657797
.write = tracing_set_trace_write,
77667798
.llseek = generic_file_llseek,
7799+
.release = tracing_release_generic_tr,
77677800
};
77687801

77697802
static const struct file_operations tracing_pipe_fops = {
@@ -8956,12 +8989,33 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
89568989
return cnt;
89578990
}
89588991

8992+
static int tracing_open_options(struct inode *inode, struct file *filp)
8993+
{
8994+
struct trace_option_dentry *topt = inode->i_private;
8995+
int ret;
8996+
8997+
ret = tracing_check_open_get_tr(topt->tr);
8998+
if (ret)
8999+
return ret;
9000+
9001+
filp->private_data = inode->i_private;
9002+
return 0;
9003+
}
9004+
9005+
static int tracing_release_options(struct inode *inode, struct file *file)
9006+
{
9007+
struct trace_option_dentry *topt = file->private_data;
9008+
9009+
trace_array_put(topt->tr);
9010+
return 0;
9011+
}
89599012

89609013
static const struct file_operations trace_options_fops = {
8961-
.open = tracing_open_generic,
9014+
.open = tracing_open_options,
89629015
.read = trace_options_read,
89639016
.write = trace_options_write,
89649017
.llseek = generic_file_llseek,
9018+
.release = tracing_release_options,
89659019
};
89669020

89679021
/*
@@ -9739,8 +9793,8 @@ init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer)
97399793
tr, &tracing_mark_fops);
97409794

97419795
file = __find_event_file(tr, "ftrace", "print");
9742-
if (file && file->dir)
9743-
trace_create_file("trigger", TRACE_MODE_WRITE, file->dir,
9796+
if (file && file->ef)
9797+
eventfs_add_file("trigger", TRACE_MODE_WRITE, file->ef,
97449798
file, &event_trigger_fops);
97459799
tr->trace_marker_file = file;
97469800

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,8 @@ void tracing_reset_all_online_cpus(void);
610610
void tracing_reset_all_online_cpus_unlocked(void);
611611
int tracing_open_generic(struct inode *inode, struct file *filp);
612612
int tracing_open_generic_tr(struct inode *inode, struct file *filp);
613+
int tracing_open_file_tr(struct inode *inode, struct file *filp);
614+
int tracing_release_file_tr(struct inode *inode, struct file *filp);
613615
bool tracing_is_disabled(void);
614616
bool tracer_tracing_is_on(struct trace_array *tr);
615617
void tracer_tracing_on(struct trace_array *tr);

0 commit comments

Comments
 (0)