diff options
| author | Christian Brauner <brauner@kernel.org> | 2025-02-21 16:13:04 +0300 | 
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2025-03-04 11:29:52 +0300 | 
| commit | 9ed72af4e292e770f6977a032de32112b079c2ce (patch) | |
| tree | e829c04e6654da53548256abaaf430917f66260f | |
| parent | b73ec10a458796bed6d51768d5f26c4660f62ae4 (diff) | |
| download | linux-9ed72af4e292e770f6977a032de32112b079c2ce.tar.xz | |
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>
| -rw-r--r-- | fs/namespace.c | 44 | 
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;  | 
