diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 65 |
1 files changed, 22 insertions, 43 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 398a50ff2438..50ca17d3cb45 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -313,7 +313,7 @@ int __mnt_want_write(struct vfsmount *m) | |||
313 | * incremented count after it has set MNT_WRITE_HOLD. | 313 | * incremented count after it has set MNT_WRITE_HOLD. |
314 | */ | 314 | */ |
315 | smp_mb(); | 315 | smp_mb(); |
316 | while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) | 316 | while (ACCESS_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD) |
317 | cpu_relax(); | 317 | cpu_relax(); |
318 | /* | 318 | /* |
319 | * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will | 319 | * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will |
@@ -384,7 +384,7 @@ EXPORT_SYMBOL_GPL(mnt_clone_write); | |||
384 | */ | 384 | */ |
385 | int __mnt_want_write_file(struct file *file) | 385 | int __mnt_want_write_file(struct file *file) |
386 | { | 386 | { |
387 | struct inode *inode = file->f_dentry->d_inode; | 387 | struct inode *inode = file_inode(file); |
388 | 388 | ||
389 | if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) | 389 | if (!(file->f_mode & FMODE_WRITE) || special_file(inode->i_mode)) |
390 | return __mnt_want_write(file->f_path.mnt); | 390 | return __mnt_want_write(file->f_path.mnt); |
@@ -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 */ |
@@ -1293,24 +1300,6 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) | |||
1293 | 1300 | ||
1294 | #endif | 1301 | #endif |
1295 | 1302 | ||
1296 | static int mount_is_safe(struct path *path) | ||
1297 | { | ||
1298 | if (ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) | ||
1299 | return 0; | ||
1300 | return -EPERM; | ||
1301 | #ifdef notyet | ||
1302 | if (S_ISLNK(path->dentry->d_inode->i_mode)) | ||
1303 | return -EPERM; | ||
1304 | if (path->dentry->d_inode->i_mode & S_ISVTX) { | ||
1305 | if (current_uid() != path->dentry->d_inode->i_uid) | ||
1306 | return -EPERM; | ||
1307 | } | ||
1308 | if (inode_permission(path->dentry->d_inode, MAY_WRITE)) | ||
1309 | return -EPERM; | ||
1310 | return 0; | ||
1311 | #endif | ||
1312 | } | ||
1313 | |||
1314 | static bool mnt_ns_loop(struct path *path) | 1303 | static bool mnt_ns_loop(struct path *path) |
1315 | { | 1304 | { |
1316 | /* Could bind mounting the mount namespace inode cause a | 1305 | /* Could bind mounting the mount namespace inode cause a |
@@ -1633,9 +1622,6 @@ static int do_change_type(struct path *path, int flag) | |||
1633 | int type; | 1622 | int type; |
1634 | int err = 0; | 1623 | int err = 0; |
1635 | 1624 | ||
1636 | if (!ns_capable(mnt->mnt_ns->user_ns, CAP_SYS_ADMIN)) | ||
1637 | return -EPERM; | ||
1638 | |||
1639 | if (path->dentry != path->mnt->mnt_root) | 1625 | if (path->dentry != path->mnt->mnt_root) |
1640 | return -EINVAL; | 1626 | return -EINVAL; |
1641 | 1627 | ||
@@ -1669,9 +1655,7 @@ static int do_loopback(struct path *path, const char *old_name, | |||
1669 | LIST_HEAD(umount_list); | 1655 | LIST_HEAD(umount_list); |
1670 | struct path old_path; | 1656 | struct path old_path; |
1671 | struct mount *mnt = NULL, *old; | 1657 | struct mount *mnt = NULL, *old; |
1672 | int err = mount_is_safe(path); | 1658 | int err; |
1673 | if (err) | ||
1674 | return err; | ||
1675 | if (!old_name || !*old_name) | 1659 | if (!old_name || !*old_name) |
1676 | return -EINVAL; | 1660 | return -EINVAL; |
1677 | err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); | 1661 | err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); |
@@ -1748,9 +1732,6 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1748 | struct super_block *sb = path->mnt->mnt_sb; | 1732 | struct super_block *sb = path->mnt->mnt_sb; |
1749 | struct mount *mnt = real_mount(path->mnt); | 1733 | struct mount *mnt = real_mount(path->mnt); |
1750 | 1734 | ||
1751 | if (!capable(CAP_SYS_ADMIN)) | ||
1752 | return -EPERM; | ||
1753 | |||
1754 | if (!check_mnt(mnt)) | 1735 | if (!check_mnt(mnt)) |
1755 | return -EINVAL; | 1736 | return -EINVAL; |
1756 | 1737 | ||
@@ -1764,6 +1745,8 @@ static int do_remount(struct path *path, int flags, int mnt_flags, | |||
1764 | down_write(&sb->s_umount); | 1745 | down_write(&sb->s_umount); |
1765 | if (flags & MS_BIND) | 1746 | if (flags & MS_BIND) |
1766 | err = change_mount_flags(path->mnt, flags); | 1747 | err = change_mount_flags(path->mnt, flags); |
1748 | else if (!capable(CAP_SYS_ADMIN)) | ||
1749 | err = -EPERM; | ||
1767 | else | 1750 | else |
1768 | err = do_remount_sb(sb, flags, data, 0); | 1751 | err = do_remount_sb(sb, flags, data, 0); |
1769 | if (!err) { | 1752 | if (!err) { |
@@ -1796,9 +1779,7 @@ static int do_move_mount(struct path *path, const char *old_name) | |||
1796 | struct path old_path, parent_path; | 1779 | struct path old_path, parent_path; |
1797 | struct mount *p; | 1780 | struct mount *p; |
1798 | struct mount *old; | 1781 | struct mount *old; |
1799 | int err = 0; | 1782 | int err; |
1800 | if (!ns_capable(real_mount(path->mnt)->mnt_ns->user_ns, CAP_SYS_ADMIN)) | ||
1801 | return -EPERM; | ||
1802 | if (!old_name || !*old_name) | 1783 | if (!old_name || !*old_name) |
1803 | return -EINVAL; | 1784 | return -EINVAL; |
1804 | err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); | 1785 | err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); |
@@ -1933,18 +1914,13 @@ static int do_new_mount(struct path *path, const char *fstype, int flags, | |||
1933 | int mnt_flags, const char *name, void *data) | 1914 | int mnt_flags, const char *name, void *data) |
1934 | { | 1915 | { |
1935 | struct file_system_type *type; | 1916 | struct file_system_type *type; |
1936 | struct user_namespace *user_ns; | 1917 | struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; |
1937 | struct vfsmount *mnt; | 1918 | struct vfsmount *mnt; |
1938 | int err; | 1919 | int err; |
1939 | 1920 | ||
1940 | if (!fstype) | 1921 | if (!fstype) |
1941 | return -EINVAL; | 1922 | return -EINVAL; |
1942 | 1923 | ||
1943 | /* we need capabilities... */ | ||
1944 | user_ns = real_mount(path->mnt)->mnt_ns->user_ns; | ||
1945 | if (!ns_capable(user_ns, CAP_SYS_ADMIN)) | ||
1946 | return -EPERM; | ||
1947 | |||
1948 | type = get_fs_type(fstype); | 1924 | type = get_fs_type(fstype); |
1949 | if (!type) | 1925 | if (!type) |
1950 | return -ENODEV; | 1926 | return -ENODEV; |
@@ -2258,6 +2234,9 @@ long do_mount(const char *dev_name, const char *dir_name, | |||
2258 | if (retval) | 2234 | if (retval) |
2259 | goto dput_out; | 2235 | goto dput_out; |
2260 | 2236 | ||
2237 | if (!may_mount()) | ||
2238 | return -EPERM; | ||
2239 | |||
2261 | /* Default to relatime unless overriden */ | 2240 | /* Default to relatime unless overriden */ |
2262 | if (!(flags & MS_NOATIME)) | 2241 | if (!(flags & MS_NOATIME)) |
2263 | mnt_flags |= MNT_RELATIME; | 2242 | mnt_flags |= MNT_RELATIME; |
@@ -2567,7 +2546,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2567 | struct mount *new_mnt, *root_mnt; | 2546 | struct mount *new_mnt, *root_mnt; |
2568 | int error; | 2547 | int error; |
2569 | 2548 | ||
2570 | if (!ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN)) | 2549 | if (!may_mount()) |
2571 | return -EPERM; | 2550 | return -EPERM; |
2572 | 2551 | ||
2573 | error = user_path_dir(new_root, &new); | 2552 | error = user_path_dir(new_root, &new); |