--- /dev/null
+From 427215d85e8d1476da1a86b8d67aceb485eb3631 Mon Sep 17 00:00:00 2001
+From: Miklos Szeredi <mszeredi@redhat.com>
+Date: Mon, 9 Aug 2021 10:19:47 +0200
+Subject: ovl: prevent private clone if bind mount is not allowed
+
+From: Miklos Szeredi <mszeredi@redhat.com>
+
+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 <alois1@gmx-topmail.de>
+Fixes: c771d683a62e ("vfs: introduce clone_private_mount()")
+Cc: <stable@vger.kernel.org> # v3.18
+Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/namespace.c | 42 +++++++++++++++++++++++++++---------------
+ 1 file changed, 27 insertions(+), 15 deletions(-)
+
+--- a/fs/namespace.c
++++ b/fs/namespace.c
+@@ -1853,6 +1853,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
+ *
+@@ -1867,16 +1881,27 @@ struct vfsmount *clone_private_mount(str
+ 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;
+
+- down_read(&namespace_sem);
+ 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);
+
+@@ -2192,19 +2217,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.
+ */