From: Casey Schaufler <casey@schaufler-ca.com>
To: Kees Cook <keescook@chromium.org>
Cc: LKLM <linux-kernel@vger.kernel.org>,
LSM <linux-security-module@vger.kernel.org>,
SE Linux <selinux@tycho.nsa.gov>,
James Morris <jmorris@namei.org>,
John Johansen <john.johansen@canonical.com>,
Eric Paris <eparis@redhat.com>,
Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>,
Casey Schaufler <casey@schaufler-ca.com>
Subject: Re: [PATCH v14 0/6] LSM: Multiple concurrent LSMs
Date: Tue, 06 Aug 2013 15:25:44 -0700 [thread overview]
Message-ID: <520177E8.5080906@schaufler-ca.com> (raw)
In-Reply-To: <20130806063002.GF2280@outflux.net>
On 8/5/2013 11:30 PM, Kees Cook wrote:
> On Thu, Jul 25, 2013 at 11:52 PM, Casey Schaufler <casey@schaufler-ca.com> wrote:
>> The /proc/*/attr interfaces are given to one LSM. This can be
>> done by setting CONFIG_SECURITY_PRESENT. Additional interfaces
>> have been created in /proc/*/attr so that each LSM has its own
>> named interfaces. The name of the presenting LSM can be read from
> For me, this is one problem that was bothering me, but it was a cosmetic
> one that I'd mentioned before: I really disliked the /proc/$pid/attr
> interface being named "$lsm.$file". I feel it's important to build
> directories in attr/ for each LSM. So, I spent time to figure out a way to
> do this. This patch changes the interface to /proc/$pid/attr/$lsm/$file
> instead, which I feel has a much more appealing organizational structure.
I will confess that the reason I went with <lsm>.current instead of
<lsm>/current was that the former was easier to implement.
> -Kees
>
> ---
> Subject: [PATCH] LSM: use subdirectories for LSM attr files
>
> Instead of filling the /proc/$pid/attr/ directory with every LSM's needed
> attr files, insert a directory entry for each LSM which contains the
> needed files.
>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
> fs/proc/base.c | 95 ++++++++++++++++++++++++++++++++++++----------
> fs/proc/internal.h | 1 +
> include/linux/security.h | 11 +++---
> security/security.c | 67 ++++++++++++++------------------
> 4 files changed, 112 insertions(+), 62 deletions(-)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 941fe83..4c80ffd 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -138,6 +138,10 @@ struct pid_entry {
> NOD(NAME, (S_IFREG|(MODE)), \
> NULL, &proc_single_file_operations, \
> { .proc_show = show } )
> +#define ATTR(LSM, NAME, MODE) \
> + NOD(NAME, (S_IFREG|(MODE)), \
> + NULL, &proc_pid_attr_operations, \
> + { .lsm = LSM } )
>
> /*
> * Count the number of hardlinks for the pid_entry table, excluding the .
> @@ -2292,7 +2296,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
> if (!task)
> return -ESRCH;
>
> - length = security_getprocattr(task,
> + length = security_getprocattr(task, PROC_I(inode)->op.lsm,
> (char*)file->f_path.dentry->d_name.name,
> &p);
> put_task_struct(task);
> @@ -2335,7 +2339,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
> if (length < 0)
> goto out_free;
>
> - length = security_setprocattr(task,
> + length = security_setprocattr(task, PROC_I(inode)->op.lsm,
> (char*)file->f_path.dentry->d_name.name,
> (void*)page, count);
> mutex_unlock(&task->signal->cred_guard_mutex);
> @@ -2353,29 +2357,82 @@ static const struct file_operations proc_pid_attr_operations = {
> .llseek = generic_file_llseek,
> };
>
> +#define LSM_DIR_OPS(LSM) \
> +static int proc_##LSM##_attr_dir_readdir(struct file * filp, \
> + void * dirent, filldir_t filldir) \
> +{ \
> + return proc_pident_readdir(filp, dirent, filldir, \
> + LSM##_attr_dir_stuff, \
> + ARRAY_SIZE(LSM##_attr_dir_stuff)); \
> +} \
> +\
> +static const struct file_operations proc_##LSM##_attr_dir_ops = { \
> + .read = generic_read_dir, \
> + .readdir = proc_##LSM##_attr_dir_readdir, \
> + .llseek = default_llseek, \
> +}; \
> +\
> +static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \
> + struct dentry *dentry, unsigned int flags) \
> +{ \
> + return proc_pident_lookup(dir, dentry, \
> + LSM##_attr_dir_stuff, \
> + ARRAY_SIZE(LSM##_attr_dir_stuff)); \
> +} \
> +\
> +static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
> + .lookup = proc_##LSM##_attr_dir_lookup, \
> + .getattr = pid_getattr, \
> + .setattr = proc_setattr, \
> +};
That's one hell of a macro you got there, Kees.
I'm not saying it's bad, but it is quite the mouthful.
> +
> +#ifdef CONFIG_SECURITY_SELINUX
> +static const struct pid_entry selinux_attr_dir_stuff[] = {
> + ATTR("selinux", "current", S_IRUGO|S_IWUGO),
> + ATTR("selinux", "prev", S_IRUGO),
> + ATTR("selinux", "exec", S_IRUGO|S_IWUGO),
> + ATTR("selinux", "fscreate", S_IRUGO|S_IWUGO),
> + ATTR("selinux", "keycreate", S_IRUGO|S_IWUGO),
> + ATTR("selinux", "sockcreate", S_IRUGO|S_IWUGO),
> +};
> +LSM_DIR_OPS(selinux);
> +#endif
> +
> +#ifdef CONFIG_SECURITY_SMACK
> +static const struct pid_entry smack_attr_dir_stuff[] = {
> + ATTR("smack", "current", S_IRUGO|S_IWUGO),
> +};
> +LSM_DIR_OPS(smack);
> +#endif
> +
> +#ifdef CONFIG_SECURITY_APPARMOR
> +static const struct pid_entry apparmor_attr_dir_stuff[] = {
> + ATTR("apparmor", "current", S_IRUGO|S_IWUGO),
> + ATTR("apparmor", "prev", S_IRUGO),
> + ATTR("apparmor", "exec", S_IRUGO|S_IWUGO),
> +};
> +LSM_DIR_OPS(apparmor);
> +#endif
> +
%s/dir_stuff/dir_entries/g
It doesn't have to be "entries", but "stuff" is horribly non-descriptive.
> static const struct pid_entry attr_dir_stuff[] = {
> - REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("prev", S_IRUGO, proc_pid_attr_operations),
> - REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("context", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> + ATTR(NULL, "current", S_IRUGO|S_IWUGO),
> + ATTR(NULL, "prev", S_IRUGO),
> + ATTR(NULL, "exec", S_IRUGO|S_IWUGO),
> + ATTR(NULL, "fscreate", S_IRUGO|S_IWUGO),
> + ATTR(NULL, "keycreate", S_IRUGO|S_IWUGO),
> + ATTR(NULL, "sockcreate", S_IRUGO|S_IWUGO),
> + ATTR(NULL, "context", S_IRUGO|S_IWUGO),
> #ifdef CONFIG_SECURITY_SELINUX
> - REG("selinux.current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("selinux.prev", S_IRUGO, proc_pid_attr_operations),
> - REG("selinux.exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("selinux.fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("selinux.keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("selinux.sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> + DIR("selinux", S_IRUGO|S_IXUGO,
> + proc_selinux_attr_dir_inode_ops, proc_selinux_attr_dir_ops),
> #endif
> #ifdef CONFIG_SECURITY_SMACK
> - REG("smack.current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> + DIR("smack", S_IRUGO|S_IXUGO,
> + proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
> #endif
> #ifdef CONFIG_SECURITY_APPARMOR
> - REG("apparmor.current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> - REG("apparmor.prev", S_IRUGO, proc_pid_attr_operations),
> - REG("apparmor.exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
> + DIR("apparmor", S_IRUGO|S_IXUGO,
> + proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops),
> #endif
>
> };
> diff --git a/fs/proc/internal.h b/fs/proc/internal.h
> index d600fb0..795f649 100644
> --- a/fs/proc/internal.h
> +++ b/fs/proc/internal.h
> @@ -56,6 +56,7 @@ union proc_op {
> int (*proc_show)(struct seq_file *m,
> struct pid_namespace *ns, struct pid *pid,
> struct task_struct *task);
> + const char *lsm;
> };
>
> struct proc_inode {
> diff --git a/include/linux/security.h b/include/linux/security.h
> index d60e21c..fa89618 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -2115,9 +2115,10 @@ int security_sem_semctl(struct sem_array *sma, int cmd);
> int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
> unsigned nsops, int alter);
> void security_d_instantiate(struct dentry *dentry, struct inode *inode);
> -int security_getprocattr(struct task_struct *p, char *name, char **value);
> -int security_setprocattr(struct task_struct *p, char *name, void *value,
> - size_t size);
> +int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
> + char **value);
> +int security_setprocattr(struct task_struct *p, const char *lsm, char *name,
> + void *value, size_t size);
> int security_netlink_send(struct sock *sk, struct sk_buff *skb);
> int security_secid_to_secctx(struct secids *secid, char **secdata, u32 *seclen,
> struct security_operations **secops);
> @@ -2801,8 +2802,8 @@ static inline void security_d_instantiate(struct dentry *dentry,
> struct inode *inode)
> { }
>
> -static inline int security_getprocattr(struct task_struct *p, char *name,
> - char **value)
> +static inline int security_getprocattr(struct task_struct *p, char *lsm,
> + char *name, char **value)
> {
> return -EINVAL;
> }
> diff --git a/security/security.c b/security/security.c
> index 119a377..499af30 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1897,74 +1897,65 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
> }
> EXPORT_SYMBOL(security_d_instantiate);
>
> -int security_getprocattr(struct task_struct *p, char *name, char **value)
> +int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
> + char **value)
> {
> struct security_operations *sop = NULL;
> struct secids secid;
> - char *lsm;
> - int lsmlen;
> int ret;
>
> /*
> - * Names will either be in the legacy form containing
> - * no periods (".") or they will be the LSM name followed
> - * by the legacy suffix. "current" or "selinux.current"
> - * The exception is "context", which gets all of the LSMs.
> - *
> - * Legacy names are handled by the presenting LSM.
> - * Suffixed names are handled by the named LSM.
> + * Target LSM will be either NULL or looked up by name. Names with
> + * a NULL LSM (legacy) are handled by the presenting LSM. The
> + * exception is "context", which gets all of the LSMs.
> */
> if (strcmp(name, "context") == 0) {
> + char *lsmname;
> + int lsmlen;
> +
> security_task_getsecid(p, &secid);
> - ret = security_secid_to_secctx(&secid, &lsm, &lsmlen, &sop);
> + ret = security_secid_to_secctx(&secid, &lsmname, &lsmlen, &sop);
> if (ret == 0) {
> - *value = kstrdup(lsm, GFP_KERNEL);
> + *value = kstrdup(lsmname, GFP_KERNEL);
> if (*value == NULL)
> ret = -ENOMEM;
> else
> ret = strlen(*value);
> - security_release_secctx(lsm, lsmlen, sop);
> + security_release_secctx(lsmname, lsmlen, sop);
> }
> return ret;
> }
>
> - if (present_ops && !strchr(name, '.'))
> - return present_getprocattr(p, name, value);
> -
> - for_each_hook(sop, getprocattr) {
> - lsm = sop->name;
> - lsmlen = strlen(lsm);
> - if (!strncmp(name, lsm, lsmlen) && name[lsmlen] == '.')
> - return sop->getprocattr(p, name + lsmlen + 1, value);
> + if (!lsm) {
> + if (present_ops)
> + return present_getprocattr(p, name, value);
> + } else {
> + for_each_hook(sop, getprocattr) {
> + if (!strcmp(lsm, sop->name))
> + return sop->getprocattr(p, name, value);
> + }
> }
> return -EINVAL;
> }
>
> -int security_setprocattr(struct task_struct *p, char *name, void *value,
> - size_t size)
> +int security_setprocattr(struct task_struct *p, const char *lsm, char *name,
> + void *value, size_t size)
> {
> struct security_operations *sop;
> - char *lsm;
> - int lsmlen;
>
> /*
> - * Names will either be in the legacy form containing
> - * no periods (".") or they will be the LSM name followed
> - * by the legacy suffix.
> - * "current" or "selinux.current"
> - *
> - * Legacy names are handled by the presenting LSM.
> - * Suffixed names are handled by the named LSM.
> + * Target LSM will be either NULL or looked up by name. Names with
> + * a NULL LSM (legacy) are handled by the presenting LSM. The
> */
> if (present_ops && !strchr(name, '.'))
> return present_setprocattr(p, name, value, size);
We'll want to loose the preceding two lines, and add some later.
> - for_each_hook(sop, setprocattr) {
> - lsm = sop->name;
> - lsmlen = strlen(lsm);
> - if (!strncmp(name, lsm, lsmlen) && name[lsmlen] == '.')
> - return sop->setprocattr(p, name + lsmlen + 1, value,
> - size);
> + if (lsm) {
> + for_each_hook(sop, setprocattr) {
> + if (!strcmp(lsm, sop->name))
> + return sop->setprocattr(p, name, value,
> + size);
> + }
> - }
+ } else if (present_ops)
+ return present_setprocattr(p, name, value, size);
> return -EINVAL;
> }
next prev parent reply other threads:[~2013-08-06 22:25 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-07-25 18:22 [PATCH v14 0/6] LSM: Multiple concurrent LSMs Casey Schaufler
2013-07-25 18:32 ` [PATCH v14 1/6] LSM: Security blob abstraction Casey Schaufler
2013-07-29 21:15 ` Kees Cook
2013-07-30 1:49 ` Casey Schaufler
2013-07-25 18:32 ` [PATCH v14 2/6] LSM: Move the capability LSM into the hook handlers Casey Schaufler
2013-07-25 18:32 ` [PATCH v14 3/6] LSM: Explicit individual LSM associations Casey Schaufler
2013-07-29 20:51 ` Kees Cook
2013-07-30 1:48 ` Casey Schaufler
2013-07-30 22:08 ` Paul Moore
2013-07-31 16:22 ` Casey Schaufler
2013-07-31 19:39 ` Paul Moore
2013-07-31 21:21 ` Casey Schaufler
2013-08-01 18:35 ` Paul Moore
2013-08-01 18:52 ` Casey Schaufler
2013-08-01 21:30 ` Paul Moore
2013-08-01 22:15 ` Casey Schaufler
2013-08-01 22:18 ` Paul Moore
2013-07-25 18:32 ` [PATCH v14 4/6] LSM: List based multiple LSM hooks Casey Schaufler
2013-07-25 18:32 ` [PATCH v14 5/6] LSM: SO_PEERSEC configuration options Casey Schaufler
2013-07-30 21:47 ` Paul Moore
2013-07-31 15:45 ` Casey Schaufler
2013-07-31 17:56 ` Paul Moore
2013-07-25 18:32 ` [PATCH v14 6/6] LSM: Multiple LSM Documentation and cleanup Casey Schaufler
2013-07-26 23:17 ` Randy Dunlap
2013-07-28 18:46 ` Casey Schaufler
2013-08-01 2:48 ` [PATCH v14 0/6] LSM: Multiple concurrent LSMs Balbir Singh
2013-08-01 17:21 ` Casey Schaufler
2013-08-06 3:28 ` Balbir Singh
2013-08-06 6:30 ` Kees Cook
2013-08-06 22:25 ` Casey Schaufler [this message]
2013-08-06 22:36 ` Kees Cook
2013-08-27 2:29 ` Casey Schaufler
2013-08-28 15:55 ` Kees Cook
2013-09-05 18:48 ` Kees Cook
2013-09-06 6:44 ` Casey Schaufler
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=520177E8.5080906@schaufler-ca.com \
--to=casey@schaufler-ca.com \
--cc=eparis@redhat.com \
--cc=jmorris@namei.org \
--cc=john.johansen@canonical.com \
--cc=keescook@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=penguin-kernel@i-love.sakura.ne.jp \
--cc=selinux@tycho.nsa.gov \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox