Re: [PATCH] configfs: protect symlink source callbacks from removal

From: Breno Leitao

Date: Fri Nov 06 2026 - 11:21:03 EST


On Thu, Nov 05, 2026 at 01:45:17PM +0000, Yingjie Wang wrote:
> From: Yingjie Wang <1075151112@xxxxxx>
>
> configfs_symlink() drops the source directory inode lock while resolving
> its target. A concurrent rmdir() of the source item can take that lock,
> detach the item and clear its ci_group in unlink_obj(). configfs_symlink()
> then reacquires the lock and calls the source ->allow_link() callback on
> the detached item. Its config_item reference keeps the object allocated,
> but not attached to the hierarchy.
>
> The UVC gadget format callback reads src->ci_group->cg_subsys to take the
> subsystem mutex and faults on the cleared pointer. Racing symlink() into
> a UVC format directory with rmdir() of that directory produces:
>
> BUG: KASAN: null-ptr-deref in uvcg_format_allow_link+0x2a/0x140
> Read of size 8 at addr 0000000000000060 by task configfs_race/291
> Call Trace:
> uvcg_format_allow_link+0x2a/0x140
> configfs_symlink+0x3f2/0x870
> vfs_symlink+0xc0/0x2a0
> filename_symlinkat+0x118/0x2b0
> __x64_sys_symlink+0x50/0x70
>
> Creating the items needs the privileges required to manage configfs.
>
> Rechecking ci_group after relocking would cover rmdir(), which holds the
> source inode lock until unlink_obj() returns. It would not cover
> configfs_unregister_group() and configfs_unregister_subsystem(): both
> clear ci_group in unlink_group() while the source inode lock is not held,
> so the check could become stale before the callback runs.
>
> Take the source fragment read lock after reacquiring the inode lock and
> hold it through allow_link(), create_link() and drop_link(). rmdir() and
> both unregister paths mark the fragment dead under the write lock before
> they unlink the item, so a concurrent removal either waits for the
> callback to finish or makes the symlink fail with -ENOENT.
>
> Built from the same configuration, the kernel without this change faulted
> within 1,000 iterations, while the kernel with it completed 10,000
> iterations with no report. The reproducer covers the rmdir() path; the
> unregister paths were checked by code inspection.
>
> Fixes: 351e5d869e5a ("configfs: fix a deadlock in configfs_symlink()")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Yingjie Wang <1075151112@xxxxxx>

How this patch was tested?

I applied this patch to next-20261104 and raced symlink() inside
ports/1/subsystems against a mkdir/rmdir loop on ports/1. KASAN fired
within a second:

BUG: KASAN: slab-use-after-free in config_item_put+0x48/0x180
Write of size 4 at addr ff110001068d64b4 by task brute/170
Call Trace:
config_item_put+0x48/0x180
configfs_symlink+0x4eb/0x770
vfs_symlink+0x25b/0x4b0
filename_symlinkat+0x10d/0x2f0
...
Allocated by task 168:
__kmalloc_cache_noprof+0x26c/0x4c0
nvmet_ports_make+0xcc/0xd10
configfs_mkdir+0x44d/0x810
...
Freed by task 168:
kfree+0x150/0x4f0
config_item_put+0x139/0x180