xref: /openbmc/linux/fs/proc_namespace.c (revision 4f6cce39)
1 /*
2  * fs/proc_namespace.c - handling of /proc/<pid>/{mounts,mountinfo,mountstats}
3  *
4  * In fact, that's a piece of procfs; it's *almost* isolated from
5  * the rest of fs/proc, but has rather close relationships with
6  * fs/namespace.c, thus here instead of fs/proc
7  *
8  */
9 #include <linux/mnt_namespace.h>
10 #include <linux/nsproxy.h>
11 #include <linux/security.h>
12 #include <linux/fs_struct.h>
13 #include <linux/sched/task.h>
14 
15 #include "proc/internal.h" /* only for get_proc_task() in ->open() */
16 
17 #include "pnode.h"
18 #include "internal.h"
19 
20 static unsigned mounts_poll(struct file *file, poll_table *wait)
21 {
22 	struct seq_file *m = file->private_data;
23 	struct proc_mounts *p = m->private;
24 	struct mnt_namespace *ns = p->ns;
25 	unsigned res = POLLIN | POLLRDNORM;
26 	int event;
27 
28 	poll_wait(file, &p->ns->poll, wait);
29 
30 	event = ACCESS_ONCE(ns->event);
31 	if (m->poll_event != event) {
32 		m->poll_event = event;
33 		res |= POLLERR | POLLPRI;
34 	}
35 
36 	return res;
37 }
38 
39 struct proc_fs_info {
40 	int flag;
41 	const char *str;
42 };
43 
44 static int show_sb_opts(struct seq_file *m, struct super_block *sb)
45 {
46 	static const struct proc_fs_info fs_info[] = {
47 		{ MS_SYNCHRONOUS, ",sync" },
48 		{ MS_DIRSYNC, ",dirsync" },
49 		{ MS_MANDLOCK, ",mand" },
50 		{ MS_LAZYTIME, ",lazytime" },
51 		{ 0, NULL }
52 	};
53 	const struct proc_fs_info *fs_infop;
54 
55 	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
56 		if (sb->s_flags & fs_infop->flag)
57 			seq_puts(m, fs_infop->str);
58 	}
59 
60 	return security_sb_show_options(m, sb);
61 }
62 
63 static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
64 {
65 	static const struct proc_fs_info mnt_info[] = {
66 		{ MNT_NOSUID, ",nosuid" },
67 		{ MNT_NODEV, ",nodev" },
68 		{ MNT_NOEXEC, ",noexec" },
69 		{ MNT_NOATIME, ",noatime" },
70 		{ MNT_NODIRATIME, ",nodiratime" },
71 		{ MNT_RELATIME, ",relatime" },
72 		{ 0, NULL }
73 	};
74 	const struct proc_fs_info *fs_infop;
75 
76 	for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
77 		if (mnt->mnt_flags & fs_infop->flag)
78 			seq_puts(m, fs_infop->str);
79 	}
80 }
81 
82 static inline void mangle(struct seq_file *m, const char *s)
83 {
84 	seq_escape(m, s, " \t\n\\");
85 }
86 
87 static void show_type(struct seq_file *m, struct super_block *sb)
88 {
89 	mangle(m, sb->s_type->name);
90 	if (sb->s_subtype && sb->s_subtype[0]) {
91 		seq_putc(m, '.');
92 		mangle(m, sb->s_subtype);
93 	}
94 }
95 
96 static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
97 {
98 	struct proc_mounts *p = m->private;
99 	struct mount *r = real_mount(mnt);
100 	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
101 	struct super_block *sb = mnt_path.dentry->d_sb;
102 	int err;
103 
104 	if (sb->s_op->show_devname) {
105 		err = sb->s_op->show_devname(m, mnt_path.dentry);
106 		if (err)
107 			goto out;
108 	} else {
109 		mangle(m, r->mnt_devname ? r->mnt_devname : "none");
110 	}
111 	seq_putc(m, ' ');
112 	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
113 	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
114 	if (err)
115 		goto out;
116 	seq_putc(m, ' ');
117 	show_type(m, sb);
118 	seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw");
119 	err = show_sb_opts(m, sb);
120 	if (err)
121 		goto out;
122 	show_mnt_opts(m, mnt);
123 	if (sb->s_op->show_options)
124 		err = sb->s_op->show_options(m, mnt_path.dentry);
125 	seq_puts(m, " 0 0\n");
126 out:
127 	return err;
128 }
129 
130 static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
131 {
132 	struct proc_mounts *p = m->private;
133 	struct mount *r = real_mount(mnt);
134 	struct super_block *sb = mnt->mnt_sb;
135 	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
136 	int err;
137 
138 	seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
139 		   MAJOR(sb->s_dev), MINOR(sb->s_dev));
140 	if (sb->s_op->show_path) {
141 		err = sb->s_op->show_path(m, mnt->mnt_root);
142 		if (err)
143 			goto out;
144 	} else {
145 		seq_dentry(m, mnt->mnt_root, " \t\n\\");
146 	}
147 	seq_putc(m, ' ');
148 
149 	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
150 	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
151 	if (err)
152 		goto out;
153 
154 	seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
155 	show_mnt_opts(m, mnt);
156 
157 	/* Tagged fields ("foo:X" or "bar") */
158 	if (IS_MNT_SHARED(r))
159 		seq_printf(m, " shared:%i", r->mnt_group_id);
160 	if (IS_MNT_SLAVE(r)) {
161 		int master = r->mnt_master->mnt_group_id;
162 		int dom = get_dominating_id(r, &p->root);
163 		seq_printf(m, " master:%i", master);
164 		if (dom && dom != master)
165 			seq_printf(m, " propagate_from:%i", dom);
166 	}
167 	if (IS_MNT_UNBINDABLE(r))
168 		seq_puts(m, " unbindable");
169 
170 	/* Filesystem specific data */
171 	seq_puts(m, " - ");
172 	show_type(m, sb);
173 	seq_putc(m, ' ');
174 	if (sb->s_op->show_devname) {
175 		err = sb->s_op->show_devname(m, mnt->mnt_root);
176 		if (err)
177 			goto out;
178 	} else {
179 		mangle(m, r->mnt_devname ? r->mnt_devname : "none");
180 	}
181 	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
182 	err = show_sb_opts(m, sb);
183 	if (err)
184 		goto out;
185 	if (sb->s_op->show_options)
186 		err = sb->s_op->show_options(m, mnt->mnt_root);
187 	seq_putc(m, '\n');
188 out:
189 	return err;
190 }
191 
192 static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
193 {
194 	struct proc_mounts *p = m->private;
195 	struct mount *r = real_mount(mnt);
196 	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
197 	struct super_block *sb = mnt_path.dentry->d_sb;
198 	int err;
199 
200 	/* device */
201 	if (sb->s_op->show_devname) {
202 		seq_puts(m, "device ");
203 		err = sb->s_op->show_devname(m, mnt_path.dentry);
204 		if (err)
205 			goto out;
206 	} else {
207 		if (r->mnt_devname) {
208 			seq_puts(m, "device ");
209 			mangle(m, r->mnt_devname);
210 		} else
211 			seq_puts(m, "no device");
212 	}
213 
214 	/* mount point */
215 	seq_puts(m, " mounted on ");
216 	/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
217 	err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\");
218 	if (err)
219 		goto out;
220 	seq_putc(m, ' ');
221 
222 	/* file system type */
223 	seq_puts(m, "with fstype ");
224 	show_type(m, sb);
225 
226 	/* optional statistics */
227 	if (sb->s_op->show_stats) {
228 		seq_putc(m, ' ');
229 		err = sb->s_op->show_stats(m, mnt_path.dentry);
230 	}
231 
232 	seq_putc(m, '\n');
233 out:
234 	return err;
235 }
236 
237 static int mounts_open_common(struct inode *inode, struct file *file,
238 			      int (*show)(struct seq_file *, struct vfsmount *))
239 {
240 	struct task_struct *task = get_proc_task(inode);
241 	struct nsproxy *nsp;
242 	struct mnt_namespace *ns = NULL;
243 	struct path root;
244 	struct proc_mounts *p;
245 	struct seq_file *m;
246 	int ret = -EINVAL;
247 
248 	if (!task)
249 		goto err;
250 
251 	task_lock(task);
252 	nsp = task->nsproxy;
253 	if (!nsp || !nsp->mnt_ns) {
254 		task_unlock(task);
255 		put_task_struct(task);
256 		goto err;
257 	}
258 	ns = nsp->mnt_ns;
259 	get_mnt_ns(ns);
260 	if (!task->fs) {
261 		task_unlock(task);
262 		put_task_struct(task);
263 		ret = -ENOENT;
264 		goto err_put_ns;
265 	}
266 	get_fs_root(task->fs, &root);
267 	task_unlock(task);
268 	put_task_struct(task);
269 
270 	ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts));
271 	if (ret)
272 		goto err_put_path;
273 
274 	m = file->private_data;
275 	m->poll_event = ns->event;
276 
277 	p = m->private;
278 	p->ns = ns;
279 	p->root = root;
280 	p->show = show;
281 	p->cached_event = ~0ULL;
282 
283 	return 0;
284 
285  err_put_path:
286 	path_put(&root);
287  err_put_ns:
288 	put_mnt_ns(ns);
289  err:
290 	return ret;
291 }
292 
293 static int mounts_release(struct inode *inode, struct file *file)
294 {
295 	struct seq_file *m = file->private_data;
296 	struct proc_mounts *p = m->private;
297 	path_put(&p->root);
298 	put_mnt_ns(p->ns);
299 	return seq_release_private(inode, file);
300 }
301 
302 static int mounts_open(struct inode *inode, struct file *file)
303 {
304 	return mounts_open_common(inode, file, show_vfsmnt);
305 }
306 
307 static int mountinfo_open(struct inode *inode, struct file *file)
308 {
309 	return mounts_open_common(inode, file, show_mountinfo);
310 }
311 
312 static int mountstats_open(struct inode *inode, struct file *file)
313 {
314 	return mounts_open_common(inode, file, show_vfsstat);
315 }
316 
317 const struct file_operations proc_mounts_operations = {
318 	.open		= mounts_open,
319 	.read		= seq_read,
320 	.llseek		= seq_lseek,
321 	.release	= mounts_release,
322 	.poll		= mounts_poll,
323 };
324 
325 const struct file_operations proc_mountinfo_operations = {
326 	.open		= mountinfo_open,
327 	.read		= seq_read,
328 	.llseek		= seq_lseek,
329 	.release	= mounts_release,
330 	.poll		= mounts_poll,
331 };
332 
333 const struct file_operations proc_mountstats_operations = {
334 	.open		= mountstats_open,
335 	.read		= seq_read,
336 	.llseek		= seq_lseek,
337 	.release	= mounts_release,
338 };
339