[PATCH 4.19 10/11] ovl: prevent private clone if bind mount is not allowed
flat view
STALE1878d
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Date: 2021-08-13 15:15:46
Also in:
lkml
From: Miklos Szeredi <redacted>
commit 427215d85e8d1476da1a86b8d67aceb485eb3631 upstream.
Add the following checks from __do_loopback() to clone_private_mount() as
well:
- verify that the mount is in the current namespace
- verify that there are no locked children
Reported-by: Alois Wohlschlager <redacted>
Fixes: c771d683a62e ("vfs: introduce clone_private_mount()")
Cc: <redacted> # v3.18
Signed-off-by: Miklos Szeredi <redacted>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
fs/namespace.c | 42 ++++++++++++++++++++++++++++--------------
1 file changed, 28 insertions(+), 14 deletions(-)
--- a/fs/namespace.c
+++ b/fs/namespace.c@@ -1799,6 +1799,20 @@ void drop_collected_mounts(struct vfsmou namespace_unlock(); } +static bool has_locked_children(struct mount *mnt, struct dentry *dentry) +{ + struct mount *child; + + list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { + if (!is_subdir(child->mnt_mountpoint, dentry)) + continue; + + if (child->mnt.mnt_flags & MNT_LOCKED) + return true; + } + return false; +} + /** * clone_private_mount - create a private clone of a path *
@@ -1813,14 +1827,27 @@ struct vfsmount *clone_private_mount(con struct mount *old_mnt = real_mount(path->mnt); struct mount *new_mnt; + down_read(&namespace_sem); if (IS_MNT_UNBINDABLE(old_mnt)) - return ERR_PTR(-EINVAL); + goto invalid; + + if (!check_mnt(old_mnt)) + goto invalid; + + if (has_locked_children(old_mnt, path->dentry)) + goto invalid; new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); + up_read(&namespace_sem); + if (IS_ERR(new_mnt)) return ERR_CAST(new_mnt); return &new_mnt->mnt; + +invalid: + up_read(&namespace_sem); + return ERR_PTR(-EINVAL); } EXPORT_SYMBOL_GPL(clone_private_mount);
@@ -2136,19 +2163,6 @@ static int do_change_type(struct path *p return err; } -static bool has_locked_children(struct mount *mnt, struct dentry *dentry) -{ - struct mount *child; - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { - if (!is_subdir(child->mnt_mountpoint, dentry)) - continue; - - if (child->mnt.mnt_flags & MNT_LOCKED) - return true; - } - return false; -} - /* * do loopback mount. */