mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: syzbot <syzbot+a89f9434fb5a001ccd58@syzkaller.appspotmail.com>
Cc: jack@suse.cz, linux-fsdevel@vger.kernel.org,
	 linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com,
	viro@zeniv.linux.org.uk
Subject: Re: [syzbot] [fs?] KASAN: slab-use-after-free Read in clone_mnt
Date: Sat, 14 Feb 2026 16:59:11 +0100	[thread overview]
Message-ID: <20260214-werft-vorerst-0b3bf9610224@brauner> (raw)
In-Reply-To: <699047f6.050a0220.2757fb.0024.GAE@google.com>

[-- Attachment #1: Type: text/plain, Size: 1668 bytes --]

On Sat, Feb 14, 2026 at 02:01:26AM -0800, syzbot wrote:
> Hello,
> 
> syzbot found the following issue on:
> 
> HEAD commit:    c22e26bd0906 Merge tag 'landlock-7.0-rc1' of git://git.ker..
> git tree:       upstream
> console output: https://syzkaller.appspot.com/x/log.txt?x=12c6a6e6580000
> kernel config:  https://syzkaller.appspot.com/x/.config?x=6428d17febdfb14e
> dashboard link: https://syzkaller.appspot.com/bug?extid=a89f9434fb5a001ccd58
> compiler:       Debian clang version 21.1.8 (++20251221033036+2078da43e25a-1~exp1~20251221153213.50), Debian LLD 21.1.8
> 
> Unfortunately, I don't have any reproducer for this issue yet.
> 
> Downloadable assets:
> disk image: https://storage.googleapis.com/syzbot-assets/b33c549157ca/disk-c22e26bd.raw.xz
> vmlinux: https://storage.googleapis.com/syzbot-assets/34c7ded19553/vmlinux-c22e26bd.xz
> kernel image: https://storage.googleapis.com/syzbot-assets/66faec2158ed/bzImage-c22e26bd.xz
> 
> IMPORTANT: if you fix the issue, please add the following tag to the commit:
> Reported-by: syzbot+a89f9434fb5a001ccd58@syzkaller.appspotmail.com

Right, this should be fixed by the appended patch. If someone had the
bright idea to make the real rootfs a shared or dependent mount and it
is later copied the copy will become a peer of the old real rootfs mount
or a dependent mount of it. If locking the new rootfs mount for mounting
fails or the subsequent do_loopback() fails we rely on the copy of the
real root mount to be cleaned up by path_put(). The problem is that this
doesn't deal with mount propagation and will leave the mounts linked in
the propagation lists. Fix this by actually unmounting the copied tree.



[-- Attachment #2: 0001-mount-unmount-copied-tree.patch --]
[-- Type: text/x-diff, Size: 4131 bytes --]

From 3b3dc6a956af1afc6b95c68550b99083d47ce5fa Mon Sep 17 00:00:00 2001
From: Christian Brauner <brauner@kernel.org>
Date: Sat, 14 Feb 2026 16:22:13 +0100
Subject: [PATCH] mount: unmount copied tree

Fix an oversight when creating a new mount namespace. If someone had the
bright idea to make the real rootfs a shared or dependent mount and it
is later copied the copy will become a peer of the old real rootfs mount
or a dependent mount of it. The namespace semaphore is dropped and we
use mount lock exact to lock the new real root mount. If that fails or
the subsequent do_loopback() fails we rely on the copy of the real root
mount to be cleaned up by path_put(). The problem is that this doesn't
deal with mount propagation and will leave the mounts linked in the
propagation lists. Fix this by actually unmounting the copied tree.

Reported-by: syzbot+a89f9434fb5a001ccd58@syzkaller.appspotmail.com
Link: https:/lore.kernel.org/699047f6.050a0220.2757fb.0024.GAE@google.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 fs/namespace.c | 37 ++++++++++++++++++++++---------------
 1 file changed, 22 insertions(+), 15 deletions(-)

diff --git a/fs/namespace.c b/fs/namespace.c
index a67cbe42746d..89cac95e6c9b 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -3073,16 +3073,13 @@ static struct file *open_detached_copy(struct path *path, unsigned int flags)
 	return file;
 }
 
-DEFINE_FREE(put_empty_mnt_ns, struct mnt_namespace *,
-	    if (!IS_ERR_OR_NULL(_T)) free_mnt_ns(_T))
-
 static struct mnt_namespace *create_new_namespace(struct path *path, unsigned int flags)
 {
-	struct mnt_namespace *new_ns __free(put_empty_mnt_ns) = NULL;
-	struct path to_path __free(path_put) = {};
 	struct mnt_namespace *ns = current->nsproxy->mnt_ns;
 	struct user_namespace *user_ns = current_user_ns();
+	struct mnt_namespace *new_ns;
 	struct mount *new_ns_root;
+	struct path to_path;
 	struct mount *mnt;
 	unsigned int copy_flags = 0;
 	bool locked = false;
@@ -3096,8 +3093,10 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
 
 	scoped_guard(namespace_excl) {
 		new_ns_root = clone_mnt(ns->root, ns->root->mnt.mnt_root, copy_flags);
-		if (IS_ERR(new_ns_root))
+		if (IS_ERR(new_ns_root)) {
+			emptied_ns = new_ns;
 			return ERR_CAST(new_ns_root);
+		}
 
 		/*
 		 * If the real rootfs had a locked mount on top of it somewhere
@@ -3122,12 +3121,17 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
 
 	/* Borrow the reference from clone_mnt(). */
 	to_path.mnt = &new_ns_root->mnt;
-	to_path.dentry = dget(new_ns_root->mnt.mnt_root);
+	to_path.dentry = new_ns_root->mnt.mnt_root;
 
 	/* Now lock for actual mounting. */
 	LOCK_MOUNT_EXACT(mp, &to_path);
-	if (unlikely(IS_ERR(mp.parent)))
+	if (unlikely(IS_ERR(mp.parent))) {
+		guard(namespace_excl)();
+		emptied_ns = new_ns;
+		guard(mount_writer)();
+		umount_tree(new_ns_root, 0);
 		return ERR_CAST(mp.parent);
+	}
 
 	/*
 	 * We don't emulate unshare()ing a mount namespace. We stick to the
@@ -3135,10 +3139,13 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
 	 * saner and simpler semantics.
 	 */
 	mnt = __do_loopback(path, flags, copy_flags);
-	if (IS_ERR(mnt))
-		return ERR_CAST(mnt);
-
 	scoped_guard(mount_writer) {
+		if (IS_ERR(mnt)) {
+			emptied_ns = new_ns;
+			umount_tree(new_ns_root, 0);
+			return ERR_CAST(mnt);
+		}
+
 		if (locked)
 			mnt->mnt.mnt_flags |= MNT_LOCKED;
 		/*
@@ -3151,14 +3158,14 @@ static struct mnt_namespace *create_new_namespace(struct path *path, unsigned in
 	}
 
 	/* Add all mounts to the new namespace. */
-	for (struct mount *p = new_ns_root; p; p = next_mnt(p, new_ns_root)) {
-		mnt_add_to_ns(new_ns, p);
+	for (mnt = new_ns_root; mnt; mnt = next_mnt(mnt, new_ns_root)) {
+		mnt_add_to_ns(new_ns, mnt);
 		new_ns->nr_mounts++;
 	}
 
-	new_ns->root = real_mount(no_free_ptr(to_path.mnt));
+	new_ns->root = real_mount(to_path.mnt);
 	ns_tree_add_raw(new_ns);
-	return no_free_ptr(new_ns);
+	return new_ns;
 }
 
 static struct file *open_new_namespace(struct path *path, unsigned int flags)
-- 
2.47.3


  reply	other threads:[~2026-02-14 15:59 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-14 10:01 syzbot
2026-02-14 15:59 ` Christian Brauner [this message]
2026-02-17 12:12   ` Christian Brauner

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=20260214-werft-vorerst-0b3bf9610224@brauner \
    --to=brauner@kernel.org \
    --cc=jack@suse.cz \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=syzbot+a89f9434fb5a001ccd58@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    --cc=viro@zeniv.linux.org.uk \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®