Skip to content

Commit aaa76ef

Browse files
Al Virosmb49
authored andcommitted
fs/fhandle.c: fix a race in call of has_locked_children()
BugLink: https://bugs.launchpad.net/bugs/2119603 [ Upstream commit 1f282cd ] may_decode_fh() is calling has_locked_children() while holding no locks. That's an oopsable race... The rest of the callers are safe since they are holding namespace_sem and are guaranteed a positive refcount on the mount in question. Rename the current has_locked_children() to __has_locked_children(), make it static and switch the fs/namespace.c users to it. Make has_locked_children() a wrapper for __has_locked_children(), calling the latter under read_seqlock_excl(&mount_lock). Reviewed-by: Christian Brauner <brauner@kernel.org> Reviewed-by: Jeff Layton <jlayton@kernel.org> Fixes: 620c266 ("fhandle: relax open_by_handle_at() permission checks") Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Sasha Levin <sashal@kernel.org> CVE-2025-38306 Signed-off-by: Manuel Diewald <manuel.diewald@canonical.com> Signed-off-by: Mehmet Basaran <mehmet.basaran@canonical.com>
1 parent 84df389 commit aaa76ef

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

fs/namespace.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,7 +2271,7 @@ void drop_collected_mounts(struct vfsmount *mnt)
22712271
namespace_unlock();
22722272
}
22732273

2274-
bool has_locked_children(struct mount *mnt, struct dentry *dentry)
2274+
static bool __has_locked_children(struct mount *mnt, struct dentry *dentry)
22752275
{
22762276
struct mount *child;
22772277

@@ -2307,7 +2307,7 @@ struct vfsmount *clone_private_mount(const struct path *path)
23072307
if (!check_mnt(old_mnt))
23082308
goto invalid;
23092309

2310-
if (has_locked_children(old_mnt, path->dentry))
2310+
if (__has_locked_children(old_mnt, path->dentry))
23112311
goto invalid;
23122312

23132313
new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
@@ -2793,7 +2793,7 @@ static struct mount *__do_loopback(struct path *old_path, int recurse)
27932793
return mnt;
27942794
}
27952795

2796-
if (!recurse && has_locked_children(old, old_path->dentry))
2796+
if (!recurse && __has_locked_children(old, old_path->dentry))
27972797
return mnt;
27982798

27992799
if (recurse)
@@ -3128,6 +3128,16 @@ static inline int tree_contains_unbindable(struct mount *mnt)
31283128
return 0;
31293129
}
31303130

3131+
bool has_locked_children(struct mount *mnt, struct dentry *dentry)
3132+
{
3133+
bool res;
3134+
3135+
read_seqlock_excl(&mount_lock);
3136+
res = __has_locked_children(mnt, dentry);
3137+
read_sequnlock_excl(&mount_lock);
3138+
return res;
3139+
}
3140+
31313141
/*
31323142
* Check that there aren't references to earlier/same mount namespaces in the
31333143
* specified subtree. Such references can act as pins for mount namespaces
@@ -3190,7 +3200,7 @@ static int do_set_group(struct path *from_path, struct path *to_path)
31903200
goto out;
31913201

31923202
/* From mount should not have locked children in place of To's root */
3193-
if (has_locked_children(from, to->mnt.mnt_root))
3203+
if (__has_locked_children(from, to->mnt.mnt_root))
31943204
goto out;
31953205

31963206
/* Setting sharing groups is only allowed on private mounts */

0 commit comments

Comments
 (0)