lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 9 May 2022 12:41:54 +0200
From:   Christian Brauner <brauner@...nel.org>
To:     zhanglin <zhang.lin16@....com.cn>
Cc:     linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
        akpm@...ux-foundation.org, keescook@...omium.org,
        adobriyan@...il.com, sfr@...b.auug.org.au,
        zhengqi.arch@...edance.com, ebiederm@...ssion.com,
        kaleshsingh@...gle.com, stephen.s.brennan@...cle.com,
        ohoono.kwon@...sung.com, haolee.swjtu@...il.com,
        fweimer@...hat.com, xue.zhihong@....com.cn, wang.yi59@....com.cn,
        jiang.xuexin@....com.cn, zealci@....com.cn
Subject: Re: [PATCH] fs/proc: add mask_secrets to prevent sensitive
 information leakage.

On Mon, May 09, 2022 at 01:46:13PM +0800, zhanglin wrote:
> There are about 17000+ packages exists on centos. After investigation on
> 10000+ pacakges, About 200+ commands support passing plain(or encrypted)
> passwords through command line arguments. Those sensitive information are
> exposed through a global readable interface: /proc/$pid/cmdline.
> 
> To prevent the leakcage, adding mask_secrets procfs entry will hook the
> get_mm_cmdline()'s output and mask sensitive fields in /proc/$pid/cmdline
> using repeating 'Z's.
> 
> Signed-off-by: zhanglin <zhang.lin16@....com.cn>
> ---

Hey zhanglin, thanks for the patch but I think that's a NAK.

* Applications that worry about this should use other means of passing
  sensitive information and there are a multitude of ways of doing so.
* This is a huge amount of (fragile looking) code to get this working.
* Introducing a special secret --password= seems hacky and a bad
  precedent for more --ARG= patches following this. The kernel should
  care about such calling conventions.
* It seems that this has potential to introduce conflicts and or
  regression for tools that make use of a --password command line switch
  in creative ways.
* Tools that currently pass passwords via the command line need to
  switch their argument passing to --password=. But if they do that they
  might as well just rework their secret passing to not pass them on the
  command line or introduce a safe way to do so.

IOW, this is all solvable in userspace without the kernel to learn about
--password and growing a huge amount of code to do so. Bad userspace
practice may but in general shouldn't require the kernel to make up for it.

>  fs/proc/Kconfig        |  20 ++
>  fs/proc/Makefile       |   1 +
>  fs/proc/base.c         |  10 +
>  fs/proc/mask_secrets.c | 593 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 624 insertions(+)
>  create mode 100644 fs/proc/mask_secrets.c
> 
> diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
> index c93000105..3e5ce7162 100644
> --- a/fs/proc/Kconfig
> +++ b/fs/proc/Kconfig
> @@ -107,3 +107,23 @@ config PROC_PID_ARCH_STATUS
>  config PROC_CPU_RESCTRL
>  	def_bool n
>  	depends on PROC_FS
> +
> +config PROC_MASK_SECRETS
> +	bool "mask secret fields in process cmdline"
> +	default n
> +	help
> +	  mask secret fields in process cmdline to prevent sensitive information
> +	  leakage. Enable this feature, credentials including username, passwords
> +	  will be masked with repeating 'Z'. "ZZZZZZ..." but no real sensitive
> +	  information will appear in /proc/$pid/cmdline. for example: useradd -rp
> +	  ZZZZZZ will appear in /proc/$pid/cmdline instead iif you run 'echo 1 >
> +	  /proc/mask_secrets/enabled && echo "+/usr/sbin/useradd:-p:--password" >
> +	  /proc/mask_secrets/cmdtab'.
> +
> +	  Say Y if you want to enable this feature.
> +	  Enable/Disable: echo 1/0 > /proc/mask_secrets/enabled.
> +	  Add masking rules: echo '+${command}:--${secret_opt1}:-${secret_opt2}:...
> +	  ' > /proc/mask_secrets/cmdtab.
> +	  Remove masking rules: echo '-${command}' > /proc/mask_secrets/cmdtab.
> +	  Commands must be well written in absolute path form.
> +
> diff --git a/fs/proc/Makefile b/fs/proc/Makefile
> index bd08616ed..06521b7ff 100644
> --- a/fs/proc/Makefile
> +++ b/fs/proc/Makefile
> @@ -34,3 +34,4 @@ proc-$(CONFIG_PROC_VMCORE)	+= vmcore.o
>  proc-$(CONFIG_PRINTK)	+= kmsg.o
>  proc-$(CONFIG_PROC_PAGE_MONITOR)	+= page.o
>  proc-$(CONFIG_BOOT_CONFIG)	+= bootconfig.o
> +proc-$(CONFIG_PROC_MASK_SECRETS)	+= mask_secrets.o
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index d89526cfe..9fe0de79a 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -103,6 +103,10 @@
>  
>  #include "../../lib/kstrtox.h"
>  
> +#ifdef CONFIG_PROC_MASK_SECRETS
> +extern size_t mask_secrets(struct mm_struct *mm, char __user *buf, size_t count, loff_t pos);
> +#endif
> +
>  /* NOTE:
>   *	Implementing inode permission operations in /proc is almost
>   *	certainly an error.  Permission checks need to happen during
> @@ -312,6 +316,12 @@ static ssize_t get_mm_cmdline(struct mm_struct *mm, char __user *buf,
>  	if (count > arg_end - pos)
>  		count = arg_end - pos;
>  
> +#ifdef CONFIG_PROC_MASK_SECRETS
> +	len = mask_secrets(mm, buf, count, pos);
> +	if (len > 0)
> +		return len;
> +#endif
> +
>  	page = (char *)__get_free_page(GFP_KERNEL);
>  	if (!page)
>  		return -ENOMEM;
> diff --git a/fs/proc/mask_secrets.c b/fs/proc/mask_secrets.c
> new file mode 100644
> index 000000000..035230d1e
> --- /dev/null
> +++ b/fs/proc/mask_secrets.c
> @@ -0,0 +1,593 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + *  linux/fs/proc/mask_secrets.c
> + *
> + *  Copyright (C) 2022, 2022 zhanglin
> + *
> + *  /proc/mask_secrets directory handling functions
> + */
> +
> +#include <linux/ctype.h>
> +#include <linux/fs.h>
> +#include <linux/init.h>
> +#include <linux/hashtable.h>
> +#include <linux/mm.h>
> +#include <linux/proc_fs.h>
> +#include <linux/seq_file.h>
> +#include <linux/slab.h>
> +
> +#define CMDLINE_HASHTABSIZE	1024
> +#define cmdline_hash(x)		((x) % CMDLINE_HASHTABSIZE)
> +
> +static const char *SECRET_SEPARATOR = ":";
> +static const int MASK_SECRETS_ENABLED = 1;
> +static const int MASK_SECRETS_DISABLED;
> +static DEFINE_SPINLOCK(mask_secrets_enabled_spinlock);
> +static int __rcu *mask_secrets_enabled __read_mostly = (int *)&MASK_SECRETS_DISABLED;
> +static DEFINE_SPINLOCK(cmdline_hashtab_spinlock);
> +static struct hlist_head __rcu cmdline_hashtab[CMDLINE_HASHTABSIZE] __read_mostly = {
> +	[0 ... (CMDLINE_HASHTABSIZE-1)] = HLIST_HEAD_INIT };
> +static struct kmem_cache *cmdline_hashtab_item_cachep;
> +
> +struct cmdline_hashtab_item {
> +	struct hlist_node hlist;
> +	char *cmdline;
> +	char *progname;
> +	char *secrets;
> +};
> +
> +static int is_mask_secrets_enabled(void)
> +{
> +	int ret = 0;
> +
> +	rcu_read_lock();
> +	ret = *(rcu_dereference(mask_secrets_enabled));
> +	rcu_read_unlock();
> +	return ret;
> +}
> +
> +size_t mask_secrets(struct mm_struct *mm, char __user *buf,
> +			      size_t count, loff_t pos)
> +{
> +	unsigned long arg_start = 0;
> +	unsigned long arg_end = 0;
> +	int mask_arg_len = 0;
> +	size_t remote_vm_copied = 0;
> +	struct file *file = 0;
> +	struct inode *inode = 0;
> +	char *kbuf = 0;
> +	char *progname = 0;
> +	int proghash = -1;
> +	int prog_found = 0;
> +	char *mask_arg_start = 0;
> +	char *mask_arg_end = 0;
> +	struct cmdline_hashtab_item *chi = 0;
> +	char *psecret = 0;
> +	size_t psecret_len = 0;
> +	char *pmask = 0;
> +	size_t pmask_len = 0;
> +	size_t size;
> +	size_t total_copied = 0;
> +	int err = 0;
> +
> +	if (!is_mask_secrets_enabled()) {
> +		err = -EPERM;
> +		goto exit_err;
> +	}
> +
> +	spin_lock(&mm->arg_lock);
> +	arg_start = mm->arg_start;
> +	arg_end = mm->arg_end;
> +	spin_unlock(&mm->arg_lock);
> +	if (arg_start >= arg_end) {
> +		err = -ERANGE;
> +		goto exit_err;
> +	}
> +	mask_arg_len = arg_end - arg_start + 1;
> +
> +	file = get_mm_exe_file(mm);
> +	if (!file) {
> +		err = -ENOENT;
> +		goto exit_err;
> +	}
> +	inode = file_inode(file);
> +	if (!inode) {
> +		err = -ENOENT;
> +		goto exit_err;
> +	}
> +	proghash = cmdline_hash(inode->i_ino);
> +	kbuf = kzalloc(max(PATH_MAX, mask_arg_len), GFP_KERNEL);
> +	if (!kbuf) {
> +		err = -ENOMEM;
> +		goto exit_err;
> +	}
> +	progname = d_path(&file->f_path, kbuf, PATH_MAX);
> +	if (IS_ERR_OR_NULL(progname)) {
> +		err = -ENOENT;
> +		goto cleanup_kbuf;
> +	}
> +
> +	rcu_read_lock();
> +	prog_found = 0;
> +	hash_for_each_possible_rcu(cmdline_hashtab, chi, hlist, proghash)
> +		if (strcmp(chi->progname, progname) == 0) {
> +			prog_found = 1;
> +			break;
> +		}
> +
> +	if (!prog_found) {
> +		rcu_read_unlock();
> +		goto cleanup_kbuf;
> +	}
> +
> +	mask_arg_start = kbuf;
> +	mask_arg_end = mask_arg_start + (arg_end - arg_start);
> +	remote_vm_copied = access_remote_vm(mm, arg_start, mask_arg_start, mask_arg_len, FOLL_ANON);

While I'm not a core mm person and don't feel able to review this it all
seems very dodgy to me.

> +	if (remote_vm_copied <= 0) {
> +		rcu_read_unlock();
> +		err = -EIO;
> +		goto cleanup_kbuf;
> +	}
> +	/*skip progname */
> +	for (pmask = mask_arg_start; *pmask && (pmask <= mask_arg_end); pmask++)
> +		;
> +
> +	if (!chi->secrets) {
> +		rcu_read_unlock();
> +		/*mask everything, such as: xxxconnect host port username password.*/
> +		for (pmask = pmask + 1; (pmask <= mask_arg_end); pmask++)
> +			for (; (pmask <= mask_arg_end) && (*pmask); pmask++)
> +				*pmask = 'Z';
> +		goto copydata;
> +	}
> +
> +	for (pmask = pmask + 1; pmask <= mask_arg_end; pmask++) {
> +		psecret = chi->secrets;
> +		while (*psecret) {
> +			psecret_len = strlen(psecret);
> +			if (psecret_len < 2) {
> +				rcu_read_unlock();
> +				err = -EINVAL;
> +				goto cleanup_kbuf;
> +			}
> +
> +			if (strcmp(pmask, psecret) == 0) {
> +				pmask += psecret_len + 1;
> +				goto mask_secret;
> +			}
> +
> +			if (strncmp(pmask, psecret, psecret_len) == 0) {
> +				/*handle case: --password=xxxx */
> +				if ((psecret[0] == '-') && (psecret[1] == '-'))
> +					if (pmask[psecret_len] == '=') {
> +						pmask += psecret_len + 1;
> +						goto mask_secret;
> +					}
> +
> +				if (psecret[0] == '-') {
> +					/*handle case: -password=xxxx or -p=xxxx*/
> +					if (pmask[psecret_len] == '=') {
> +						pmask += psecret_len + 1;
> +						goto mask_secret;
> +					}
> +
> +					/*handle case: -pxxxx*/
> +					if (psecret_len == 2) {
> +						pmask += psecret_len;
> +						goto mask_secret;
> +					}
> +				}
> +			}
> +
> +			if (psecret_len == 2) {
> +				pmask_len = strlen(pmask);
> +				/*handle case: -yp xxxx, such as: useradd -rp xxxx*/
> +				if ((pmask_len > 2) && (*pmask == '-')
> +				      && (pmask[pmask_len - 1] == psecret[1])) {
> +					pmask += pmask_len + 1;
> +					goto mask_secret;
> +				}
> +			}
> +
> +			psecret += psecret_len + 1;
> +		}
> +
> +		pmask += strlen(pmask);
> +		continue;
> +
> +mask_secret:
> +		for (; (pmask <= mask_arg_end) && (*pmask); pmask++)
> +			*pmask = 'Z';
> +	}
> +	rcu_read_unlock();
> +
> +copydata:
> +	size = arg_end - pos;
> +	size = min_t(size_t, size, count);
> +	if (copy_to_user(buf, mask_arg_start + pos - arg_start, size))
> +		goto cleanup_kbuf;
> +
> +	total_copied = size;
> +
> +cleanup_kbuf:
> +	kfree(kbuf);
> +
> +exit_err:
> +	return total_copied;
> +}
> +
> +static int show_mask_secrets_enabled(struct seq_file *m, void *v)
> +{
> +	rcu_read_lock();
> +	seq_printf(m, "%d\n", *(rcu_dereference(mask_secrets_enabled)));
> +	rcu_read_unlock();
> +
> +	return 0;
> +}
> +
> +static int open_mask_secrets_enabled(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, show_mask_secrets_enabled, NULL);
> +}
> +
> +static ssize_t write_mask_secrets_enabled(struct file *file, const char __user *buf,
> +				   size_t count, loff_t *ppos)
> +{
> +	int val, old_val;
> +	int err = kstrtoint_from_user(buf, count, 0, &val);
> +
> +	if (err)
> +		return err;
> +
> +	if ((val != 0) && (val != 1))
> +		return -EINVAL;
> +
> +	rcu_read_lock();
> +	old_val = *(rcu_dereference(mask_secrets_enabled));
> +	rcu_read_unlock();
> +
> +	if (val == old_val)
> +		return count;
> +	spin_lock(&mask_secrets_enabled_spinlock);
> +	rcu_assign_pointer(mask_secrets_enabled,
> +		       val ? &MASK_SECRETS_ENABLED : &MASK_SECRETS_DISABLED);
> +	spin_unlock(&mask_secrets_enabled_spinlock);
> +	synchronize_rcu();
> +
> +	return count;
> +}
> +
> +static const struct proc_ops mask_secrets_enabled_proc_ops = {
> +	.proc_open	= open_mask_secrets_enabled,
> +	.proc_read	= seq_read,
> +	.proc_write	= write_mask_secrets_enabled,
> +	.proc_lseek	= seq_lseek,
> +	.proc_release	= single_release,
> +};
> +
> +
> +static int show_mask_secrets_cmdtab(struct seq_file *m, void *v)
> +{
> +	struct cmdline_hashtab_item *chi = 0;
> +	char *secret;
> +	int proghash = 0;
> +	int err = 0;
> +
> +	if (!is_mask_secrets_enabled()) {
> +		err = -EPERM;
> +		return err;
> +	}
> +
> +	rcu_read_lock();
> +	hash_for_each_rcu(cmdline_hashtab, proghash, chi, hlist) {
> +		seq_printf(m, "[%04d]: %s", proghash, chi->progname);
> +		if (chi->secrets) {
> +			secret = chi->secrets;
> +			while (*secret) {
> +				seq_printf(m, ":%s", secret);
> +				secret += strlen(secret) + 1;
> +			}
> +		}
> +		seq_puts(m, "\n");
> +	}
> +	rcu_read_unlock();
> +
> +	return err;
> +}
> +
> +static int open_mask_secrets_cmdtab(struct inode *inode, struct file *file)
> +{
> +	return single_open(file, show_mask_secrets_cmdtab, NULL);
> +}
> +
> +static size_t serialize_cmdtab(char *buf)
> +{
> +	struct cmdline_hashtab_item *chi = 0;
> +	size_t secrets_prefix_len = strlen("[xxxx]: ");
> +	size_t secrets_cmdtab_len = 0;
> +	char *secret = 0;
> +	size_t secret_len = 0;
> +	int proghash = 0;
> +
> +	rcu_read_lock();
> +	secrets_cmdtab_len = 0;
> +	hash_for_each_rcu(cmdline_hashtab, proghash, chi, hlist) {
> +		if (buf)
> +			sprintf(buf + secrets_cmdtab_len, "[%04d]: %s", proghash, chi->progname);
> +		secrets_cmdtab_len += secrets_prefix_len + strlen(chi->progname);
> +		if (chi->secrets) {
> +			secret = chi->secrets;
> +			while (*secret) {
> +				if (buf)
> +					sprintf(buf + secrets_cmdtab_len, ":%s", secret);
> +				secret_len = strlen(secret);
> +				secret += secret_len + 1;
> +				secrets_cmdtab_len += secret_len + 1;
> +			}
> +		}
> +		if (buf)
> +			buf[secrets_cmdtab_len++] = '\n';
> +	}
> +	rcu_read_unlock();
> +
> +	return secrets_cmdtab_len;
> +}
> +
> +static ssize_t read_mask_secrets_cmdtab(struct file *file, char __user *buf,
> +		size_t len, loff_t *offset)
> +{
> +	char *secrets_cmdtab = 0;
> +	size_t secrets_cmdtab_len = 0;
> +	ssize_t ret = 0;
> +
> +	secrets_cmdtab_len = serialize_cmdtab(0);
> +	secrets_cmdtab = kzalloc(secrets_cmdtab_len, GFP_KERNEL);
> +	if (!secrets_cmdtab)
> +		return 0;
> +	secrets_cmdtab_len = serialize_cmdtab(secrets_cmdtab);
> +
> +	ret = simple_read_from_buffer(buf, len, offset,
> +			secrets_cmdtab, secrets_cmdtab_len);
> +
> +	kfree(secrets_cmdtab);
> +
> +	return ret;
> +}
> +
> +static int cmdline_hashtab_add(char *cmdline)
> +{
> +	struct cmdline_hashtab_item *chi = 0;
> +	char *progname = 0, *progname_start = cmdline + 1;
> +	char *secrets_start = 0;
> +	char *secret = 0;
> +	int secret_len = 0;
> +	int proghash = -1;
> +	struct file *file;
> +	struct inode *inode;
> +	int err = 0;
> +
> +	progname = strsep(&progname_start, SECRET_SEPARATOR);
> +	if (progname == NULL) {
> +		err = -EINVAL;
> +		goto exit_err;
> +	}
> +	if (progname[0] != '/') {
> +		err = -EINVAL;
> +		goto exit_err;
> +	}
> +	secrets_start = progname_start;
> +	if (secrets_start) {
> +		secret = secrets_start + strlen(secrets_start) - 1;
> +		while ((!isspace(*secret)) && (secret >= secrets_start))
> +			secret--;
> +		if (isspace(*secret) && (secret >= secrets_start)) {
> +			err = -EINVAL;
> +			goto exit_err;
> +		}
> +
> +		while ((secret = strsep(&secrets_start, SECRET_SEPARATOR)) != NULL) {
> +			secret_len = strlen(secret);
> +			if (secret_len < 2) {
> +				err = -EINVAL;
> +				goto exit_err;
> +			}
> +			if (secret[0] != '-') {
> +				err = -EINVAL;
> +				goto exit_err;
> +			}
> +		}
> +		secrets_start = progname_start;
> +	}
> +
> +	file = filp_open(progname, O_PATH, 0);
> +	if (IS_ERR(file)) {
> +		err = -ENOENT;
> +		goto exit_err;
> +	}
> +	inode = file_inode(file);
> +	if (!inode) {
> +		filp_close(file, 0);
> +		err = -ENOENT;
> +		goto exit_err;
> +	}
> +	proghash = cmdline_hash(inode->i_ino);
> +	filp_close(file, 0);
> +
> +	rcu_read_lock();
> +	hash_for_each_possible_rcu(cmdline_hashtab, chi, hlist, proghash)
> +		if (strcmp(chi->progname, progname) == 0) {
> +			rcu_read_unlock();
> +			err = -EEXIST;
> +			goto exit_err;
> +		}
> +	rcu_read_unlock();
> +
> +	chi = kmem_cache_zalloc(cmdline_hashtab_item_cachep, GFP_KERNEL);
> +	if (!chi) {
> +		err = -ENOMEM;
> +		goto exit_err;
> +	}
> +	INIT_HLIST_NODE(&chi->hlist);
> +	chi->cmdline = cmdline;
> +	chi->progname = progname;
> +	chi->secrets = secrets_start;
> +
> +	spin_lock(&cmdline_hashtab_spinlock);
> +	hash_add_rcu(cmdline_hashtab, &chi->hlist, proghash);
> +	spin_unlock(&cmdline_hashtab_spinlock);
> +	synchronize_rcu();
> +
> +exit_err:
> +	return err;
> +}
> +
> +
> +static int cmdline_hashtab_remove(char *cmdline)
> +{
> +	char *progname = cmdline + 1;
> +	struct file *file = 0;
> +	struct inode *inode = 0;
> +	int proghash = 0;
> +	struct cmdline_hashtab_item *chi = 0;
> +	int err = 0;
> +
> +	if (progname[0] != '/')
> +		goto exit_noent;
> +
> +	file = filp_open(progname, O_PATH, 0);
> +	if (IS_ERR(file))
> +		goto exit_noent;
> +	inode = file_inode(file);
> +	if (!inode) {
> +		filp_close(file, 0);
> +		goto exit_noent;
> +	}
> +	proghash = cmdline_hash(inode->i_ino);
> +	filp_close(file, 0);
> +
> +	rcu_read_lock();
> +	hash_for_each_possible_rcu(cmdline_hashtab, chi, hlist, proghash)
> +		if (strcmp(chi->progname, progname) == 0) {
> +			rcu_read_unlock();
> +			goto prog_found;
> +		}
> +	rcu_read_unlock();
> +
> +exit_noent:
> +	return (err = -ENOENT);
> +
> +prog_found:
> +	spin_lock(&cmdline_hashtab_spinlock);
> +	hash_del_rcu(&chi->hlist);
> +	spin_unlock(&cmdline_hashtab_spinlock);
> +	synchronize_rcu();
> +	kfree(chi->cmdline);
> +	kmem_cache_free(cmdline_hashtab_item_cachep, chi);
> +	kfree(cmdline);
> +	return err;
> +}
> +
> +static ssize_t write_mask_secrets_cmdtab(struct file *file, const char __user *buf,
> +				   size_t count, loff_t *ppos)
> +{
> +	char *kbuf = 0;
> +	char *op = 0;
> +	int err = 0;
> +
> +	if (count < 3) {
> +		err = -EINVAL;
> +		goto exit_err;
> +	}
> +
> +	if (!is_mask_secrets_enabled()) {
> +		err = -EPERM;
> +		goto exit_err;
> +	}
> +
> +	kbuf = kzalloc(count + 1, GFP_KERNEL);
> +	if (!kbuf) {
> +		err = -ENOMEM;
> +		goto exit_err;
> +	}
> +
> +	if (copy_from_user(kbuf, buf, count)) {
> +		err = -EFAULT;
> +		goto cleanup_kbuf;
> +	}
> +	kbuf[count - 1] = '\0';
> +	kbuf[count] = '\0';
> +
> +	op = kbuf;
> +	if ((*op != '+') && (*op != '-')) {
> +		err = -EINVAL;
> +		goto cleanup_kbuf;
> +	}
> +
> +	if (op[0] == '+')
> +		err = cmdline_hashtab_add(kbuf);
> +	else
> +		err = cmdline_hashtab_remove(kbuf);
> +
> +	if (err)
> +		goto cleanup_kbuf;
> +
> +	return count;
> +
> +cleanup_kbuf:
> +	kfree(kbuf);
> +
> +exit_err:
> +	return err;
> +}
> +
> +static const struct proc_ops mask_secrets_cmdtab_proc_ops = {
> +	.proc_open	= open_mask_secrets_cmdtab,
> +	.proc_lseek	= seq_lseek,
> +	.proc_read	= read_mask_secrets_cmdtab,
> +	.proc_write	= write_mask_secrets_cmdtab,
> +	.proc_release	= single_release,
> +};
> +
> +static int __init proc_mask_secrets_init(void)
> +{
> +	struct proc_dir_entry *pde_mask_secrets = NULL;
> +	struct proc_dir_entry *pde_mask_secrets_enabled = NULL;
> +	struct proc_dir_entry *pde_mask_secrets_cmdtab = NULL;
> +
> +	pde_mask_secrets = proc_mkdir("mask_secrets", NULL);
> +	if (!pde_mask_secrets)
> +		goto exit_nomem;
> +
> +	pde_mask_secrets_enabled = proc_create("enabled", 0644,
> +			pde_mask_secrets, &mask_secrets_enabled_proc_ops);
> +	if (!pde_mask_secrets_enabled)
> +		goto cleanup_pde_mask_secrets;
> +
> +	pde_mask_secrets_cmdtab = proc_create("cmdtab", 0644,
> +			pde_mask_secrets, &mask_secrets_cmdtab_proc_ops);
> +	if (!pde_mask_secrets_cmdtab)
> +		goto cleanup_pde_mask_secrets_enabled;
> +
> +	cmdline_hashtab_item_cachep = kmem_cache_create("cmdline_hashtab_item_cachep",
> +		       sizeof(struct cmdline_hashtab_item), 0, 0, NULL);
> +	if (!cmdline_hashtab_item_cachep)
> +		goto cleanup_pde_mask_secrets_cmdtab;
> +
> +	*((int *)&MASK_SECRETS_ENABLED) = 1;
> +	*((int *)&MASK_SECRETS_DISABLED) = 0;
> +
> +	return 0;
> +
> +cleanup_pde_mask_secrets_cmdtab:
> +	proc_remove(pde_mask_secrets_cmdtab);
> +
> +cleanup_pde_mask_secrets_enabled:
> +	proc_remove(pde_mask_secrets_enabled);
> +
> +cleanup_pde_mask_secrets:
> +	proc_remove(pde_mask_secrets);
> +
> +exit_nomem:
> +	return -ENOMEM;
> +}
> +fs_initcall(proc_mask_secrets_init);
> -- 
> 2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ