Unverified Commit 9ed72af4 authored by Christian Brauner's avatar Christian Brauner
Browse files

fs: add may_copy_tree()

Add a helper that verifies whether a caller may copy a given mount tree.

Link: https://lore.kernel.org/r/20250221-brauner-open_tree-v1-5-dbcfcb98c676@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent b73ec10a
Loading
Loading
Loading
Loading
+37 −7
Original line number Diff line number Diff line
@@ -2808,6 +2808,41 @@ static int do_change_type(struct path *path, int ms_flags)
	return err;
}

/* may_copy_tree() - check if a mount tree can be copied
 * @path: path to the mount tree to be copied
 *
 * This helper checks if the caller may copy the mount tree starting
 * from @path->mnt. The caller may copy the mount tree under the
 * following circumstances:
 *
 * (1) The caller is located in the mount namespace of the mount tree.
 *     This also implies that the mount does not belong to an anonymous
 *     mount namespace.
 * (2) The caller tries to copy an nfs mount referring to a mount
 *     namespace, i.e., the caller is trying to copy a mount namespace
 *     entry from nsfs.
 * (3) The caller tries to copy a pidfs mount referring to a pidfd.
 *
 * Returns true if the mount tree can be copied, false otherwise.
 */
static inline bool may_copy_tree(struct path *path)
{
	struct mount *mnt = real_mount(path->mnt);
	const struct dentry_operations *d_op;

	if (check_mnt(mnt))
		return true;

	d_op = path->dentry->d_op;
	if (d_op == &ns_dentry_operations)
		return true;

	if (d_op == &pidfs_dentry_operations)
		return true;

	return false;
}

static struct mount *__do_loopback(struct path *old_path, int recurse)
{
	struct mount *mnt = ERR_PTR(-EINVAL), *old = real_mount(old_path->mnt);
@@ -2815,13 +2850,8 @@ static struct mount *__do_loopback(struct path *old_path, int recurse)
	if (IS_MNT_UNBINDABLE(old))
		return mnt;

	if (!check_mnt(old)) {
		const struct dentry_operations *d_op = old_path->dentry->d_op;

		if (d_op != &ns_dentry_operations &&
		    d_op != &pidfs_dentry_operations)
	if (!may_copy_tree(old_path))
		return mnt;
	}

	if (!recurse && has_locked_children(old, old_path->dentry))
		return mnt;