From patchwork Fri Jul 24 10:04:36 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Pawelczyk X-Patchwork-Id: 6859061 Return-Path: X-Original-To: patchwork-linux-fsdevel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E09F3C05AC for ; Fri, 24 Jul 2015 10:10:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C21492063D for ; Fri, 24 Jul 2015 10:10:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6FD0020609 for ; Fri, 24 Jul 2015 10:10:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753557AbbGXKJv (ORCPT ); Fri, 24 Jul 2015 06:09:51 -0400 Received: from mailout2.w1.samsung.com ([210.118.77.12]:31781 "EHLO mailout2.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750963AbbGXKF2 (ORCPT ); Fri, 24 Jul 2015 06:05:28 -0400 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout2.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NRZ005ECLD11D90@mailout2.w1.samsung.com>; Fri, 24 Jul 2015 11:05:25 +0100 (BST) X-AuditID: cbfec7f4-f79c56d0000012ee-77-55b20de510cb Received: from eusync2.samsung.com ( [203.254.199.212]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id A5.FE.04846.5ED02B55; Fri, 24 Jul 2015 11:05:25 +0100 (BST) Received: from amdc2143.DIGITAL.local ([106.120.53.33]) by eusync2.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0NRZ00EPNLC23A60@eusync2.samsung.com>; Fri, 24 Jul 2015 11:05:25 +0100 (BST) From: Lukasz Pawelczyk To: "Eric W. Biederman" , "Serge E. Hallyn" , Al Viro , Alexey Dobriyan , Andrew Morton , Andy Lutomirski , Arnd Bergmann , Casey Schaufler , David Howells , Eric Dumazet , Eric Paris , Fabian Frederick , Greg KH , James Morris , Jiri Slaby , Joe Perches , John Johansen , Jonathan Corbet , Kees Cook , Lukasz Pawelczyk , Mauro Carvalho Chehab , NeilBrown , Oleg Nesterov , Paul Moore , Stephen Smalley , Tetsuo Handa , Zefan Li , linux-doc@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-security-module@vger.kernel.org, selinux@tycho.nsa.gov Cc: havner@gmail.com Subject: [PATCH v3 02/11] lsm: /proc/$PID/attr/label_map file and getprocattr_seq hook Date: Fri, 24 Jul 2015 12:04:36 +0200 Message-id: <1437732285-11524-3-git-send-email-l.pawelczyk@samsung.com> X-Mailer: git-send-email 2.4.3 In-reply-to: <1437732285-11524-1-git-send-email-l.pawelczyk@samsung.com> References: <1437732285-11524-1-git-send-email-l.pawelczyk@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAAzWRe0hTcRTH/W2/3TulG5dp66IVNeqfyFeUHNLCyPAiUSEJ5j819TLNbcqm phE0Sy1nmsxQmTOVlYEPNFPJx1K0pvmYii/Q0lIXQTYfaJKmSyf9d8738znn/HGEfFE3dhfG KhM5lVIqlxAuuG+7e9TTStWH+YxqxFCYFgKG2moCtnRmEqabNgiY73iMwPZwE4O9KZ0Eq3mW hKxvA3zQbv4h4JGxlgD7z1OQOxcKxTNzGHpWMwh4XrfEg/5sBfTrynlQnvkSQ5vpE4aRFgMB S09nCdA9ySGhqkYjgKrvKWAq1WBobM9AMKUrxFCcbhNAV6uRD/nznRgGhywkDG51CwKPsTML W5jd3NAhVq/JIdhizTBmm/VfSLasPokdb73Jpn/4JWCbayp5bE/RJmbbS6pJ1pibL2CXrZOY bXi2ow6sRbA1ph/oukeES0A0J49N5lTeF267xIyNj+CEgksp2vwpQoPW/bTIWcjQZ5gp+yK5 V4uZoelaQotchCL6FWJGrZnkXpPGYyom+vCuRdA+zPqQib8L3OhGZyavrgbtAj7txvy1LTtW udLhjDXT5BjA9AlmwaBx5BQdzFQYKgV7544wltpVh+NMs0zfyIrDEe042XoDmYeoMuRUiQ5w SVEJ6kiZwtdLLVWok5Qyr6h4RT3ae+/qO2Q0n+tEtBBJ9lEdujdhIoE0WZ2q6ESMkC9xo5zM OxEVLU29x6nib6mS5Jy6E3kIseQgVdKyeENEy6SJXBzHJXCq/5QndHbXoLNXr7QGBWVQ/sOH KL3lRWBOSXNa2te1B/IAO/bIOj7n2juVvD/EHqn1PTwtNhuVbR+D/S5Ph7+eGWsOvZYjPv27 wdDmr9BN9n6+XxZcgKpDm0q9z2/fKVpRetr0b28Y24yTdYoxS5x4ayLsYkyXV+Ldo70N7+PM 5aT7aECRLEuC1TFS35N8lVr6D/CqxxjaAgAA Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Spam-Status: No, score=-8.1 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This commit adds a new proc attribute, label_map that is required by an upcoming Smack namespace. In general it can be used to hold a map of labels, e.g. to be used in namespaces. Due to the nature of this file, the standard getprocattr hook might not be enough to handle it. The map's output can in principle be greater than page size to which the aforementioned hook is limited. To handle this properly a getprocattr_seq LSM hook has been added that makes it possible to handle any chosen proc attr by seq operations. See the documentation in the patch below for the details about how to use the hook. Signed-off-by: Lukasz Pawelczyk Acked-by: Serge Hallyn --- fs/proc/base.c | 81 +++++++++++++++++++++++++++++++++++++++++++---- include/linux/lsm_hooks.h | 15 +++++++++ include/linux/security.h | 9 ++++++ security/security.c | 8 +++++ 4 files changed, 107 insertions(+), 6 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index aa50d1a..e5ac827 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2338,20 +2338,77 @@ out: } #ifdef CONFIG_SECURITY +static int proc_pid_attr_open(struct inode *inode, struct file *file) +{ + const char *name = file->f_path.dentry->d_name.name; + const struct seq_operations *ops; + struct task_struct *task; + struct seq_file *seq; + int ret; + + file->private_data = NULL; + + task = get_proc_task(inode); + if (!task) + return -ESRCH; + + /* don't use seq_ops if they are not provided by LSM */ + ret = security_getprocattr_seq(task, name, &ops); + if (ret == -EOPNOTSUPP) { + put_task_struct(task); + return 0; + } + if (ret) { + put_task_struct(task); + return ret; + } + + ret = seq_open(file, ops); + if (ret) { + put_task_struct(task); + return ret; + } + + seq = file->private_data; + seq->private = task; + + return 0; +} + +static int proc_pid_attr_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + struct task_struct *task; + + /* don't use seq_ops if they were not provided by LSM */ + if (file->private_data == NULL) + return 0; + + seq = file->private_data; + task = seq->private; + put_task_struct(task); + + return seq_release(inode, file); +} + static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { - struct inode * inode = file_inode(file); + struct inode *inode = file_inode(file); + const char *name = file->f_path.dentry->d_name.name; char *p = NULL; ssize_t length; - struct task_struct *task = get_proc_task(inode); + struct task_struct *task; + + /* use seq_ops if they were provided by LSM */ + if (file->private_data) + return seq_read(file, buf, count, ppos); + task = get_proc_task(inode); if (!task) return -ESRCH; - length = security_getprocattr(task, - (char*)file->f_path.dentry->d_name.name, - &p); + length = security_getprocattr(task, (char *)name, &p); put_task_struct(task); if (length > 0) length = simple_read_from_buffer(buf, count, ppos, p, length); @@ -2359,6 +2416,15 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, return length; } +static loff_t proc_pid_attr_lseek(struct file *file, loff_t offset, int whence) +{ + /* use seq_ops if they were provided by LSM */ + if (file->private_data) + return seq_lseek(file, offset, whence); + + return generic_file_llseek(file, offset, whence); +} + static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { @@ -2405,9 +2471,11 @@ out_no_task: } static const struct file_operations proc_pid_attr_operations = { + .open = proc_pid_attr_open, + .release = proc_pid_attr_release, .read = proc_pid_attr_read, + .llseek = proc_pid_attr_lseek, .write = proc_pid_attr_write, - .llseek = generic_file_llseek, }; static const struct pid_entry attr_dir_stuff[] = { @@ -2417,6 +2485,7 @@ static const struct pid_entry attr_dir_stuff[] = { 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("label_map", S_IRUGO|S_IWUGO, proc_pid_attr_operations), }; static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 228558c..d347e66 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1208,6 +1208,18 @@ * @name full extended attribute name to check against * LSM as a MAC label. * + * @getprocattr_seq: + * An alternative to the getprocattr, that makes it possible for an attr + * file to be handled by seq operations. If this function returns valid + * @ops for a specific @name, those operations will be used and + * getprocattr will not be called. + * A proper task for the file is then passed in seq_file->private. + * @p a task associated with the proc file. + * @name name of the attr file under /proc/$PID/attr/ to be handled. + * @ops (out) seq_operations to be used for @name. + * Return 0 if @name is to be handled by seq, EOPNOTSUPP if getprocattr() + * should be used. Other errors will be passed to user-space. + * * @secid_to_secctx: * Convert secid to security context. If secdata is NULL the length of * the result will be returned in seclen, but no secdata will be returned. @@ -1525,6 +1537,8 @@ union security_list_options { void (*d_instantiate)(struct dentry *dentry, struct inode *inode); + int (*getprocattr_seq)(struct task_struct *p, const char *name, + const struct seq_operations **ops); int (*getprocattr)(struct task_struct *p, char *name, char **value); int (*setprocattr)(struct task_struct *p, char *name, void *value, size_t size); @@ -1774,6 +1788,7 @@ struct security_hook_heads { struct list_head sem_semop; struct list_head netlink_send; struct list_head d_instantiate; + struct list_head getprocattr_seq; struct list_head getprocattr; struct list_head setprocattr; struct list_head ismaclabel; diff --git a/include/linux/security.h b/include/linux/security.h index 1b0eccc..3090bb2 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -345,6 +345,8 @@ 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_seq(struct task_struct *p, const char *name, + const struct seq_operations **ops); 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_netlink_send(struct sock *sk, struct sk_buff *skb); @@ -1057,6 +1059,13 @@ static inline int security_sem_semop(struct sem_array *sma, static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode) { } +static inline int security_getprocattr_seq(struct task_struct *p, + const char *name, + const struct seq_operations **ops) +{ + return -EOPNOTSUPP; +} + static inline int security_getprocattr(struct task_struct *p, char *name, char **value) { return -EINVAL; diff --git a/security/security.c b/security/security.c index 5e66388..e348e38 100644 --- a/security/security.c +++ b/security/security.c @@ -1126,6 +1126,12 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode) } EXPORT_SYMBOL(security_d_instantiate); +int security_getprocattr_seq(struct task_struct *p, const char *name, + const struct seq_operations **ops) +{ + return call_int_hook(getprocattr_seq, -EOPNOTSUPP, p, name, ops); +} + int security_getprocattr(struct task_struct *p, char *name, char **value) { return call_int_hook(getprocattr, -EINVAL, p, name, value); @@ -1778,6 +1784,8 @@ struct security_hook_heads security_hook_heads = { .netlink_send = LIST_HEAD_INIT(security_hook_heads.netlink_send), .d_instantiate = LIST_HEAD_INIT(security_hook_heads.d_instantiate), + .getprocattr_seq = + LIST_HEAD_INIT(security_hook_heads.getprocattr_seq), .getprocattr = LIST_HEAD_INIT(security_hook_heads.getprocattr), .setprocattr = LIST_HEAD_INIT(security_hook_heads.setprocattr), .ismaclabel = LIST_HEAD_INIT(security_hook_heads.ismaclabel),