diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2012-07-27 00:42:03 -0400 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2012-11-19 08:59:21 -0500 |
commit | 0c55cfc4166d9a0f38de779bd4d75a90afbe7734 (patch) | |
tree | d7ac108d615869ea615eec8693993c2700b24351 /fs/namespace.c | |
parent | 7a472ef4be8387bc05a42e16309b02c8ca943a40 (diff) |
vfs: Allow unprivileged manipulation of the mount namespace.
- Add a filesystem flag to mark filesystems that are safe to mount as
an unprivileged user.
- Add a filesystem flag to mark filesystems that don't need MNT_NODEV
when mounted by an unprivileged user.
- Relax the permission checks to allow unprivileged users that have
CAP_SYS_ADMIN permissions in the user namespace referred to by the
current mount namespace to be allowed to mount, unmount, and move
filesystems.
Acked-by: "Serge E. Hallyn" <serge@hallyn.com>
Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 4dfcaf05d17c..9ddc86f93221 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1269,7 +1269,7 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
1269 | goto dput_and_out; | 1269 | goto dput_and_out; |
1270 | 1270 | ||
1271 | retval = -EPERM; | 1271 | retval = -EPERM; |
1272 | if (!capable(CAP_SYS_ADMIN)) | 1272 | if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) |
1273 | goto dput_and_out; | 1273 | goto dput_and_out; |
1274 | 1274 | ||
1275 | retval = do_umount(mnt, flags); | 1275 | retval = do_umount(mnt, flags); |
@@ -1295,7 +1295,7 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) | |||
1295 | 1295 | ||
1296 | static int mount_is_safe(struct path *path) | 1296 | static int mount_is_safe(struct path *path) |
1297 | { | 1297 | { |
1298 | if (capable(CAP_SYS_ADMIN)) | 1298 | if (ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) |
1299 | return 0; | 1299 | return 0; |
1300 | return -EPERM; | 1300 | return -EPERM; |
1301 | #ifdef notyet | 1301 | #ifdef notyet |
@@ -1633,7 +1633,7 @@ static int do_change_type(struct path *path, int flag) | |||
1633 | int type; | 1633 | int type; |
1634 | int err = 0; | 1634 | int err = 0; |
1635 | 1635 | ||
1636 | if (!capable(CAP_SYS_ADMIN)) | 1636 | if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) |
1637 | return -EPERM; | 1637 | return -EPERM; |
1638 | 1638 | ||
1639 | if (path->dentry != path->mnt->mnt_root) | 1639 | if (path->dentry != path->mnt->mnt_root) |
@@ -1797,7 +1797,7 @@ static int do_move_mount(struct path *path, const char *old_name) | |||
1797 | struct mount *p; | 1797 | struct mount *p; |
1798 | struct mount *old; | 1798 | struct mount *old; |
1799 | int err = 0; | 1799 | int err = 0; |
1800 | if (!capable(CAP_SYS_ADMIN)) | 1800 | if (!ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) |
1801 | return -EPERM; | 1801 | return -EPERM; |
1802 | if (!old_name || !*old_name) | 1802 | if (!old_name || !*old_name) |
1803 | return -EINVAL; | 1803 | return -EINVAL; |
@@ -1884,21 +1884,6 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) | |||
1884 | return ERR_PTR(err); | 1884 | return ERR_PTR(err); |
1885 | } | 1885 | } |
1886 | 1886 | ||
1887 | static struct vfsmount * | ||
1888 | do_kern_mount(const char *fstype, int flags, const char *name, void *data) | ||
1889 | { | ||
1890 | struct file_system_type *type = get_fs_type(fstype); | ||
1891 | struct vfsmount *mnt; | ||
1892 | if (!type) | ||
1893 | return ERR_PTR(-ENODEV); | ||
1894 | mnt = vfs_kern_mount(type, flags, name, data); | ||
1895 | if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && | ||
1896 | !mnt->mnt_sb->s_subtype) | ||
1897 | mnt = fs_set_subtype(mnt, fstype); | ||
1898 | put_filesystem(type); | ||
1899 | return mnt; | ||
1900 | } | ||
1901 | |||
1902 | /* | 1887 | /* |
1903 | * add a mount into a namespace's mount tree | 1888 | * add a mount into a namespace's mount tree |
1904 | */ | 1889 | */ |
@@ -1944,20 +1929,46 @@ unlock: | |||
1944 | * create a new mount for userspace and request it to be added into the | 1929 | * create a new mount for userspace and request it to be added into the |
1945 | * namespace's tree | 1930 | * namespace's tree |
1946 | */ | 1931 | */ |
1947 | static int do_new_mount(struct path *path, const char *type, int flags, | 1932 | static int do_new_mount(struct path *path, const char *fstype, int flags, |
1948 | int mnt_flags, const char *name, void *data) | 1933 | int mnt_flags, const char *name, void *data) |
1949 | { | 1934 | { |
1935 | struct file_system_type *type; | ||
1936 | struct user_namespace *user_ns; | ||
1950 | struct vfsmount *mnt; | 1937 | struct vfsmount *mnt; |
1951 | int err; | 1938 | int err; |
1952 | 1939 | ||
1953 | if (!type) | 1940 | if (!fstype) |
1954 | return -EINVAL; | 1941 | return -EINVAL; |
1955 | 1942 | ||
1956 | /* we need capabilities... */ | 1943 | /* we need capabilities... */ |
1957 | if (!capable(CAP_SYS_ADMIN)) | 1944 | user_ns = real_mount(path->mnt)->mnt_ns->user_ns; |
1945 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
1958 | return -EPERM; | 1946 | return -EPERM; |
1959 | 1947 | ||
1960 | mnt = do_kern_mount(type, flags, name, data); | 1948 | type = get_fs_type(fstype); |
1949 | if (!type) | ||
1950 | return -ENODEV; | ||
1951 | |||
1952 | if (user_ns != &init_user_ns) { | ||
1953 | if (!(type->fs_flags & FS_USERNS_MOUNT)) { | ||
1954 | put_filesystem(type); | ||
1955 | return -EPERM; | ||
1956 | } | ||
1957 | /* Only in special cases allow devices from mounts | ||
1958 | * created outside the initial user namespace. | ||
1959 | */ | ||
1960 | if (!(type->fs_flags & FS_USERNS_DEV_MOUNT)) { | ||
1961 | flags |= MS_NODEV; | ||
1962 | mnt_flags |= MNT_NODEV; | ||
1963 | } | ||
1964 | } | ||
1965 | |||
1966 | mnt = vfs_kern_mount(type, flags, name, data); | ||
1967 | if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && | ||
1968 | !mnt->mnt_sb->s_subtype) | ||
1969 | mnt = fs_set_subtype(mnt, fstype); | ||
1970 | |||
1971 | put_filesystem(type); | ||
1961 | if (IS_ERR(mnt)) | 1972 | if (IS_ERR(mnt)) |
1962 | return PTR_ERR(mnt); | 1973 | return PTR_ERR(mnt); |
1963 | 1974 | ||
@@ -2549,7 +2560,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2549 | struct mount *new_mnt, *root_mnt; | 2560 | struct mount *new_mnt, *root_mnt; |
2550 | int error; | 2561 | int error; |
2551 | 2562 | ||
2552 | if (!capable(CAP_SYS_ADMIN)) | 2563 | if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) |
2553 | return -EPERM; | 2564 | return -EPERM; |
2554 | 2565 | ||
2555 | error = user_path_dir(new_root, &new); | 2566 | error = user_path_dir(new_root, &new); |
@@ -2631,8 +2642,13 @@ static void __init init_mount_tree(void) | |||
2631 | struct vfsmount *mnt; | 2642 | struct vfsmount *mnt; |
2632 | struct mnt_namespace *ns; | 2643 | struct mnt_namespace *ns; |
2633 | struct path root; | 2644 | struct path root; |
2645 | struct file_system_type *type; | ||
2634 | 2646 | ||
2635 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 2647 | type = get_fs_type("rootfs"); |
2648 | if (!type) | ||
2649 | panic("Can't find rootfs type"); | ||
2650 | mnt = vfs_kern_mount(type, 0, "rootfs", NULL); | ||
2651 | put_filesystem(type); | ||
2636 | if (IS_ERR(mnt)) | 2652 | if (IS_ERR(mnt)) |
2637 | panic("Can't create rootfs"); | 2653 | panic("Can't create rootfs"); |
2638 | 2654 | ||
@@ -2757,7 +2773,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) | |||
2757 | struct mnt_namespace *mnt_ns = ns; | 2773 | struct mnt_namespace *mnt_ns = ns; |
2758 | struct path root; | 2774 | struct path root; |
2759 | 2775 | ||
2760 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_CHROOT)) | 2776 | if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || |
2777 | !nsown_capable(CAP_SYS_CHROOT)) | ||
2761 | return -EINVAL; | 2778 | return -EINVAL; |
2762 | 2779 | ||
2763 | if (fs->users != 1) | 2780 | if (fs->users != 1) |