diff options
Diffstat (limited to 'fs/proc/root.c')
| -rw-r--r-- | fs/proc/root.c | 78 | 
1 files changed, 71 insertions, 7 deletions
diff --git a/fs/proc/root.c b/fs/proc/root.c index 9a8a2b77b874..46a15d8a29ca 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -18,6 +18,7 @@  #include <linux/bitops.h>  #include <linux/mount.h>  #include <linux/pid_namespace.h> +#include <linux/parser.h>  #include "internal.h" @@ -36,6 +37,63 @@ static int proc_set_super(struct super_block *sb, void *data)  	return err;  } +enum { +	Opt_gid, Opt_hidepid, Opt_err, +}; + +static const match_table_t tokens = { +	{Opt_hidepid, "hidepid=%u"}, +	{Opt_gid, "gid=%u"}, +	{Opt_err, NULL}, +}; + +static int proc_parse_options(char *options, struct pid_namespace *pid) +{ +	char *p; +	substring_t args[MAX_OPT_ARGS]; +	int option; + +	if (!options) +		return 1; + +	while ((p = strsep(&options, ",")) != NULL) { +		int token; +		if (!*p) +			continue; + +		args[0].to = args[0].from = 0; +		token = match_token(p, tokens, args); +		switch (token) { +		case Opt_gid: +			if (match_int(&args[0], &option)) +				return 0; +			pid->pid_gid = option; +			break; +		case Opt_hidepid: +			if (match_int(&args[0], &option)) +				return 0; +			if (option < 0 || option > 2) { +				pr_err("proc: hidepid value must be between 0 and 2.\n"); +				return 0; +			} +			pid->hide_pid = option; +			break; +		default: +			pr_err("proc: unrecognized mount option \"%s\" " +			       "or missing value\n", p); +			return 0; +		} +	} + +	return 1; +} + +int proc_remount(struct super_block *sb, int *flags, char *data) +{ +	struct pid_namespace *pid = sb->s_fs_info; +	return !proc_parse_options(data, pid); +} +  static struct dentry *proc_mount(struct file_system_type *fs_type,  	int flags, const char *dev_name, void *data)  { @@ -43,11 +101,15 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,  	struct super_block *sb;  	struct pid_namespace *ns;  	struct proc_inode *ei; +	char *options; -	if (flags & MS_KERNMOUNT) +	if (flags & MS_KERNMOUNT) {  		ns = (struct pid_namespace *)data; -	else +		options = NULL; +	} else {  		ns = current->nsproxy->pid_ns; +		options = data; +	}  	sb = sget(fs_type, proc_test_super, proc_set_super, ns);  	if (IS_ERR(sb)) @@ -55,6 +117,10 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,  	if (!sb->s_root) {  		sb->s_flags = flags; +		if (!proc_parse_options(options, ns)) { +			deactivate_locked_super(sb); +			return ERR_PTR(-EINVAL); +		}  		err = proc_fill_super(sb);  		if (err) {  			deactivate_locked_super(sb); @@ -91,20 +157,18 @@ static struct file_system_type proc_fs_type = {  void __init proc_root_init(void)  { -	struct vfsmount *mnt;  	int err;  	proc_init_inodecache();  	err = register_filesystem(&proc_fs_type);  	if (err)  		return; -	mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); -	if (IS_ERR(mnt)) { +	err = pid_ns_prepare_proc(&init_pid_ns); +	if (err) {  		unregister_filesystem(&proc_fs_type);  		return;  	} -	init_pid_ns.proc_mnt = mnt;  	proc_symlink("mounts", NULL, "self/mounts");  	proc_net_init(); @@ -209,5 +273,5 @@ int pid_ns_prepare_proc(struct pid_namespace *ns)  void pid_ns_release_proc(struct pid_namespace *ns)  { -	mntput(ns->proc_mnt); +	kern_unmount(ns->proc_mnt);  }  | 
