From patchwork Wed Jan 18 19:07:19 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Casey Schaufler X-Patchwork-Id: 9524597 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 584F160113 for ; Wed, 18 Jan 2017 19:09:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 492B0285F9 for ; Wed, 18 Jan 2017 19:09:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3B34A2861D; Wed, 18 Jan 2017 19:09:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4D4DA285F9 for ; Wed, 18 Jan 2017 19:09:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753487AbdARTIr (ORCPT ); Wed, 18 Jan 2017 14:08:47 -0500 Received: from nm25-vm2.bullet.mail.ne1.yahoo.com ([98.138.91.213]:59229 "EHLO nm25-vm2.bullet.mail.ne1.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752114AbdARTIp (ORCPT ); Wed, 18 Jan 2017 14:08:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1484766441; bh=TaE7kP+v4nG/KbrU4WTWd1E41TGDp9q9FIExDqcjisM=; h=To:Cc:From:Subject:Date:From:Subject; b=I3DLN7heunP0lm8lDzsASnB4HYVLkaM4a0z7OHHLUl30PfC7gaXPnlFZZ9t2mfl3WqOzunod6/4fUX/6TDSqFzJFJBuyy2IRzra5B0eGFO7X/jeJ+2G720wm3tyBKBDSSTPo3JoYyt1ucMVqBZkISfU9dK59hYc2aaudzxwLH97KWHgLz3sRv2bKlsepCdmdf7vqHcwwMD321Gpf4r6j58/VkM2p4FdN2zxjFMEWOuZJmYbTnrI22Tasd18ODg0TcLZ4yBrv5S2vgajMBJ7oGdF+BQv+k88PjzRy4hI4J/bxxi+3EBqktts4/12ssLF7r6eEA8tk/MDcGtRhucmG/w== Received: from [98.138.100.113] by nm25.bullet.mail.ne1.yahoo.com with NNFMP; 18 Jan 2017 19:07:21 -0000 Received: from [98.138.104.113] by tm104.bullet.mail.ne1.yahoo.com with NNFMP; 18 Jan 2017 19:07:21 -0000 Received: from [127.0.0.1] by smtp222.mail.ne1.yahoo.com with NNFMP; 18 Jan 2017 19:07:21 -0000 X-Yahoo-Newman-Id: 381646.31062.bm@smtp222.mail.ne1.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: R81LM0cVM1m9eZ5IotJc8_hoS1qKs6es8QoYqqcdgGpgdur fKOUlvO6Yv2ifpctEvhsde8P5_OIxQILCOFgYS2mEts22nhYsAAeAEFjo5e9 dOR0J49bv.r9Aea7b4nb4MRUoFq4nmqLKzrgUmKUycUISkWSFtJFjwqsrPYi YUA2NNggYb_2dvR7pEObnJg9hs4o6xADaWGFYapXZ7cLI75NHUllWvCWhOSB tLSB4hEfnZigopAFhqryik0s.vh72PjOWoq1fGe3o9aahCASxUD1FiThd_FG C1OHLHDJvjEI3PSsa5CsqC1X7x.XnPAGHvnA7_u9hOTeslkn.bfIJdLgCgT7 JVqNGXUyYS2OEB0c.yFCxvMMYgLqlKqhG3yiz9ypXQ6LMUlmtF1UyvUJ6loT D5bTyjKTaFPMr7FDZA4w78s8ma0tdW4N4G9y8sILxmmbM25jCKSEsHmQ5aP3 CW539u9k9Rgs1pqNL7NSJi0.ITGQGZ8oooKlnnRjNeow.fYS5RjaformTBiH lFoBCiv3xDc4qqRjrKQXVlPLZzO870CKEUV1Qh17jWFqfuIqbmvYwwYbwsw- - X-Yahoo-SMTP: OIJXglSswBDfgLtXluJ6wiAYv6_cnw-- To: LSM , LKLM , James Morris , Alexey Dobriyan Cc: Kees Cook , Casey Schaufler From: Casey Schaufler Subject: [PATCH] LSM: Add a Smack subdirectory in /proc/.../attr Message-ID: Date: Wed, 18 Jan 2017 11:07:19 -0800 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Thunderbird/45.6.0 MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Subject: [PATCH] LSM: Add a Smack subdirectory in /proc/.../attr Back in 2007 I made what turned out to be a rather serious mistake in the implementation of the Smack security module. The SELinux module used an interface in /proc to manipulate the security context on processes. Rather than use a similar interface, I used the same interface. The AppArmor team did likewise. Now /proc/.../attr/current will tell you the security "context" of the process, but it will be different depending on the security module you're using. This patch provides a subdirectory in /proc/.../attr for Smack. Smack user space can use the "current" file in this subdirectory and never have to worry about getting SELinux attributes by mistake. Programs that use the old interface will continue to work (or fail, as the case may be) as before. This patch does not include subdirectories for SELinux or AppArmor. I do have a patch that provides those, and will happily make it available should anyone see value in it. The original implementation is by Kees Cook. Signed-off-by: Casey Schaufler --- Documentation/security/LSM.txt | 19 +++++++++---- fs/proc/base.c | 62 ++++++++++++++++++++++++++++++++++++------ fs/proc/internal.h | 1 + include/linux/security.h | 15 ++++++---- security/security.c | 30 +++++++++++++++++--- 5 files changed, 103 insertions(+), 24 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/Documentation/security/LSM.txt b/Documentation/security/LSM.txt index c2683f2..57eafbc 100644 --- a/Documentation/security/LSM.txt +++ b/Documentation/security/LSM.txt @@ -16,11 +16,10 @@ MAC extensions, other extensions can be built using the LSM to provide specific changes to system operation when these tweaks are not available in the core functionality of Linux itself. -Without a specific LSM built into the kernel, the default LSM will be the -Linux capabilities system. Most LSMs choose to extend the capabilities -system, building their checks on top of the defined capability hooks. -For more details on capabilities, see capabilities(7) in the Linux -man-pages project. +The Linux capabilities modules will always be included. For more details +on capabilities, see capabilities(7) in the Linux man-pages project. +This may be followed by any number of "minor" modules and at most one +"major" module. A list of the active security modules can be found by reading /sys/kernel/security/lsm. This is a comma separated list, and @@ -29,6 +28,14 @@ order in which checks are made. The capability module will always be first, followed by any "minor" modules (e.g. Yama) and then the one "major" module (e.g. SELinux) if there is one configured. +Process attributes associated with "major" security modules should +be accessed and maintained using the special files in /proc/.../attr. +A security module may maintain a module specific subdirectory there, +named after the module. /proc/.../attr/smack is provided by the Smack +security module and contains all its special files. The files directly +in /proc/.../attr remain as legacy interfaces for modules that provide +subdirectories. + Based on https://lkml.org/lkml/2007/10/26/215, a new LSM is accepted into the kernel when its intent (a description of what it tries to protect against and in what cases one would expect to @@ -38,4 +45,4 @@ that end users and distros can make a more informed decision about which LSMs suit their requirements. For extensive documentation on the available LSM hook interfaces, please -see include/linux/security.h. +see include/linux/lsm_hooks.h. diff --git a/fs/proc/base.c b/fs/proc/base.c index 8e7e61b..565010c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -134,9 +134,13 @@ struct pid_entry { #define REG(NAME, MODE, fops) \ NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) #define ONE(NAME, MODE, show) \ - NOD(NAME, (S_IFREG|(MODE)), \ + 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 . @@ -2467,7 +2471,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); @@ -2507,7 +2511,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, page, count); mutex_unlock(&task->signal->cred_guard_mutex); @@ -2525,13 +2529,53 @@ static const struct file_operations proc_pid_attr_operations = { .llseek = generic_file_llseek, }; +#define LSM_DIR_OPS(LSM) \ +static int proc_##LSM##_attr_dir_iterate(struct file *filp, \ + struct dir_context *ctx) \ +{ \ + return proc_pident_readdir(filp, ctx, \ + LSM##_attr_dir_stuff, \ + ARRAY_SIZE(LSM##_attr_dir_stuff)); \ +} \ +\ +static const struct file_operations proc_##LSM##_attr_dir_ops = { \ + .read = generic_read_dir, \ + .iterate = proc_##LSM##_attr_dir_iterate, \ + .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, \ +} + +#ifdef CONFIG_SECURITY_SMACK +static const struct pid_entry smack_attr_dir_stuff[] = { + ATTR("smack", "current", 0666), +}; +LSM_DIR_OPS(smack); +#endif + 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), + ATTR(NULL, "current", 0666), + ATTR(NULL, "prev", 0444), + ATTR(NULL, "exec", 0666), + ATTR(NULL, "fscreate", 0666), + ATTR(NULL, "keycreate", 0666), + ATTR(NULL, "sockcreate", 0666), +#ifdef CONFIG_SECURITY_SMACK + DIR("smack", 0555, + proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops), +#endif }; static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 2de5194..ba44806 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 c2125e9..839e8b9 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -360,8 +360,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_ismaclabel(const char *name); int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); @@ -1098,15 +1100,18 @@ static inline int security_sem_semop(struct sem_array *sma, return 0; } -static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode) +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, const char *lsm, + char *name, char **value) { return -EINVAL; } -static inline int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size) +static inline int security_setprocattr(struct task_struct *p, const char *lsm, + char *name, void *value, size_t size) { return -EINVAL; } diff --git a/security/security.c b/security/security.c index f0a802ee..4b6f7643 100644 --- a/security/security.c +++ b/security/security.c @@ -1203,14 +1203,36 @@ 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) { - return call_int_hook(getprocattr, -EINVAL, p, name, value); + struct security_hook_list *hp; + int rc = -EINVAL; + + list_for_each_entry(hp, &security_hook_heads.getprocattr, list) { + if (lsm != NULL && strcmp(lsm, hp->lsm)) + continue; + rc = hp->hook.getprocattr(p, name, value); + if (rc != -ENOENT) + return rc; + } + 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) { - return call_int_hook(setprocattr, -EINVAL, p, name, value, size); + struct security_hook_list *hp; + int rc = -EINVAL; + + list_for_each_entry(hp, &security_hook_heads.setprocattr, list) { + if (lsm != NULL && strcmp(lsm, hp->lsm)) + continue; + rc = hp->hook.setprocattr(p, name, value, size); + if (rc != -ENOENT) + break; + } + return rc; } int security_netlink_send(struct sock *sk, struct sk_buff *skb)