aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c65
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 */
385int __mnt_want_write_file(struct file *file) 385int __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 */
1243static 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);
1276dput_and_out: 1283dput_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
1296static 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
1314static bool mnt_ns_loop(struct path *path) 1303static 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);