aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2013-03-30 00:04:39 -0400
committerEric W. Biederman <ebiederm@xmission.com>2013-07-24 12:14:46 -0400
commit5ff9d8a65ce80efb509ce4e8051394e9ed2cd942 (patch)
treee2ae0447cda004f29a2a081bbdb428a72862402b /fs/namespace.c
parentad81f0545ef01ea651886dddac4bef6cec930092 (diff)
vfs: Lock in place mounts from more privileged users
When creating a less privileged mount namespace or propogating mounts from a more privileged to a less privileged mount namespace lock the submounts so they may not be unmounted individually in the child mount namespace revealing what is under them. This enforces the reasonable expectation that it is not possible to see under a mount point. Most of the time mounts are on empty directories and revealing that does not matter, however I have seen an occassionaly sloppy configuration where there were interesting things concealed under a mount point that probably should not be revealed. Expirable submounts are not locked because they will eventually unmount automatically so whatever is under them already needs to be safe for unprivileged users to access. From a practical standpoint these restrictions do not appear to be significant for unprivileged users of the mount namespace. Recursive bind mounts and pivot_root continues to work, and mounts that are created in a mount namespace may be unmounted there. All of which means that the common idiom of keeping a directory of interesting files and using pivot_root to throw everything else away continues to work just fine. Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Acked-by: Andy Lutomirski <luto@amacapital.net> Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 7b1ca9ba0b0a..7e16a730559c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -831,6 +831,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
831 if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) 831 if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
832 mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; 832 mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
833 833
834 /* Don't allow unprivileged users to reveal what is under a mount */
835 if ((flag & CL_UNPRIVILEGED) && list_empty(&old->mnt_expire))
836 mnt->mnt.mnt_flags |= MNT_LOCKED;
837
834 atomic_inc(&sb->s_active); 838 atomic_inc(&sb->s_active);
835 mnt->mnt.mnt_sb = sb; 839 mnt->mnt.mnt_sb = sb;
836 mnt->mnt.mnt_root = dget(root); 840 mnt->mnt.mnt_root = dget(root);
@@ -1327,6 +1331,8 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
1327 goto dput_and_out; 1331 goto dput_and_out;
1328 if (!check_mnt(mnt)) 1332 if (!check_mnt(mnt))
1329 goto dput_and_out; 1333 goto dput_and_out;
1334 if (mnt->mnt.mnt_flags & MNT_LOCKED)
1335 goto dput_and_out;
1330 1336
1331 retval = do_umount(mnt, flags); 1337 retval = do_umount(mnt, flags);
1332dput_and_out: 1338dput_and_out:
@@ -1381,6 +1387,7 @@ struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
1381 if (IS_ERR(q)) 1387 if (IS_ERR(q))
1382 return q; 1388 return q;
1383 1389
1390 q->mnt.mnt_flags &= ~MNT_LOCKED;
1384 q->mnt_mountpoint = mnt->mnt_mountpoint; 1391 q->mnt_mountpoint = mnt->mnt_mountpoint;
1385 1392
1386 p = mnt; 1393 p = mnt;
@@ -1696,6 +1703,19 @@ static int do_change_type(struct path *path, int flag)
1696 return err; 1703 return err;
1697} 1704}
1698 1705
1706static bool has_locked_children(struct mount *mnt, struct dentry *dentry)
1707{
1708 struct mount *child;
1709 list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) {
1710 if (!is_subdir(child->mnt_mountpoint, dentry))
1711 continue;
1712
1713 if (child->mnt.mnt_flags & MNT_LOCKED)
1714 return true;
1715 }
1716 return false;
1717}
1718
1699/* 1719/*
1700 * do loopback mount. 1720 * do loopback mount.
1701 */ 1721 */
@@ -1731,6 +1751,9 @@ static int do_loopback(struct path *path, const char *old_name,
1731 if (!check_mnt(parent) || !check_mnt(old)) 1751 if (!check_mnt(parent) || !check_mnt(old))
1732 goto out2; 1752 goto out2;
1733 1753
1754 if (!recurse && has_locked_children(old, old_path.dentry))
1755 goto out2;
1756
1734 if (recurse) 1757 if (recurse)
1735 mnt = copy_tree(old, old_path.dentry, 0); 1758 mnt = copy_tree(old, old_path.dentry, 0);
1736 else 1759 else
@@ -1741,6 +1764,8 @@ static int do_loopback(struct path *path, const char *old_name,
1741 goto out2; 1764 goto out2;
1742 } 1765 }
1743 1766
1767 mnt->mnt.mnt_flags &= ~MNT_LOCKED;
1768
1744 err = graft_tree(mnt, parent, mp); 1769 err = graft_tree(mnt, parent, mp);
1745 if (err) { 1770 if (err) {
1746 br_write_lock(&vfsmount_lock); 1771 br_write_lock(&vfsmount_lock);
@@ -1853,6 +1878,9 @@ static int do_move_mount(struct path *path, const char *old_name)
1853 if (!check_mnt(p) || !check_mnt(old)) 1878 if (!check_mnt(p) || !check_mnt(old))
1854 goto out1; 1879 goto out1;
1855 1880
1881 if (old->mnt.mnt_flags & MNT_LOCKED)
1882 goto out1;
1883
1856 err = -EINVAL; 1884 err = -EINVAL;
1857 if (old_path.dentry != old_path.mnt->mnt_root) 1885 if (old_path.dentry != old_path.mnt->mnt_root)
1858 goto out1; 1886 goto out1;
@@ -2630,6 +2658,8 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
2630 goto out4; 2658 goto out4;
2631 if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) 2659 if (!check_mnt(root_mnt) || !check_mnt(new_mnt))
2632 goto out4; 2660 goto out4;
2661 if (new_mnt->mnt.mnt_flags & MNT_LOCKED)
2662 goto out4;
2633 error = -ENOENT; 2663 error = -ENOENT;
2634 if (d_unlinked(new.dentry)) 2664 if (d_unlinked(new.dentry))
2635 goto out4; 2665 goto out4;
@@ -2653,6 +2683,10 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
2653 br_write_lock(&vfsmount_lock); 2683 br_write_lock(&vfsmount_lock);
2654 detach_mnt(new_mnt, &parent_path); 2684 detach_mnt(new_mnt, &parent_path);
2655 detach_mnt(root_mnt, &root_parent); 2685 detach_mnt(root_mnt, &root_parent);
2686 if (root_mnt->mnt.mnt_flags & MNT_LOCKED) {
2687 new_mnt->mnt.mnt_flags |= MNT_LOCKED;
2688 root_mnt->mnt.mnt_flags &= ~MNT_LOCKED;
2689 }
2656 /* mount old root on put_old */ 2690 /* mount old root on put_old */
2657 attach_mnt(root_mnt, old_mnt, old_mp); 2691 attach_mnt(root_mnt, old_mnt, old_mp);
2658 /* mount new_root on / */ 2692 /* mount new_root on / */