aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c34
-rw-r--r--include/linux/mount.h1
2 files changed, 35 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 / */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 73005f9957ea..38cd98f112a0 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -48,6 +48,7 @@ struct mnt_namespace;
48#define MNT_INTERNAL 0x4000 48#define MNT_INTERNAL 0x4000
49 49
50#define MNT_LOCK_READONLY 0x400000 50#define MNT_LOCK_READONLY 0x400000
51#define MNT_LOCKED 0x800000
51 52
52struct vfsmount { 53struct vfsmount {
53 struct dentry *mnt_root; /* root of the mounted tree */ 54 struct dentry *mnt_root; /* root of the mounted tree */