summaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-06-29 22:27:44 +0200
committerAl Viro <viro@zeniv.linux.org.uk>2019-07-01 16:46:36 +0200
commit570d7a98e7d6d5d8706d94ffd2d40adeaa318332 (patch)
tree56980b6ac051d46174e62c1919ec14d02d25ad5d /fs/namespace.c
parentfs/namespace: fix unprivileged mount propagation (diff)
downloadlinux-570d7a98e7d6d5d8706d94ffd2d40adeaa318332.tar.xz
linux-570d7a98e7d6d5d8706d94ffd2d40adeaa318332.zip
vfs: move_mount: reject moving kernel internal mounts
sys_move_mount() crashes by dereferencing the pointer MNT_NS_INTERNAL, a.k.a. ERR_PTR(-EINVAL), if the old mount is specified by fd for a kernel object with an internal mount, such as a pipe or memfd. Fix it by checking for this case and returning -EINVAL. [AV: what we want is is_mounted(); use that instead of making the condition even more convoluted] Reproducer: #include <unistd.h> #define __NR_move_mount 429 #define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 int main() { int fds[2]; pipe(fds); syscall(__NR_move_mount, fds[0], "", -1, "/", MOVE_MOUNT_F_EMPTY_PATH); } Reported-by: syzbot+6004acbaa1893ad013f0@syzkaller.appspotmail.com Fixes: 2db154b3ea8e ("vfs: syscall: Add move_mount(2) to move mounts around") Signed-off-by: Eric Biggers <ebiggers@google.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 7660c2749c96..6fbc9126367a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2596,11 +2596,12 @@ static int do_move_mount(struct path *old_path, struct path *new_path)
if (!check_mnt(p))
goto out;
- /* The thing moved should be either ours or completely unattached. */
- if (attached && !check_mnt(old))
+ /* The thing moved must be mounted... */
+ if (!is_mounted(&old->mnt))
goto out;
- if (!attached && !(ns && is_anon_ns(ns)))
+ /* ... and either ours or the root of anon namespace */
+ if (!(attached ? check_mnt(old) : is_anon_ns(ns)))
goto out;
if (old->mnt.mnt_flags & MNT_LOCKED)