common object embedded into various struct ....ns
[linux-2.6-block.git] / fs / namespace.c
index 348562f14e93b712dfe4f2e335eb39d632c63f28..adc2ea2532a04fc0ffb686f125dbdccffdbee6b8 100644 (file)
@@ -1439,6 +1439,8 @@ static int do_umount(struct mount *mnt, int flags)
                 * Special case for "unmounting" root ...
                 * we just try to remount it readonly.
                 */
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
                down_write(&sb->s_umount);
                if (!(sb->s_flags & MS_RDONLY))
                        retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
@@ -1684,6 +1686,33 @@ void drop_collected_mounts(struct vfsmount *mnt)
        namespace_unlock();
 }
 
+/**
+ * clone_private_mount - create a private clone of a path
+ *
+ * This creates a new vfsmount, which will be the clone of @path.  The new will
+ * not be attached anywhere in the namespace and will be private (i.e. changes
+ * to the originating mount won't be propagated into this).
+ *
+ * Release with mntput().
+ */
+struct vfsmount *clone_private_mount(struct path *path)
+{
+       struct mount *old_mnt = real_mount(path->mnt);
+       struct mount *new_mnt;
+
+       if (IS_MNT_UNBINDABLE(old_mnt))
+               return ERR_PTR(-EINVAL);
+
+       down_read(&namespace_sem);
+       new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE);
+       up_read(&namespace_sem);
+       if (IS_ERR(new_mnt))
+               return ERR_CAST(new_mnt);
+
+       return &new_mnt->mnt;
+}
+EXPORT_SYMBOL_GPL(clone_private_mount);
+
 int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
                   struct vfsmount *root)
 {
@@ -2611,7 +2640,7 @@ dput_out:
 
 static void free_mnt_ns(struct mnt_namespace *ns)
 {
-       proc_free_inum(ns->proc_inum);
+       proc_free_inum(ns->ns.inum);
        put_user_ns(ns->user_ns);
        kfree(ns);
 }
@@ -2633,7 +2662,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns)
        new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
        if (!new_ns)
                return ERR_PTR(-ENOMEM);
-       ret = proc_alloc_inum(&new_ns->proc_inum);
+       ret = proc_alloc_inum(&new_ns->ns.inum);
        if (ret) {
                kfree(new_ns);
                return ERR_PTR(ret);
@@ -2913,6 +2942,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
        /* make sure we can reach put_old from new_root */
        if (!is_path_reachable(old_mnt, old.dentry, &new))
                goto out4;
+       /* make certain new is below the root */
+       if (!is_path_reachable(new_mnt, new.dentry, &root))
+               goto out4;
        root_mp->m_count++; /* pin it so it won't go away */
        lock_mount_hash();
        detach_mnt(new_mnt, &parent_path);
@@ -3169,7 +3201,7 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns)
 static unsigned int mntns_inum(void *ns)
 {
        struct mnt_namespace *mnt_ns = ns;
-       return mnt_ns->proc_inum;
+       return mnt_ns->ns.inum;
 }
 
 const struct proc_ns_operations mntns_operations = {