Skip to content

Commit 6a002d4

Browse files
Miklos Szeredigregkh
authored andcommitted
ovl: prevent private clone if bind mount is not allowed
commit 427215d 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 <[email protected]> Fixes: c771d68 ("vfs: introduce clone_private_mount()") Cc: <[email protected]> # v3.18 Signed-off-by: Miklos Szeredi <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bffead8 commit 6a002d4

File tree

1 file changed

+28
-14
lines changed

1 file changed

+28
-14
lines changed

fs/namespace.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1919,6 +1919,20 @@ void drop_collected_mounts(struct vfsmount *mnt)
19191919
namespace_unlock();
19201920
}
19211921

1922+
static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
1923+
{
1924+
struct mount *child;
1925+
1926+
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
1927+
if (!is_subdir(child->mnt_mountpoint, dentry))
1928+
continue;
1929+
1930+
if (child->mnt.mnt_flags & MNT_LOCKED)
1931+
return true;
1932+
}
1933+
return false;
1934+
}
1935+
19221936
/**
19231937
* clone_private_mount - create a private clone of a path
19241938
*
@@ -1933,17 +1947,30 @@ struct vfsmount *clone_private_mount(const struct path *path)
19331947
struct mount *old_mnt = real_mount(path->mnt);
19341948
struct mount *new_mnt;
19351949

1950+
down_read(&namespace_sem);
19361951
if (IS_MNT_UNBINDABLE(old_mnt))
1937-
return ERR_PTR(-EINVAL);
1952+
goto invalid;
1953+
1954+
if (!check_mnt(old_mnt))
1955+
goto invalid;
1956+
1957+
if (has_locked_children(old_mnt, path->dentry))
1958+
goto invalid;
19381959

19391960
new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
1961+
up_read(&namespace_sem);
1962+
19401963
if (IS_ERR(new_mnt))
19411964
return ERR_CAST(new_mnt);
19421965

19431966
/* Longterm mount to be removed by kern_unmount*() */
19441967
new_mnt->mnt_ns = MNT_NS_INTERNAL;
19451968

19461969
return &new_mnt->mnt;
1970+
1971+
invalid:
1972+
up_read(&namespace_sem);
1973+
return ERR_PTR(-EINVAL);
19471974
}
19481975
EXPORT_SYMBOL_GPL(clone_private_mount);
19491976

@@ -2295,19 +2322,6 @@ static int do_change_type(struct path *path, int ms_flags)
22952322
return err;
22962323
}
22972324

2298-
static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
2299-
{
2300-
struct mount *child;
2301-
list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
2302-
if (!is_subdir(child->mnt_mountpoint, dentry))
2303-
continue;
2304-
2305-
if (child->mnt.mnt_flags & MNT_LOCKED)
2306-
return true;
2307-
}
2308-
return false;
2309-
}
2310-
23112325
static struct mount *__do_loopback(struct path *old_path, int recurse)
23122326
{
23132327
struct mount *mnt = ERR_PTR(-EINVAL), *old = real_mount(old_path->mnt);

0 commit comments

Comments
 (0)