aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/mount.h1
-rw-r--r--fs/namespace.c95
-rw-r--r--fs/proc/namespaces.c5
-rw-r--r--include/linux/proc_fs.h7
4 files changed, 108 insertions, 0 deletions
diff --git a/fs/mount.h b/fs/mount.h
index 4f291f9de641..e9c37dd3d00d 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -6,6 +6,7 @@ struct mnt_namespace {
6 atomic_t count; 6 atomic_t count;
7 struct mount * root; 7 struct mount * root;
8 struct list_head list; 8 struct list_head list;
9 u64 seq; /* Sequence number to prevent loops */
9 wait_queue_head_t poll; 10 wait_queue_head_t poll;
10 int event; 11 int event;
11}; 12};
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};
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 85ca047e35f1..2a17fd9ae6a9 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -27,6 +27,7 @@ static const struct proc_ns_operations *ns_entries[] = {
27#ifdef CONFIG_PID_NS 27#ifdef CONFIG_PID_NS
28 &pidns_operations, 28 &pidns_operations,
29#endif 29#endif
30 &mntns_operations,
30}; 31};
31 32
32static const struct file_operations ns_file_operations = { 33static const struct file_operations ns_file_operations = {
@@ -201,3 +202,7 @@ out_invalid:
201 return ERR_PTR(-EINVAL); 202 return ERR_PTR(-EINVAL);
202} 203}
203 204
205bool proc_ns_inode(struct inode *inode)
206{
207 return inode->i_fop == &ns_file_operations;
208}
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index acaafcd40aa5..9014c041e752 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -174,6 +174,7 @@ extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
174 struct proc_dir_entry *parent); 174 struct proc_dir_entry *parent);
175 175
176extern struct file *proc_ns_fget(int fd); 176extern struct file *proc_ns_fget(int fd);
177extern bool proc_ns_inode(struct inode *inode);
177 178
178#else 179#else
179 180
@@ -229,6 +230,11 @@ static inline struct file *proc_ns_fget(int fd)
229 return ERR_PTR(-EINVAL); 230 return ERR_PTR(-EINVAL);
230} 231}
231 232
233static inline bool proc_ns_inode(struct inode *inode)
234{
235 return false;
236}
237
232#endif /* CONFIG_PROC_FS */ 238#endif /* CONFIG_PROC_FS */
233 239
234#if !defined(CONFIG_PROC_KCORE) 240#if !defined(CONFIG_PROC_KCORE)
@@ -252,6 +258,7 @@ extern const struct proc_ns_operations netns_operations;
252extern const struct proc_ns_operations utsns_operations; 258extern const struct proc_ns_operations utsns_operations;
253extern const struct proc_ns_operations ipcns_operations; 259extern const struct proc_ns_operations ipcns_operations;
254extern const struct proc_ns_operations pidns_operations; 260extern const struct proc_ns_operations pidns_operations;
261extern const struct proc_ns_operations mntns_operations;
255 262
256union proc_op { 263union proc_op {
257 int (*proc_get_link)(struct dentry *, struct path *); 264 int (*proc_get_link)(struct dentry *, struct path *);