cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

proc_namespace.c (8324B)


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