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