Commit 6814ef2d authored by Alexey Gladkov's avatar Alexey Gladkov Committed by Eric W. Biederman
Browse files

proc: add option to mount only a pids subset



This allows to hide all files and directories in the procfs that are not
related to tasks.

Signed-off-by: default avatarAlexey Gladkov <gladkov.alexey@gmail.com>
Reviewed-by: default avatarAlexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: default avatarKees Cook <keescook@chromium.org>
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
parent 24a71ce5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -269,6 +269,11 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
		unsigned int flags)
{
	struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb);

	if (fs_info->pidonly == PROC_PIDONLY_ON)
		return ERR_PTR(-ENOENT);

	return proc_lookup_de(dir, dentry, PDE(dir));
}

@@ -325,6 +330,10 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
int proc_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *inode = file_inode(file);
	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);

	if (fs_info->pidonly == PROC_PIDONLY_ON)
		return 1;

	return proc_readdir_de(file, ctx, PDE(inode));
}
+6 −0
Original line number Diff line number Diff line
@@ -173,6 +173,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
	if (fs_info->hide_pid != HIDEPID_OFF)
		seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
	if (fs_info->pidonly != PROC_PIDONLY_OFF)
		seq_printf(seq, ",subset=pid");

	return 0;
}
@@ -463,6 +465,7 @@ proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,

static int proc_reg_open(struct inode *inode, struct file *file)
{
	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
	struct proc_dir_entry *pde = PDE(inode);
	int rv = 0;
	typeof_member(struct proc_ops, proc_open) open;
@@ -476,6 +479,9 @@ static int proc_reg_open(struct inode *inode, struct file *file)
		return rv;
	}

	if (fs_info->pidonly == PROC_PIDONLY_ON)
		return -ENOENT;

	/*
	 * Ensure that
	 * 1) PDE's ->release hook will be called no matter what
+33 −0
Original line number Diff line number Diff line
@@ -34,16 +34,19 @@ struct proc_fs_context {
	unsigned int		mask;
	int			hidepid;
	int			gid;
	int			pidonly;
};

enum proc_param {
	Opt_gid,
	Opt_hidepid,
	Opt_subset,
};

static const struct fs_parameter_spec proc_fs_parameters[] = {
	fsparam_u32("gid",	Opt_gid),
	fsparam_u32("hidepid",	Opt_hidepid),
	fsparam_string("subset",	Opt_subset),
	{}
};

@@ -55,6 +58,29 @@ static inline int valid_hidepid(unsigned int value)
		value == HIDEPID_NOT_PTRACEABLE);
}

static int proc_parse_subset_param(struct fs_context *fc, char *value)
{
	struct proc_fs_context *ctx = fc->fs_private;

	while (value) {
		char *ptr = strchr(value, ',');

		if (ptr != NULL)
			*ptr++ = '\0';

		if (*value != '\0') {
			if (!strcmp(value, "pid")) {
				ctx->pidonly = PROC_PIDONLY_ON;
			} else {
				return invalf(fc, "proc: unsupported subset option - %s\n", value);
			}
		}
		value = ptr;
	}

	return 0;
}

static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
	struct proc_fs_context *ctx = fc->fs_private;
@@ -76,6 +102,11 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
		ctx->hidepid = result.uint_32;
		break;

	case Opt_subset:
		if (proc_parse_subset_param(fc, param->string) < 0)
			return -EINVAL;
		break;

	default:
		return -EINVAL;
	}
@@ -94,6 +125,8 @@ static void proc_apply_options(struct proc_fs_info *fs_info,
		fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
	if (ctx->mask & (1 << Opt_hidepid))
		fs_info->hide_pid = ctx->hidepid;
	if (ctx->mask & (1 << Opt_subset))
		fs_info->pidonly = ctx->pidonly;
}

static int proc_fill_super(struct super_block *s, struct fs_context *fc)
+7 −0
Original line number Diff line number Diff line
@@ -50,12 +50,19 @@ enum {
	HIDEPID_NOT_PTRACEABLE = 4, /* Limit pids to only ptraceable pids */
};

/* definitions for proc mount option pidonly */
enum {
	PROC_PIDONLY_OFF = 0,
	PROC_PIDONLY_ON  = 1,
};

struct proc_fs_info {
	struct pid_namespace *pid_ns;
	struct dentry *proc_self;        /* For /proc/self */
	struct dentry *proc_thread_self; /* For /proc/thread-self */
	kgid_t pid_gid;
	int hide_pid;
	int pidonly;
};

static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)