Skip to content

Commit 020010f

Browse files
committed
eventfs: Delete eventfs_inode when the last dentry is freed
There exists a race between holding a reference of an eventfs_inode dentry and the freeing of the eventfs_inode. If user space has a dentry held long enough, it may still be able to access the dentry's eventfs_inode after it has been freed. To prevent this, have he eventfs_inode freed via the last dput() (or via RCU if the eventfs_inode does not have a dentry). This means reintroducing the eventfs_inode del_list field at a temporary place to put the eventfs_inode. It needs to mark it as freed (via the list) but also must invalidate the dentry immediately as the return from eventfs_remove_dir() expects that they are. But the dentry invalidation must not be called under the eventfs_mutex, so it must be done after the eventfs_inode is marked as free (put on a deletion list). Link: https://lkml.kernel.org/r/20231101172650.123479767@goodmis.org Cc: stable@vger.kernel.org Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Ajay Kaher <akaher@vmware.com> Fixes: 5bdcd5f ("eventfs: Implement removal of meta data from eventfs") Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 4436532 commit 020010f

File tree

2 files changed

+69
-79
lines changed

2 files changed

+69
-79
lines changed

fs/tracefs/event_inode.c

Lines changed: 67 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,7 @@ static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry,
8585

8686
mutex_lock(&eventfs_mutex);
8787
ei = dentry->d_fsdata;
88-
/* The LSB is set when the eventfs_inode is being freed */
89-
if (((unsigned long)ei & 1UL) || ei->is_freed) {
88+
if (ei->is_freed) {
9089
/* Do not allow changes if the event is about to be removed. */
9190
mutex_unlock(&eventfs_mutex);
9291
return -ENODEV;
@@ -276,35 +275,17 @@ static void free_ei(struct eventfs_inode *ei)
276275
void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
277276
{
278277
struct tracefs_inode *ti_parent;
279-
struct eventfs_inode *ei_child, *tmp;
280278
struct eventfs_inode *ei;
281279
int i;
282280

283281
/* The top level events directory may be freed by this */
284282
if (unlikely(ti->flags & TRACEFS_EVENT_TOP_INODE)) {
285-
LIST_HEAD(ef_del_list);
286-
287283
mutex_lock(&eventfs_mutex);
288-
289284
ei = ti->private;
290-
291-
/* Record all the top level files */
292-
list_for_each_entry_srcu(ei_child, &ei->children, list,
293-
lockdep_is_held(&eventfs_mutex)) {
294-
list_add_tail(&ei_child->del_list, &ef_del_list);
295-
}
296-
297285
/* Nothing should access this, but just in case! */
298286
ti->private = NULL;
299-
300287
mutex_unlock(&eventfs_mutex);
301288

302-
/* Now safely free the top level files and their children */
303-
list_for_each_entry_safe(ei_child, tmp, &ef_del_list, del_list) {
304-
list_del(&ei_child->del_list);
305-
eventfs_remove_dir(ei_child);
306-
}
307-
308289
free_ei(ei);
309290
return;
310291
}
@@ -319,14 +300,6 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
319300
if (!ei)
320301
goto out;
321302

322-
/*
323-
* If ei was freed, then the LSB bit is set for d_fsdata.
324-
* But this should not happen, as it should still have a
325-
* ref count that prevents it. Warn in case it does.
326-
*/
327-
if (WARN_ON_ONCE((unsigned long)ei & 1))
328-
goto out;
329-
330303
/* This could belong to one of the files of the ei */
331304
if (ei->dentry != dentry) {
332305
for (i = 0; i < ei->nr_entries; i++) {
@@ -336,6 +309,8 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry)
336309
if (WARN_ON_ONCE(i == ei->nr_entries))
337310
goto out;
338311
ei->d_children[i] = NULL;
312+
} else if (ei->is_freed) {
313+
free_ei(ei);
339314
} else {
340315
ei->dentry = NULL;
341316
}
@@ -962,13 +937,65 @@ struct eventfs_inode *eventfs_create_events_dir(const char *name, struct dentry
962937
return ERR_PTR(-ENOMEM);
963938
}
964939

940+
static LLIST_HEAD(free_list);
941+
942+
static void eventfs_workfn(struct work_struct *work)
943+
{
944+
struct eventfs_inode *ei, *tmp;
945+
struct llist_node *llnode;
946+
947+
llnode = llist_del_all(&free_list);
948+
llist_for_each_entry_safe(ei, tmp, llnode, llist) {
949+
/* This dput() matches the dget() from unhook_dentry() */
950+
for (int i = 0; i < ei->nr_entries; i++) {
951+
if (ei->d_children[i])
952+
dput(ei->d_children[i]);
953+
}
954+
/* This should only get here if it had a dentry */
955+
if (!WARN_ON_ONCE(!ei->dentry))
956+
dput(ei->dentry);
957+
}
958+
}
959+
960+
static DECLARE_WORK(eventfs_work, eventfs_workfn);
961+
965962
static void free_rcu_ei(struct rcu_head *head)
966963
{
967964
struct eventfs_inode *ei = container_of(head, struct eventfs_inode, rcu);
968965

966+
if (ei->dentry) {
967+
/* Do not free the ei until all references of dentry are gone */
968+
if (llist_add(&ei->llist, &free_list))
969+
queue_work(system_unbound_wq, &eventfs_work);
970+
return;
971+
}
972+
973+
/* If the ei doesn't have a dentry, neither should its children */
974+
for (int i = 0; i < ei->nr_entries; i++) {
975+
WARN_ON_ONCE(ei->d_children[i]);
976+
}
977+
969978
free_ei(ei);
970979
}
971980

981+
static void unhook_dentry(struct dentry *dentry)
982+
{
983+
if (!dentry)
984+
return;
985+
986+
/* Keep the dentry from being freed yet (see eventfs_workfn()) */
987+
dget(dentry);
988+
989+
dentry->d_fsdata = NULL;
990+
d_invalidate(dentry);
991+
mutex_lock(&eventfs_mutex);
992+
/* dentry should now have at least a single reference */
993+
WARN_ONCE((int)d_count(dentry) < 1,
994+
"dentry %px (%s) less than one reference (%d) after invalidate\n",
995+
dentry, dentry->d_name.name, d_count(dentry));
996+
mutex_unlock(&eventfs_mutex);
997+
}
998+
972999
/**
9731000
* eventfs_remove_rec - remove eventfs dir or file from list
9741001
* @ei: eventfs_inode to be removed.
@@ -1006,33 +1033,6 @@ static void eventfs_remove_rec(struct eventfs_inode *ei, struct list_head *head,
10061033
list_add_tail(&ei->del_list, head);
10071034
}
10081035

1009-
static void unhook_dentry(struct dentry **dentry, struct dentry **list)
1010-
{
1011-
if (*dentry) {
1012-
unsigned long ptr = (unsigned long)*list;
1013-
1014-
/* Keep the dentry from being freed yet */
1015-
dget(*dentry);
1016-
1017-
/*
1018-
* Paranoid: The dget() above should prevent the dentry
1019-
* from being freed and calling eventfs_set_ei_status_free().
1020-
* But just in case, set the link list LSB pointer to 1
1021-
* and have eventfs_set_ei_status_free() check that to
1022-
* make sure that if it does happen, it will not think
1023-
* the d_fsdata is an eventfs_inode.
1024-
*
1025-
* For this to work, no eventfs_inode should be allocated
1026-
* on a odd space, as the ef should always be allocated
1027-
* to be at least word aligned. Check for that too.
1028-
*/
1029-
WARN_ON_ONCE(ptr & 1);
1030-
1031-
(*dentry)->d_fsdata = (void *)(ptr | 1);
1032-
*list = *dentry;
1033-
*dentry = NULL;
1034-
}
1035-
}
10361036
/**
10371037
* eventfs_remove_dir - remove eventfs dir or file from list
10381038
* @ei: eventfs_inode to be removed.
@@ -1043,40 +1043,28 @@ void eventfs_remove_dir(struct eventfs_inode *ei)
10431043
{
10441044
struct eventfs_inode *tmp;
10451045
LIST_HEAD(ei_del_list);
1046-
struct dentry *dentry_list = NULL;
1047-
struct dentry *dentry;
1048-
int i;
10491046

10501047
if (!ei)
10511048
return;
10521049

1050+
/*
1051+
* Move the deleted eventfs_inodes onto the ei_del_list
1052+
* which will also set the is_freed value. Note, this has to be
1053+
* done under the eventfs_mutex, but the deletions of
1054+
* the dentries must be done outside the eventfs_mutex.
1055+
* Hence moving them to this temporary list.
1056+
*/
10531057
mutex_lock(&eventfs_mutex);
10541058
eventfs_remove_rec(ei, &ei_del_list, 0);
1059+
mutex_unlock(&eventfs_mutex);
10551060

10561061
list_for_each_entry_safe(ei, tmp, &ei_del_list, del_list) {
1057-
for (i = 0; i < ei->nr_entries; i++)
1058-
unhook_dentry(&ei->d_children[i], &dentry_list);
1059-
unhook_dentry(&ei->dentry, &dentry_list);
1062+
for (int i = 0; i < ei->nr_entries; i++)
1063+
unhook_dentry(ei->d_children[i]);
1064+
unhook_dentry(ei->dentry);
1065+
list_del(&ei->del_list);
10601066
call_srcu(&eventfs_srcu, &ei->rcu, free_rcu_ei);
10611067
}
1062-
mutex_unlock(&eventfs_mutex);
1063-
1064-
while (dentry_list) {
1065-
unsigned long ptr;
1066-
1067-
dentry = dentry_list;
1068-
ptr = (unsigned long)dentry->d_fsdata & ~1UL;
1069-
dentry_list = (struct dentry *)ptr;
1070-
dentry->d_fsdata = NULL;
1071-
d_invalidate(dentry);
1072-
mutex_lock(&eventfs_mutex);
1073-
/* dentry should now have at least a single reference */
1074-
WARN_ONCE((int)d_count(dentry) < 1,
1075-
"dentry %px (%s) less than one reference (%d) after invalidate\n",
1076-
dentry, dentry->d_name.name, d_count(dentry));
1077-
mutex_unlock(&eventfs_mutex);
1078-
dput(dentry);
1079-
}
10801068
}
10811069

10821070
/**

fs/tracefs/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ struct eventfs_inode {
5454
void *data;
5555
/*
5656
* Union - used for deletion
57+
* @llist: for calling dput() if needed after RCU
5758
* @del_list: list of eventfs_inode to delete
5859
* @rcu: eventfs_inode to delete in RCU
5960
*/
6061
union {
62+
struct llist_node llist;
6163
struct list_head del_list;
6264
struct rcu_head rcu;
6365
};

0 commit comments

Comments
 (0)