summaryrefslogtreecommitdiffstats
path: root/fs/nsfs.c
diff options
context:
space:
mode:
authorAndrey Vagin <avagin@openvz.org>2016-09-06 03:47:14 -0400
committerEric W. Biederman <ebiederm@xmission.com>2016-09-22 20:59:40 -0400
commit6786741dbf99e44fb0c0ed85a37582b8a26f1c3b (patch)
treec6d4f7bbb9920c79f6a6393d0900bd850507c37a /fs/nsfs.c
parentbcac25a58bfc6bd79191ac5d7afb49bea96da8c9 (diff)
nsfs: add ioctl to get an owning user namespace for ns file descriptor
Each namespace has an owning user namespace and now there is not way to discover these relationships. Understending namespaces relationships allows to answer the question: what capability does process X have to perform operations on a resource governed by namespace Y? After a long discussion, Eric W. Biederman proposed to use ioctl-s for this purpose. The NS_GET_USERNS ioctl returns a file descriptor to an owning user namespace. It returns EPERM if a target namespace is outside of a current user namespace. v2: rename parent to relative v3: Add a missing mntput when returning -EAGAIN --EWB Acked-by: Serge Hallyn <serge@hallyn.com> Link: https://lkml.org/lkml/2016/7/6/158 Signed-off-by: Andrei Vagin <avagin@openvz.org> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'fs/nsfs.c')
-rw-r--r--fs/nsfs.c96
1 files changed, 83 insertions, 13 deletions
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 8f20d6016e20..3887da470f7e 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -5,11 +5,16 @@
5#include <linux/magic.h> 5#include <linux/magic.h>
6#include <linux/ktime.h> 6#include <linux/ktime.h>
7#include <linux/seq_file.h> 7#include <linux/seq_file.h>
8#include <linux/user_namespace.h>
9#include <linux/nsfs.h>
8 10
9static struct vfsmount *nsfs_mnt; 11static struct vfsmount *nsfs_mnt;
10 12
13static long ns_ioctl(struct file *filp, unsigned int ioctl,
14 unsigned long arg);
11static const struct file_operations ns_file_operations = { 15static const struct file_operations ns_file_operations = {
12 .llseek = no_llseek, 16 .llseek = no_llseek,
17 .unlocked_ioctl = ns_ioctl,
13}; 18};
14 19
15static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) 20static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
@@ -44,22 +49,14 @@ static void nsfs_evict(struct inode *inode)
44 ns->ops->put(ns); 49 ns->ops->put(ns);
45} 50}
46 51
47void *ns_get_path(struct path *path, struct task_struct *task, 52static void *__ns_get_path(struct path *path, struct ns_common *ns)
48 const struct proc_ns_operations *ns_ops)
49{ 53{
50 struct vfsmount *mnt = mntget(nsfs_mnt); 54 struct vfsmount *mnt = mntget(nsfs_mnt);
51 struct qstr qname = { .name = "", }; 55 struct qstr qname = { .name = "", };
52 struct dentry *dentry; 56 struct dentry *dentry;
53 struct inode *inode; 57 struct inode *inode;
54 struct ns_common *ns;
55 unsigned long d; 58 unsigned long d;
56 59
57again:
58 ns = ns_ops->get(task);
59 if (!ns) {
60 mntput(mnt);
61 return ERR_PTR(-ENOENT);
62 }
63 rcu_read_lock(); 60 rcu_read_lock();
64 d = atomic_long_read(&ns->stashed); 61 d = atomic_long_read(&ns->stashed);
65 if (!d) 62 if (!d)
@@ -68,7 +65,7 @@ again:
68 if (!lockref_get_not_dead(&dentry->d_lockref)) 65 if (!lockref_get_not_dead(&dentry->d_lockref))
69 goto slow; 66 goto slow;
70 rcu_read_unlock(); 67 rcu_read_unlock();
71 ns_ops->put(ns); 68 ns->ops->put(ns);
72got_it: 69got_it:
73 path->mnt = mnt; 70 path->mnt = mnt;
74 path->dentry = dentry; 71 path->dentry = dentry;
@@ -77,7 +74,7 @@ slow:
77 rcu_read_unlock(); 74 rcu_read_unlock();
78 inode = new_inode_pseudo(mnt->mnt_sb); 75 inode = new_inode_pseudo(mnt->mnt_sb);
79 if (!inode) { 76 if (!inode) {
80 ns_ops->put(ns); 77 ns->ops->put(ns);
81 mntput(mnt); 78 mntput(mnt);
82 return ERR_PTR(-ENOMEM); 79 return ERR_PTR(-ENOMEM);
83 } 80 }
@@ -95,17 +92,90 @@ slow:
95 return ERR_PTR(-ENOMEM); 92 return ERR_PTR(-ENOMEM);
96 } 93 }
97 d_instantiate(dentry, inode); 94 d_instantiate(dentry, inode);
98 dentry->d_fsdata = (void *)ns_ops; 95 dentry->d_fsdata = (void *)ns->ops;
99 d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); 96 d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
100 if (d) { 97 if (d) {
101 d_delete(dentry); /* make sure ->d_prune() does nothing */ 98 d_delete(dentry); /* make sure ->d_prune() does nothing */
102 dput(dentry); 99 dput(dentry);
100 mntput(mnt);
103 cpu_relax(); 101 cpu_relax();
104 goto again; 102 return ERR_PTR(-EAGAIN);
105 } 103 }
106 goto got_it; 104 goto got_it;
107} 105}
108 106
107void *ns_get_path(struct path *path, struct task_struct *task,
108 const struct proc_ns_operations *ns_ops)
109{
110 struct ns_common *ns;
111 void *ret;
112
113again:
114 ns = ns_ops->get(task);
115 if (!ns)
116 return ERR_PTR(-ENOENT);
117
118 ret = __ns_get_path(path, ns);
119 if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN)
120 goto again;
121 return ret;
122}
123
124static int open_related_ns(struct ns_common *ns,
125 struct ns_common *(*get_ns)(struct ns_common *ns))
126{
127 struct path path = {};
128 struct file *f;
129 void *err;
130 int fd;
131
132 fd = get_unused_fd_flags(O_CLOEXEC);
133 if (fd < 0)
134 return fd;
135
136 while (1) {
137 struct ns_common *relative;
138
139 relative = get_ns(ns);
140 if (IS_ERR(relative)) {
141 put_unused_fd(fd);
142 return PTR_ERR(relative);
143 }
144
145 err = __ns_get_path(&path, relative);
146 if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN)
147 continue;
148 break;
149 }
150 if (IS_ERR(err)) {
151 put_unused_fd(fd);
152 return PTR_ERR(err);
153 }
154
155 f = dentry_open(&path, O_RDONLY, current_cred());
156 path_put(&path);
157 if (IS_ERR(f)) {
158 put_unused_fd(fd);
159 fd = PTR_ERR(f);
160 } else
161 fd_install(fd, f);
162
163 return fd;
164}
165
166static long ns_ioctl(struct file *filp, unsigned int ioctl,
167 unsigned long arg)
168{
169 struct ns_common *ns = get_proc_ns(file_inode(filp));
170
171 switch (ioctl) {
172 case NS_GET_USERNS:
173 return open_related_ns(ns, ns_get_owner);
174 default:
175 return -ENOTTY;
176 }
177}
178
109int ns_get_name(char *buf, size_t size, struct task_struct *task, 179int ns_get_name(char *buf, size_t size, struct task_struct *task,
110 const struct proc_ns_operations *ns_ops) 180 const struct proc_ns_operations *ns_ops)
111{ 181{