diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2013-02-22 22:45:42 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2013-02-22 23:31:05 -0500 |
commit | 9b40bc90abd126bcc5da5658059b8e72e285e559 (patch) | |
tree | b360cf7d9cf1f7e29f5f6b9c0193fbd1a75334a6 /fs/namespace.c | |
parent | 3a142ed962958d3063f648738a3384ab90017100 (diff) |
get rid of unprotected dereferencing of mnt->mnt_ns
It's safe only under namespace_sem or vfsmount_lock; all places
in fs/namespace.c that want mnt->mnt_ns->user_ns actually want to use
current->nsproxy->mnt_ns->user_ns (note the calls of check_mnt() in
there).
Cc: stable@vger.kernel.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 29 |
1 files changed, 17 insertions, 12 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 55605c552787..edac42c6eff2 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1237,6 +1237,14 @@ static int do_umount(struct mount *mnt, int flags) | |||
1237 | return retval; | 1237 | return retval; |
1238 | } | 1238 | } |
1239 | 1239 | ||
1240 | /* | ||
1241 | * Is the caller allowed to modify his namespace? | ||
1242 | */ | ||
1243 | static inline bool may_mount(void) | ||
1244 | { | ||
1245 | return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN); | ||
1246 | } | ||
1247 | |||
1240 | /* | 1248 | /* |
1241 | * Now umount can handle mount points as well as block devices. | 1249 | * Now umount can handle mount points as well as block devices. |
1242 | * This is important for filesystems which use unnamed block devices. | 1250 | * This is important for filesystems which use unnamed block devices. |
@@ -1255,6 +1263,9 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
1255 | if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) | 1263 | if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) |
1256 | return -EINVAL; | 1264 | return -EINVAL; |
1257 | 1265 | ||
1266 | if (!may_mount()) | ||
1267 | return -EPERM; | ||
1268 | |||
1258 | if (!(flags & UMOUNT_NOFOLLOW)) | 1269 | if (!(flags & UMOUNT_NOFOLLOW)) |
1259 | lookup_flags |= LOOKUP_FOLLOW; | 1270 | lookup_flags |= LOOKUP_FOLLOW; |
1260 | 1271 | ||
@@ -1268,10 +1279,6 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags) | |||
1268 | if (!check_mnt(mnt)) | 1279 | if (!check_mnt(mnt)) |
1269 | goto dput_and_out; | 1280 | goto dput_and_out; |
1270 | 1281 | ||
1271 | retval = -EPERM; | ||
1272 | if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) | ||
1273 | goto dput_and_out; | ||
1274 | |||
1275 | retval = do_umount(mnt, flags); | 1282 | retval = do_umount(mnt, flags); |
1276 | dput_and_out: | 1283 | dput_and_out: |
1277 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ | 1284 | /* we mustn't call path_put() as that would clear mnt_expiry_mark */ |
@@ -1295,7 +1302,7 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) | |||
1295 | 1302 | ||
1296 | static int mount_is_safe(struct path *path) | 1303 | static int mount_is_safe(struct path *path) |
1297 | { | 1304 | { |
1298 | if (ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) | 1305 | if (may_mount()) |
1299 | return 0; | 1306 | return 0; |
1300 | return -EPERM; | 1307 | return -EPERM; |
1301 | #ifdef notyet | 1308 | #ifdef notyet |
@@ -1633,7 +1640,7 @@ static int do_change_type(struct path *path, int flag) | |||
1633 | int type; | 1640 | int type; |
1634 | int err = 0; | 1641 | int err = 0; |
1635 | 1642 | ||
1636 | if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) | 1643 | if (!may_mount()) |
1637 | return -EPERM; | 1644 | return -EPERM; |
1638 | 1645 | ||
1639 | if (path->dentry != path->mnt->mnt_root) | 1646 | if (path->dentry != path->mnt->mnt_root) |
@@ -1797,7 +1804,7 @@ static int do_move_mount(struct path *path, const char *old_name) | |||
1797 | struct mount *p; | 1804 | struct mount *p; |
1798 | struct mount *old; | 1805 | struct mount *old; |
1799 | int err = 0; | 1806 | int err = 0; |
1800 | if (!ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) | 1807 | if (!may_mount()) |
1801 | return -EPERM; | 1808 | return -EPERM; |
1802 | if (!old_name || !*old_name) | 1809 | if (!old_name || !*old_name) |
1803 | return -EINVAL; | 1810 | return -EINVAL; |
@@ -1933,16 +1940,14 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, | |||
1933 | int mnt_flags, const char *name, void *data) | 1940 | int mnt_flags, const char *name, void *data) |
1934 | { | 1941 | { |
1935 | struct file_system_type *type; | 1942 | struct file_system_type *type; |
1936 | struct user_namespace *user_ns; | 1943 | struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; |
1937 | struct vfsmount *mnt; | 1944 | struct vfsmount *mnt; |
1938 | int err; | 1945 | int err; |
1939 | 1946 | ||
1940 | if (!fstype) | 1947 | if (!fstype) |
1941 | return -EINVAL; | 1948 | return -EINVAL; |
1942 | 1949 | ||
1943 | /* we need capabilities... */ | 1950 | if (!may_mount()) |
1944 | user_ns = real_mount(path->mnt)->mnt_ns->user_ns; | ||
1945 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
1946 | return -EPERM; | 1951 | return -EPERM; |
1947 | 1952 | ||
1948 | type = get_fs_type(fstype); | 1953 | type = get_fs_type(fstype); |
@@ -2567,7 +2572,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2567 | struct mount *new_mnt, *root_mnt; | 2572 | struct mount *new_mnt, *root_mnt; |
2568 | int error; | 2573 | int error; |
2569 | 2574 | ||
2570 | if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) | 2575 | if (!may_mount()) |
2571 | return -EPERM; | 2576 | return -EPERM; |
2572 | 2577 | ||
2573 | error = user_path_dir(new_root, &new); | 2578 | error = user_path_dir(new_root, &new); |