Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : #include <linux/mount.h>
3 : : #include <linux/pseudo_fs.h>
4 : : #include <linux/file.h>
5 : : #include <linux/fs.h>
6 : : #include <linux/proc_fs.h>
7 : : #include <linux/proc_ns.h>
8 : : #include <linux/magic.h>
9 : : #include <linux/ktime.h>
10 : : #include <linux/seq_file.h>
11 : : #include <linux/user_namespace.h>
12 : : #include <linux/nsfs.h>
13 : : #include <linux/uaccess.h>
14 : :
15 : : #include "internal.h"
16 : :
17 : : static struct vfsmount *nsfs_mnt;
18 : :
19 : : static long ns_ioctl(struct file *filp, unsigned int ioctl,
20 : : unsigned long arg);
21 : : static const struct file_operations ns_file_operations = {
22 : : .llseek = no_llseek,
23 : : .unlocked_ioctl = ns_ioctl,
24 : : };
25 : :
26 : 0 : static char *ns_dname(struct dentry *dentry, char *buffer, int buflen)
27 : : {
28 : 0 : struct inode *inode = d_inode(dentry);
29 : 0 : const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
30 : :
31 : 0 : return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]",
32 : : ns_ops->name, inode->i_ino);
33 : : }
34 : :
35 : 0 : static void ns_prune_dentry(struct dentry *dentry)
36 : : {
37 [ # # ]: 0 : struct inode *inode = d_inode(dentry);
38 [ # # ]: 0 : if (inode) {
39 : 0 : struct ns_common *ns = inode->i_private;
40 : 0 : atomic_long_set(&ns->stashed, 0);
41 : : }
42 : 0 : }
43 : :
44 : : const struct dentry_operations ns_dentry_operations =
45 : : {
46 : : .d_prune = ns_prune_dentry,
47 : : .d_delete = always_delete_dentry,
48 : : .d_dname = ns_dname,
49 : : };
50 : :
51 : 0 : static void nsfs_evict(struct inode *inode)
52 : : {
53 : 0 : struct ns_common *ns = inode->i_private;
54 : 0 : clear_inode(inode);
55 : 0 : ns->ops->put(ns);
56 : 0 : }
57 : :
58 : : static int __ns_get_path(struct path *path, struct ns_common *ns)
59 : : {
60 : : struct vfsmount *mnt = nsfs_mnt;
61 : : struct dentry *dentry;
62 : : struct inode *inode;
63 : : unsigned long d;
64 : :
65 : : rcu_read_lock();
66 : : d = atomic_long_read(&ns->stashed);
67 : : if (!d)
68 : : goto slow;
69 : : dentry = (struct dentry *)d;
70 : : if (!lockref_get_not_dead(&dentry->d_lockref))
71 : : goto slow;
72 : : rcu_read_unlock();
73 : : ns->ops->put(ns);
74 : : got_it:
75 : : path->mnt = mntget(mnt);
76 : : path->dentry = dentry;
77 : : return 0;
78 : : slow:
79 : : rcu_read_unlock();
80 : : inode = new_inode_pseudo(mnt->mnt_sb);
81 : : if (!inode) {
82 : : ns->ops->put(ns);
83 : : return -ENOMEM;
84 : : }
85 : : inode->i_ino = ns->inum;
86 : : inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
87 : : inode->i_flags |= S_IMMUTABLE;
88 : : inode->i_mode = S_IFREG | S_IRUGO;
89 : : inode->i_fop = &ns_file_operations;
90 : : inode->i_private = ns;
91 : :
92 : : dentry = d_alloc_anon(mnt->mnt_sb);
93 : : if (!dentry) {
94 : : iput(inode);
95 : : return -ENOMEM;
96 : : }
97 : : d_instantiate(dentry, inode);
98 : : dentry->d_fsdata = (void *)ns->ops;
99 : : d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry);
100 : : if (d) {
101 : : d_delete(dentry); /* make sure ->d_prune() does nothing */
102 : : dput(dentry);
103 : : cpu_relax();
104 : : return -EAGAIN;
105 : : }
106 : : goto got_it;
107 : : }
108 : :
109 : 0 : int ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
110 : : void *private_data)
111 : : {
112 : 0 : int ret;
113 : :
114 : 0 : do {
115 : 0 : struct ns_common *ns = ns_get_cb(private_data);
116 [ # # ]: 0 : if (!ns)
117 : : return -ENOENT;
118 : 0 : ret = __ns_get_path(path, ns);
119 [ # # ]: 0 : } while (ret == -EAGAIN);
120 : :
121 : : return ret;
122 : : }
123 : :
124 : : struct ns_get_path_task_args {
125 : : const struct proc_ns_operations *ns_ops;
126 : : struct task_struct *task;
127 : : };
128 : :
129 : 0 : static struct ns_common *ns_get_path_task(void *private_data)
130 : : {
131 : 0 : struct ns_get_path_task_args *args = private_data;
132 : :
133 : 0 : return args->ns_ops->get(args->task);
134 : : }
135 : :
136 : 0 : int ns_get_path(struct path *path, struct task_struct *task,
137 : : const struct proc_ns_operations *ns_ops)
138 : : {
139 : 0 : struct ns_get_path_task_args args = {
140 : : .ns_ops = ns_ops,
141 : : .task = task,
142 : : };
143 : :
144 : 0 : return ns_get_path_cb(path, ns_get_path_task, &args);
145 : : }
146 : :
147 : 0 : int open_related_ns(struct ns_common *ns,
148 : : struct ns_common *(*get_ns)(struct ns_common *ns))
149 : : {
150 : 0 : struct path path = {};
151 : 0 : struct file *f;
152 : 0 : int err;
153 : 0 : int fd;
154 : :
155 : 0 : fd = get_unused_fd_flags(O_CLOEXEC);
156 [ # # ]: 0 : if (fd < 0)
157 : : return fd;
158 : :
159 : 0 : do {
160 : 0 : struct ns_common *relative;
161 : :
162 : 0 : relative = get_ns(ns);
163 [ # # ]: 0 : if (IS_ERR(relative)) {
164 : 0 : put_unused_fd(fd);
165 : 0 : return PTR_ERR(relative);
166 : : }
167 : :
168 : 0 : err = __ns_get_path(&path, relative);
169 [ # # ]: 0 : } while (err == -EAGAIN);
170 : :
171 [ # # ]: 0 : if (err) {
172 : 0 : put_unused_fd(fd);
173 : 0 : return err;
174 : : }
175 : :
176 : 0 : f = dentry_open(&path, O_RDONLY, current_cred());
177 : 0 : path_put(&path);
178 [ # # ]: 0 : if (IS_ERR(f)) {
179 : 0 : put_unused_fd(fd);
180 : 0 : fd = PTR_ERR(f);
181 : : } else
182 : 0 : fd_install(fd, f);
183 : :
184 : : return fd;
185 : : }
186 : : EXPORT_SYMBOL_GPL(open_related_ns);
187 : :
188 : 0 : static long ns_ioctl(struct file *filp, unsigned int ioctl,
189 : : unsigned long arg)
190 : : {
191 : 0 : struct user_namespace *user_ns;
192 [ # # # # : 0 : struct ns_common *ns = get_proc_ns(file_inode(filp));
# ]
193 : 0 : uid_t __user *argp;
194 : 0 : uid_t uid;
195 : :
196 [ # # # # : 0 : switch (ioctl) {
# ]
197 : 0 : case NS_GET_USERNS:
198 : 0 : return open_related_ns(ns, ns_get_owner);
199 : 0 : case NS_GET_PARENT:
200 [ # # ]: 0 : if (!ns->ops->get_parent)
201 : : return -EINVAL;
202 : 0 : return open_related_ns(ns, ns->ops->get_parent);
203 : 0 : case NS_GET_NSTYPE:
204 : 0 : return ns->ops->type;
205 : 0 : case NS_GET_OWNER_UID:
206 [ # # ]: 0 : if (ns->ops->type != CLONE_NEWUSER)
207 : : return -EINVAL;
208 : 0 : user_ns = container_of(ns, struct user_namespace, ns);
209 : 0 : argp = (uid_t __user *) arg;
210 [ # # ]: 0 : uid = from_kuid_munged(current_user_ns(), user_ns->owner);
211 : 0 : return put_user(uid, argp);
212 : : default:
213 : : return -ENOTTY;
214 : : }
215 : : }
216 : :
217 : 0 : int ns_get_name(char *buf, size_t size, struct task_struct *task,
218 : : const struct proc_ns_operations *ns_ops)
219 : : {
220 : 0 : struct ns_common *ns;
221 : 0 : int res = -ENOENT;
222 : 0 : const char *name;
223 : 0 : ns = ns_ops->get(task);
224 [ # # ]: 0 : if (ns) {
225 [ # # ]: 0 : name = ns_ops->real_ns_name ? : ns_ops->name;
226 : 0 : res = snprintf(buf, size, "%s:[%u]", name, ns->inum);
227 : 0 : ns_ops->put(ns);
228 : : }
229 : 0 : return res;
230 : : }
231 : :
232 : 0 : struct file *proc_ns_fget(int fd)
233 : : {
234 : 0 : struct file *file;
235 : :
236 : 0 : file = fget(fd);
237 [ # # ]: 0 : if (!file)
238 : : return ERR_PTR(-EBADF);
239 : :
240 [ # # ]: 0 : if (file->f_op != &ns_file_operations)
241 : 0 : goto out_invalid;
242 : :
243 : : return file;
244 : :
245 : : out_invalid:
246 : 0 : fput(file);
247 : 0 : return ERR_PTR(-EINVAL);
248 : : }
249 : :
250 : 0 : static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
251 : : {
252 : 0 : struct inode *inode = d_inode(dentry);
253 : 0 : const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
254 : :
255 : 0 : seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
256 : 0 : return 0;
257 : : }
258 : :
259 : : static const struct super_operations nsfs_ops = {
260 : : .statfs = simple_statfs,
261 : : .evict_inode = nsfs_evict,
262 : : .show_path = nsfs_show_path,
263 : : };
264 : :
265 : 13 : static int nsfs_init_fs_context(struct fs_context *fc)
266 : : {
267 : 13 : struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
268 [ + - ]: 13 : if (!ctx)
269 : : return -ENOMEM;
270 : 13 : ctx->ops = &nsfs_ops;
271 : 13 : ctx->dops = &ns_dentry_operations;
272 : 13 : return 0;
273 : : }
274 : :
275 : : static struct file_system_type nsfs = {
276 : : .name = "nsfs",
277 : : .init_fs_context = nsfs_init_fs_context,
278 : : .kill_sb = kill_anon_super,
279 : : };
280 : :
281 : 13 : void __init nsfs_init(void)
282 : : {
283 : 13 : nsfs_mnt = kern_mount(&nsfs);
284 [ - + ]: 13 : if (IS_ERR(nsfs_mnt))
285 : 0 : panic("can't set nsfs up\n");
286 : 13 : nsfs_mnt->mnt_sb->s_flags &= ~SB_NOUSER;
287 : 13 : }
|