diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2021-08-09 11:19:47 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2021-08-15 14:01:04 +0300 |
commit | e3eee87c846dc47f6d8eb6d85e7271f24122a279 (patch) | |
tree | e5103d8e0f6fd7e6e5150ce6e7b6028c76f2b20a /fs/namespace.c | |
parent | ffdc1e312e2074875147c1df90764a9bae56f11f (diff) | |
download | linux-e3eee87c846dc47f6d8eb6d85e7271f24122a279.tar.xz |
ovl: prevent private clone if bind mount is not allowed
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>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 42 |
1 files changed, 27 insertions, 15 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 3b20c7ff8cc3..9f2390c89b63 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1853,6 +1853,20 @@ void drop_collected_mounts(struct vfsmount *mnt) 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(struct path *path) 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 *path, int flag) 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. */ |