aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-03-07 21:49:36 -0500
committerEric W. Biederman <ebiederm@xmission.com>2012-11-19 08:59:18 -0500
commit8823c079ba7136dc1948d6f6dcb5f8022bde438e (patch)
tree2b27b0a046d453c95c1b0490c0650ea586ef0f86 /fs/namespace.c
parenta85fb273c94648cbf20a5f9bcf8bbbb075f271ad (diff)
vfs: Add setns support for the mount namespace
setns support for the mount namespace is a little tricky as an arbitrary decision must be made about what to set fs->root and fs->pwd to, as there is no expectation of a relationship between the two mount namespaces. Therefore I arbitrarily find the root mount point, and follow every mount on top of it to find the top of the mount stack. Then I set fs->root and fs->pwd to that location. The topmost root of the mount stack seems like a reasonable place to be. Bind mount support for the mount namespace inodes has the possibility of creating circular dependencies between mount namespaces. Circular dependencies can result in loops that prevent mount namespaces from every being freed. I avoid creating those circular dependencies by adding a sequence number to the mount namespace and require all bind mounts be of a younger mount namespace into an older mount namespace. Add a helper function proc_ns_inode so it is possible to detect when we are attempting to bind mound a namespace inode. Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 24960626bb6b..d287e7e74644 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -20,6 +20,7 @@
20#include <linux/fs_struct.h> /* get_fs_root et.al. */ 20#include <linux/fs_struct.h> /* get_fs_root et.al. */
21#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */ 21#include <linux/fsnotify.h> /* fsnotify_vfsmount_delete */
22#include <linux/uaccess.h> 22#include <linux/uaccess.h>
23#include <linux/proc_fs.h>
23#include "pnode.h" 24#include "pnode.h"
24#include "internal.h" 25#include "internal.h"
25 26
@@ -1308,6 +1309,26 @@ static int mount_is_safe(struct path *path)
1308#endif 1309#endif
1309} 1310}
1310 1311
1312static bool mnt_ns_loop(struct path *path)
1313{
1314 /* Could bind mounting the mount namespace inode cause a
1315 * mount namespace loop?
1316 */
1317 struct inode *inode = path->dentry->d_inode;
1318 struct proc_inode *ei;
1319 struct mnt_namespace *mnt_ns;
1320
1321 if (!proc_ns_inode(inode))
1322 return false;
1323
1324 ei = PROC_I(inode);
1325 if (ei->ns_ops != &mntns_operations)
1326 return false;
1327
1328 mnt_ns = ei->ns;
1329 return current->nsproxy->mnt_ns->seq >= mnt_ns->seq;
1330}
1331
1311struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, 1332struct mount *copy_tree(struct mount *mnt, struct dentry *dentry,
1312 int flag) 1333 int flag)
1313{ 1334{
@@ -1655,6 +1676,10 @@ static int do_loopback(struct path *path, const char *old_name,
1655 if (err) 1676 if (err)
1656 return err; 1677 return err;
1657 1678
1679 err = -EINVAL;
1680 if (mnt_ns_loop(&old_path))
1681 goto out;
1682
1658 err = lock_mount(path); 1683 err = lock_mount(path);
1659 if (err) 1684 if (err)
1660 goto out; 1685 goto out;
@@ -2261,6 +2286,15 @@ dput_out:
2261 return retval; 2286 return retval;
2262} 2287}
2263 2288
2289/*
2290 * Assign a sequence number so we can detect when we attempt to bind
2291 * mount a reference to an older mount namespace into the current
2292 * mount namespace, preventing reference counting loops. A 64bit
2293 * number incrementing at 10Ghz will take 12,427 years to wrap which
2294 * is effectively never, so we can ignore the possibility.
2295 */
2296static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1);
2297
2264static struct mnt_namespace *alloc_mnt_ns(void) 2298static struct mnt_namespace *alloc_mnt_ns(void)
2265{ 2299{
2266 struct mnt_namespace *new_ns; 2300 struct mnt_namespace *new_ns;
@@ -2268,6 +2302,7 @@ static struct mnt_namespace *alloc_mnt_ns(void)
2268 new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); 2302 new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL);
2269 if (!new_ns) 2303 if (!new_ns)
2270 return ERR_PTR(-ENOMEM); 2304 return ERR_PTR(-ENOMEM);
2305 new_ns->seq = atomic64_add_return(1, &mnt_ns_seq);
2271 atomic_set(&new_ns->count, 1); 2306 atomic_set(&new_ns->count, 1);
2272 new_ns->root = NULL; 2307 new_ns->root = NULL;
2273 INIT_LIST_HEAD(&new_ns->list); 2308 INIT_LIST_HEAD(&new_ns->list);
@@ -2681,3 +2716,63 @@ bool our_mnt(struct vfsmount *mnt)
2681{ 2716{
2682 return check_mnt(real_mount(mnt)); 2717 return check_mnt(real_mount(mnt));
2683} 2718}
2719
2720static void *mntns_get(struct task_struct *task)
2721{
2722 struct mnt_namespace *ns = NULL;
2723 struct nsproxy *nsproxy;
2724
2725 rcu_read_lock();
2726 nsproxy = task_nsproxy(task);
2727 if (nsproxy) {
2728 ns = nsproxy->mnt_ns;
2729 get_mnt_ns(ns);
2730 }
2731 rcu_read_unlock();
2732
2733 return ns;
2734}
2735
2736static void mntns_put(void *ns)
2737{
2738 put_mnt_ns(ns);
2739}
2740
2741static int mntns_install(struct nsproxy *nsproxy, void *ns)
2742{
2743 struct fs_struct *fs = current->fs;
2744 struct mnt_namespace *mnt_ns = ns;
2745 struct path root;
2746
2747 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_CHROOT))
2748 return -EINVAL;
2749
2750 if (fs->users != 1)
2751 return -EINVAL;
2752
2753 get_mnt_ns(mnt_ns);
2754 put_mnt_ns(nsproxy->mnt_ns);
2755 nsproxy->mnt_ns = mnt_ns;
2756
2757 /* Find the root */
2758 root.mnt = &mnt_ns->root->mnt;
2759 root.dentry = mnt_ns->root->mnt.mnt_root;
2760 path_get(&root);
2761 while(d_mountpoint(root.dentry) && follow_down_one(&root))
2762 ;
2763
2764 /* Update the pwd and root */
2765 set_fs_pwd(fs, &root);
2766 set_fs_root(fs, &root);
2767
2768 path_put(&root);
2769 return 0;
2770}
2771
2772const struct proc_ns_operations mntns_operations = {
2773 .name = "mnt",
2774 .type = CLONE_NEWNS,
2775 .get = mntns_get,
2776 .put = mntns_put,
2777 .install = mntns_install,
2778};