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
next prev parent 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®