[PATCH v3] configfs: Add revalidate for cached dentry to ensure it's ready

From: Edward Adam Davis

Date: Thu Oct 22 2026 - 07:11:49 EST


mkdir() triggers:
configfs_mkdir() ->
configfs_attach_group() ->
populate_groups() ->
create_default_group("ana_groups") ->
configfs_attach_group() ->
populate_groups() ->
create_default_group("1")

The creation of an inode for the subdentry 1 under ana_groups failed
due to fault injection. [1]

Because helper threads are racing open() on ana_groups, ana_groups has
dentry refcount > 1. d_delete() skips dentry_unlink_inode(), leaving
d_inode non-NULL. create_default_group() hits BUG_ON(d_inode(child)) at
fs/configfs/dir.c:734! [2]

[1]
FAULT_INJECTION: forcing a failure.
name failslab, interval 1, probability 0, space 0, times -1
Call Trace:
should_failslab+0xa8/0x100
kmem_cache_alloc_noprof+0xa1/0x600
security_inode_alloc+0x39/0x310
inode_init_always_gfp+0x97e/0xd30
alloc_inode+0x82/0x1b0
new_inode+0x1f/0x170
configfs_new_inode+0x27/0x410
configfs_create+0xb5/0x270
configfs_attach_item+0x25f/0xd60
configfs_attach_group+0x2a/0x370
create_default_group+0x87/0x180
configfs_attach_group+0x169/0x370
configfs_mkdir+0x6f0/0x9e0
vfs_mkdir+0x40c/0x620

[2]
kernel BUG at fs/configfs/dir.c:734!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI
RIP: 0010:create_default_group+0x17c/0x180
Call Trace:
configfs_attach_group+0x169/0x370
configfs_mkdir+0x6f0/0x9e0
vfs_mkdir+0x40c/0x620

The root cause is a race condition between open and mkdir. Add a revalidate
for cached dentries to prevent open from accessing directories that are not
yet ready.

Fixes: 7063fbf22611 ("[PATCH] configfs: User-driven configuration filesystem")
Reported-by: syzbot+4fae162886e497f72228@xxxxxxxxxxxxxxxxxxxxxxxxx
Closes: https://syzkaller.appspot.com/bug?extid=4fae162886e497f72228
Tested-by: syzbot+4fae162886e497f72228@xxxxxxxxxxxxxxxxxxxxxxxxx
Signed-off-by: Edward Adam Davis <eadavis@xxxxxxxx>
---
v1 -> v2: using revalidate to make it's ready
v2 -> v3: add LOOKUP_RCU check

fs/configfs/dir.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)

diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index eda80c2a2d38..76f453ed4adb 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/namei.h>

#include <linux/configfs.h>
#include "configfs_internal.h"
@@ -65,8 +66,27 @@ static void configfs_d_iput(struct dentry * dentry,
iput(inode);
}

+static int configfs_d_revalidate(struct inode *dir, const struct qstr *name,
+ struct dentry *dentry, unsigned int flags)
+{
+ struct inode *inode = d_inode(dentry);
+ struct configfs_dirent * parent_sd = dentry->d_fsdata;
+
+ if (flags & LOOKUP_RCU)
+ return -ECHILD;
+
+ if (!inode)
+ return -ECHILD;
+
+ if (!configfs_dirent_is_ready(parent_sd))
+ return -ECHILD;
+
+ return 1;
+}
+
const struct dentry_operations configfs_dentry_ops = {
.d_iput = configfs_d_iput,
+ .d_revalidate = configfs_d_revalidate,
};

#ifdef CONFIG_LOCKDEP
--
2.43.0