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

namespaces.c (4323B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <linux/proc_fs.h>
      3#include <linux/nsproxy.h>
      4#include <linux/ptrace.h>
      5#include <linux/namei.h>
      6#include <linux/file.h>
      7#include <linux/utsname.h>
      8#include <net/net_namespace.h>
      9#include <linux/ipc_namespace.h>
     10#include <linux/pid_namespace.h>
     11#include <linux/user_namespace.h>
     12#include "internal.h"
     13
     14
     15static const struct proc_ns_operations *ns_entries[] = {
     16#ifdef CONFIG_NET_NS
     17	&netns_operations,
     18#endif
     19#ifdef CONFIG_UTS_NS
     20	&utsns_operations,
     21#endif
     22#ifdef CONFIG_IPC_NS
     23	&ipcns_operations,
     24#endif
     25#ifdef CONFIG_PID_NS
     26	&pidns_operations,
     27	&pidns_for_children_operations,
     28#endif
     29#ifdef CONFIG_USER_NS
     30	&userns_operations,
     31#endif
     32	&mntns_operations,
     33#ifdef CONFIG_CGROUPS
     34	&cgroupns_operations,
     35#endif
     36#ifdef CONFIG_TIME_NS
     37	&timens_operations,
     38	&timens_for_children_operations,
     39#endif
     40};
     41
     42static const char *proc_ns_get_link(struct dentry *dentry,
     43				    struct inode *inode,
     44				    struct delayed_call *done)
     45{
     46	const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
     47	struct task_struct *task;
     48	struct path ns_path;
     49	int error = -EACCES;
     50
     51	if (!dentry)
     52		return ERR_PTR(-ECHILD);
     53
     54	task = get_proc_task(inode);
     55	if (!task)
     56		return ERR_PTR(-EACCES);
     57
     58	if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
     59		goto out;
     60
     61	error = ns_get_path(&ns_path, task, ns_ops);
     62	if (error)
     63		goto out;
     64
     65	error = nd_jump_link(&ns_path);
     66out:
     67	put_task_struct(task);
     68	return ERR_PTR(error);
     69}
     70
     71static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen)
     72{
     73	struct inode *inode = d_inode(dentry);
     74	const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
     75	struct task_struct *task;
     76	char name[50];
     77	int res = -EACCES;
     78
     79	task = get_proc_task(inode);
     80	if (!task)
     81		return res;
     82
     83	if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
     84		res = ns_get_name(name, sizeof(name), task, ns_ops);
     85		if (res >= 0)
     86			res = readlink_copy(buffer, buflen, name);
     87	}
     88	put_task_struct(task);
     89	return res;
     90}
     91
     92static const struct inode_operations proc_ns_link_inode_operations = {
     93	.readlink	= proc_ns_readlink,
     94	.get_link	= proc_ns_get_link,
     95	.setattr	= proc_setattr,
     96};
     97
     98static struct dentry *proc_ns_instantiate(struct dentry *dentry,
     99	struct task_struct *task, const void *ptr)
    100{
    101	const struct proc_ns_operations *ns_ops = ptr;
    102	struct inode *inode;
    103	struct proc_inode *ei;
    104
    105	inode = proc_pid_make_inode(dentry->d_sb, task, S_IFLNK | S_IRWXUGO);
    106	if (!inode)
    107		return ERR_PTR(-ENOENT);
    108
    109	ei = PROC_I(inode);
    110	inode->i_op = &proc_ns_link_inode_operations;
    111	ei->ns_ops = ns_ops;
    112	pid_update_inode(task, inode);
    113
    114	d_set_d_op(dentry, &pid_dentry_operations);
    115	return d_splice_alias(inode, dentry);
    116}
    117
    118static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx)
    119{
    120	struct task_struct *task = get_proc_task(file_inode(file));
    121	const struct proc_ns_operations **entry, **last;
    122
    123	if (!task)
    124		return -ENOENT;
    125
    126	if (!dir_emit_dots(file, ctx))
    127		goto out;
    128	if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries))
    129		goto out;
    130	entry = ns_entries + (ctx->pos - 2);
    131	last = &ns_entries[ARRAY_SIZE(ns_entries) - 1];
    132	while (entry <= last) {
    133		const struct proc_ns_operations *ops = *entry;
    134		if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name),
    135				     proc_ns_instantiate, task, ops))
    136			break;
    137		ctx->pos++;
    138		entry++;
    139	}
    140out:
    141	put_task_struct(task);
    142	return 0;
    143}
    144
    145const struct file_operations proc_ns_dir_operations = {
    146	.read		= generic_read_dir,
    147	.iterate_shared	= proc_ns_dir_readdir,
    148	.llseek		= generic_file_llseek,
    149};
    150
    151static struct dentry *proc_ns_dir_lookup(struct inode *dir,
    152				struct dentry *dentry, unsigned int flags)
    153{
    154	struct task_struct *task = get_proc_task(dir);
    155	const struct proc_ns_operations **entry, **last;
    156	unsigned int len = dentry->d_name.len;
    157	struct dentry *res = ERR_PTR(-ENOENT);
    158
    159	if (!task)
    160		goto out_no_task;
    161
    162	last = &ns_entries[ARRAY_SIZE(ns_entries)];
    163	for (entry = ns_entries; entry < last; entry++) {
    164		if (strlen((*entry)->name) != len)
    165			continue;
    166		if (!memcmp(dentry->d_name.name, (*entry)->name, len))
    167			break;
    168	}
    169	if (entry == last)
    170		goto out;
    171
    172	res = proc_ns_instantiate(dentry, task, *entry);
    173out:
    174	put_task_struct(task);
    175out_no_task:
    176	return res;
    177}
    178
    179const struct inode_operations proc_ns_dir_inode_operations = {
    180	.lookup		= proc_ns_dir_lookup,
    181	.getattr	= pid_getattr,
    182	.setattr	= proc_setattr,
    183};