summaryrefslogtreecommitdiff
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2025-02-21 14:13:04 +0100
committerChristian Brauner <brauner@kernel.org>2025-03-04 09:29:52 +0100
commit9ed72af4e292e770f6977a032de32112b079c2ce (patch)
treee829c04e6654da53548256abaaf430917f66260f /fs/namespace.c
parentb73ec10a458796bed6d51768d5f26c4660f62ae4 (diff)
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: Christian Brauner <brauner@kernel.org>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c44
1 files changed, 37 insertions, 7 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 8cb15539aaaf..631404fa623c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -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)
- return mnt;
- }
+ if (!may_copy_tree(old_path))
+ return mnt;
if (!recurse && has_locked_children(old, old_path->dentry))
return mnt;