All of lore.kernel.org
 help / color / mirror / Atom feed
From: Breno Leitao <leitao@debian.org>
To: Farhad Alemi <farhad.alemi@berkeley.edu>
Cc: Andreas Hindborg <a.hindborg@kernel.org>,
	 linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [BUG] configfs: slab-use-after-free in configfs_drop_dentry() on rmdir
Date: Wed, 27 May 2026 11:27:57 +0100	[thread overview]
Message-ID: <ahbG94EFLD5ntnYr@gmail.com> (raw)
In-Reply-To: <CA+0ovCjv-VYvn-4jUj3wDn+DuP9FSv-GL+yPAHbR=ZGKU0wmGg@mail.gmail.com>

On Tue, May 26, 2026 at 08:42:00PM +0000, Farhad Alemi wrote:
> Hello Andreas and the configfs team,
> 
> I am reporting a configfs use-after-free found by syzkaller.
> 
> Summary:
> A configfs config-item rmdir(2) can land in configfs_drop_dentry() with
> sd->s_dentry pointing at a dentry whose RCU grace period has not yet
> elapsed. The spin_lock(&dentry->d_lock) at fs/configfs/inode.c:209 then
> reads freed slab memory and KASAN reports a slab-use-after-free.

Thanks for the report. I was able to reproduce it on linus' upstream
tree. 

I've came up with the following fix, would you mind trying it, please?


commit d78c04736ef0ede76093c780a188560b6baed3c3
Author: Breno Leitao <leitao@debian.org>
Date:   Wed May 27 06:25:49 2026 -0400

    configfs: fix UAF in configfs_drop_dentry() after failed attribute lookup
    
    When configfs_lookup() matches an attribute it publishes the new dentry
    into sd->s_dentry (and dentry->d_fsdata) before calling
    configfs_create() to allocate the inode:
    
            dentry->d_fsdata = configfs_get(sd);
            sd->s_dentry = dentry;
            spin_unlock(&configfs_dirent_lock);
    
            inode = configfs_create(dentry, mode);
            if (IS_ERR(inode)) {
                    configfs_put(sd);
                    return ERR_CAST(inode);
            }
    
    If configfs_create() fails (e.g. new_inode() returns NULL under memory
    pressure or fault injection), the lookup returns an error and the
    caller dputs the now-negative dentry, which goes through
    __dentry_kill() and is freed via call_rcu().
    
    Because the dentry never gained an inode it does not go through the
    .d_iput op (configfs_d_iput), which is the only place that clears
    sd->s_dentry.  sd therefore keeps a stale pointer to the freed dentry.
    A subsequent rmdir of the parent item walks the parent's s_children
    list in detach_attrs() and configfs_drop_dentry() does
    spin_lock(&sd->s_dentry->d_lock) on freed memory:
    
      BUG: KASAN: slab-use-after-free in _raw_spin_lock+0xac/0x110
      Read of size 1 at addr ffff00012bacd028 by task repro/2440
       _raw_spin_lock+0xac/0x110
       configfs_drop_dentry+0x48/0x158 [configfs]
       detach_attrs.isra.0+0x18c/0x494 [configfs]
       configfs_rmdir+0x450/0x71c [configfs]
       vfs_rmdir+0x170/0x620
       ...
      Freed by task 0:
       __d_free+0x28/0x34
       rcu_do_batch+0x37c/0x1bd0
       ...
      Last potentially related work creation:
       call_rcu+0x34/0x68
       dentry_free+0xe8/0x3e0
       __dentry_kill+0x404/0x604
       dput+0x14/0x30
       lookup_open.isra.0+0x6ac/0xc00
       path_openat+0xd18/0x2588
    
    Fix this by tearing down the sd<->dentry linkage in the
    configfs_create() error path, under configfs_dirent_lock, mirroring
    what configfs_d_iput() would have done for a positive dentry.
    
    Reported-by: Farhad Alemi <farhad.alemi@berkeley.edu>
    Signed-off-by: Breno Leitao <leitao@debian.org>

diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 362b6ff9b908..68d857dcb2d9 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -486,6 +486,22 @@ static struct dentry * configfs_lookup(struct inode *dir,
 
 			inode = configfs_create(dentry, mode);
 			if (IS_ERR(inode)) {
+				/*
+				 * configfs_create() failed (e.g. -ENOMEM
+				 * from new_inode()).  The dentry will be
+				 * dput()ed by the caller and freed via RCU;
+				 * because it never gained an inode,
+				 * configfs_d_iput() will not run to clear
+				 * sd->s_dentry.  Drop the linkage here so a
+				 * later detach_attrs() walking the parent's
+				 * s_children list does not dereference a
+				 * freed dentry in configfs_drop_dentry().
+				 */
+				spin_lock(&configfs_dirent_lock);
+				if (sd->s_dentry == dentry)
+					sd->s_dentry = NULL;
+				dentry->d_fsdata = NULL;
+				spin_unlock(&configfs_dirent_lock);
 				configfs_put(sd);
 				return ERR_CAST(inode);
 			}

  reply	other threads:[~2026-05-27 10:28 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-27  3:42 [BUG] configfs: slab-use-after-free in configfs_drop_dentry() on rmdir Farhad Alemi
2026-05-27 10:27 ` Breno Leitao [this message]
2026-05-30 17:18   ` Farhad Alemi
2026-06-02  7:17   ` Al Viro

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ahbG94EFLD5ntnYr@gmail.com \
    --to=leitao@debian.org \
    --cc=a.hindborg@kernel.org \
    --cc=farhad.alemi@berkeley.edu \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.