Skip to content

Commit 4436532

Browse files
committed
eventfs: Hold eventfs_mutex when calling callback functions
The callback function that is used to create inodes and dentries is not protected by anything and the data that is passed to it could become stale. After eventfs_remove_dir() is called by the tracing system, it is free to remove the events that are associated to that directory. Unfortunately, that means the callbacks must not be called after that. CPU0 CPU1 ---- ---- eventfs_root_lookup() { eventfs_remove_dir() { mutex_lock(&event_mutex); ei->is_freed = set; mutex_unlock(&event_mutex); } kfree(event_call); for (...) { entry = &ei->entries[i]; r = entry->callback() { call = data; // call == event_call above if (call->flags ...) [ USE AFTER FREE BUG ] The safest way to protect this is to wrap the callback with: mutex_lock(&eventfs_mutex); if (!ei->is_freed) r = entry->callback(); else r = -1; mutex_unlock(&eventfs_mutex); This will make sure that the callback will not be called after it is freed. But now it needs to be known that the callback is called while holding internal eventfs locks, and that it must not call back into the eventfs / tracefs system. There's no reason it should anyway, but document that as well. Link: https://lore.kernel.org/all/CA+G9fYu9GOEbD=rR5eMR-=HJ8H6rMsbzDC2ZY5=Y50WpWAE7_Q@mail.gmail.com/ Link: https://lkml.kernel.org/r/20231101172649.906696613@goodmis.org Cc: Ajay Kaher <akaher@vmware.com> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Fixes: 5790b1f ("eventfs: Remove eventfs_file and just use eventfs_inode") Reported-by: Linux Kernel Functional Testing <lkft@linaro.org> Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org> Tested-by: Linux Kernel Functional Testing <lkft@linaro.org> Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org> Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 28e12c0 commit 4436532

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

fs/tracefs/event_inode.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,13 @@ static struct dentry *eventfs_root_lookup(struct inode *dir,
615615
entry = &ei->entries[i];
616616
if (strcmp(name, entry->name) == 0) {
617617
void *cdata = data;
618-
r = entry->callback(name, &mode, &cdata, &fops);
618+
mutex_lock(&eventfs_mutex);
619+
/* If ei->is_freed, then the event itself may be too */
620+
if (!ei->is_freed)
621+
r = entry->callback(name, &mode, &cdata, &fops);
622+
else
623+
r = -1;
624+
mutex_unlock(&eventfs_mutex);
619625
if (r <= 0)
620626
continue;
621627
ret = simple_lookup(dir, dentry, flags);
@@ -749,7 +755,13 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file)
749755
void *cdata = data;
750756
entry = &ei->entries[i];
751757
name = entry->name;
752-
r = entry->callback(name, &mode, &cdata, &fops);
758+
mutex_lock(&eventfs_mutex);
759+
/* If ei->is_freed, then the event itself may be too */
760+
if (!ei->is_freed)
761+
r = entry->callback(name, &mode, &cdata, &fops);
762+
else
763+
r = -1;
764+
mutex_unlock(&eventfs_mutex);
753765
if (r <= 0)
754766
continue;
755767
d = create_file_dentry(ei, i, parent, name, mode, cdata, fops, false);
@@ -819,6 +831,10 @@ static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx)
819831
* data = A pointer to @data, and the callback may replace it, which will
820832
* cause the file created to pass the new data to the open() call.
821833
* fops = the fops to use for the created file.
834+
*
835+
* NB. @callback is called while holding internal locks of the eventfs
836+
* system. The callback must not call any code that might also call into
837+
* the tracefs or eventfs system or it will risk creating a deadlock.
822838
*/
823839
struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode *parent,
824840
const struct eventfs_entry *entries,
@@ -878,6 +894,8 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode
878894
* @data: The default data to pass to the files (an entry may override it).
879895
*
880896
* This function creates the top of the trace event directory.
897+
*
898+
* See eventfs_create_dir() for use of @entries.
881899
*/
882900
struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry *parent,
883901
const struct eventfs_entry *entries,

include/linux/tracefs.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,52 @@ struct file_operations;
2323

2424
struct eventfs_file;
2525

26+
/**
27+
* eventfs_callback - A callback function to create dynamic files in eventfs
28+
* @name: The name of the file that is to be created
29+
* @mode: return the file mode for the file (RW access, etc)
30+
* @data: data to pass to the created file ops
31+
* @fops: the file operations of the created file
32+
*
33+
* The evetnfs files are dynamically created. The struct eventfs_entry array
34+
* is passed to eventfs_create_dir() or eventfs_create_events_dir() that will
35+
* be used to create the files within those directories. When a lookup
36+
* or access to a file within the directory is made, the struct eventfs_entry
37+
* array is used to find a callback() with the matching name that is being
38+
* referenced (for lookups, the entire array is iterated and each callback
39+
* will be called).
40+
*
41+
* The callback will be called with @name for the name of the file to create.
42+
* The callback can return less than 1 to indicate that no file should be
43+
* created.
44+
*
45+
* If a file is to be created, then @mode should be populated with the file
46+
* mode (permissions) for which the file is created for. This would be
47+
* used to set the created inode i_mode field.
48+
*
49+
* The @data should be set to the data passed to the other file operations
50+
* (read, write, etc). Note, @data will also point to the data passed in
51+
* to eventfs_create_dir() or eventfs_create_events_dir(), but the callback
52+
* can replace the data if it chooses to. Otherwise, the original data
53+
* will be used for the file operation functions.
54+
*
55+
* The @fops should be set to the file operations that will be used to create
56+
* the inode.
57+
*
58+
* NB. This callback is called while holding internal locks of the eventfs
59+
* system. The callback must not call any code that might also call into
60+
* the tracefs or eventfs system or it will risk creating a deadlock.
61+
*/
2662
typedef int (*eventfs_callback)(const char *name, umode_t *mode, void **data,
2763
const struct file_operations **fops);
2864

65+
/**
66+
* struct eventfs_entry - dynamically created eventfs file call back handler
67+
* @name: Then name of the dynamic file in an eventfs directory
68+
* @callback: The callback to get the fops of the file when it is created
69+
*
70+
* See evenfs_callback() typedef for how to set up @callback.
71+
*/
2972
struct eventfs_entry {
3073
const char *name;
3174
eventfs_callback callback;

0 commit comments

Comments
 (0)