From patchwork Wed Aug 12 19:15:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11711179 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D0ACC618 for ; Wed, 12 Aug 2020 19:15:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B86662080C for ; Wed, 12 Aug 2020 19:15:35 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="j0JXZj2X" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726631AbgHLTPe (ORCPT ); Wed, 12 Aug 2020 15:15:34 -0400 Received: from linux.microsoft.com ([13.77.154.182]:49296 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726627AbgHLTPd (ORCPT ); Wed, 12 Aug 2020 15:15:33 -0400 Received: from localhost.localdomain (c-73-172-233-15.hsd1.md.comcast.net [73.172.233.15]) by linux.microsoft.com (Postfix) with ESMTPSA id C416320B490A; Wed, 12 Aug 2020 12:15:32 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com C416320B490A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597259733; bh=xF0mhOijsh/kjeAjnO2uJStDciaP9z2VfWmKbSz/F+Q=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=j0JXZj2XXu+wQLjt7oVyp+NzTln7hSIz5ipRg1uVmnSynU1gsOIOFr1AS1/D072Fa 0M8bnrLnkRnK/ol0doItqKn8F988at+ZVN8Vmv3W2a4pmApXSKhd2c4shGpYDyQtyc Wm77ms5l8h+AI4IGR8jK008s/HxaCdbYD53PY7aE= From: Daniel Burgener To: selinux@vger.kernel.org Cc: stephen.smalley.work@gmail.com, omosnace@redhat.com, paul@paul-moore.com, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk Subject: [PATCH v2 1/4] selinux: Create function for selinuxfs directory cleanup Date: Wed, 12 Aug 2020 15:15:22 -0400 Message-Id: <20200812191525.1120850-2-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200812191525.1120850-1-dburgener@linux.microsoft.com> References: <20200812191525.1120850-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Separating the cleanup from the creation will simplify two things in future patches in this series. First, the creation can be made generic, to create directories not tied to the selinux_fs_info structure. Second, we will ultimately want to reorder creation and deletion so that the deletions aren't performed until the new directory structures have already been moved into place. Signed-off-by: Daniel Burgener --- security/selinux/selinuxfs.c | 41 ++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 131816878e50..fc914facb48f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -355,6 +355,9 @@ static int sel_make_classes(struct selinux_fs_info *fsi, static struct dentry *sel_make_dir(struct dentry *dir, const char *name, unsigned long *ino); +/* declaration for sel_remove_old_policy_nodes */ +static void sel_remove_entries(struct dentry *de); + static ssize_t sel_read_mls(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { @@ -509,11 +512,35 @@ static const struct file_operations sel_policy_ops = { .llseek = generic_file_llseek, }; +static void sel_remove_old_policy_nodes(struct selinux_fs_info *fsi) +{ + u32 i; + + /* bool_dir cleanup */ + for (i = 0; i < fsi->bool_num; i++) + kfree(fsi->bool_pending_names[i]); + kfree(fsi->bool_pending_names); + kfree(fsi->bool_pending_values); + fsi->bool_num = 0; + fsi->bool_pending_names = NULL; + fsi->bool_pending_values = NULL; + + sel_remove_entries(fsi->bool_dir); + + /* class_dir cleanup */ + sel_remove_entries(fsi->class_dir); + + /* policycap_dir cleanup */ + sel_remove_entries(fsi->policycap_dir); +} + static int sel_make_policy_nodes(struct selinux_fs_info *fsi, struct selinux_policy *newpolicy) { int ret; + sel_remove_old_policy_nodes(fsi); + ret = sel_make_bools(fsi, newpolicy); if (ret) { pr_err("SELinux: failed to load policy booleans\n"); @@ -1348,17 +1375,6 @@ static int sel_make_bools(struct selinux_fs_info *fsi, int *values = NULL; u32 sid; - /* remove any existing files */ - for (i = 0; i < fsi->bool_num; i++) - kfree(fsi->bool_pending_names[i]); - kfree(fsi->bool_pending_names); - kfree(fsi->bool_pending_values); - fsi->bool_num = 0; - fsi->bool_pending_names = NULL; - fsi->bool_pending_values = NULL; - - sel_remove_entries(dir); - ret = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) @@ -1873,9 +1889,6 @@ static int sel_make_classes(struct selinux_fs_info *fsi, int rc, nclasses, i; char **classes; - /* delete any existing entries */ - sel_remove_entries(fsi->class_dir); - rc = security_get_classes(newpolicy, &classes, &nclasses); if (rc) return rc; From patchwork Wed Aug 12 19:15:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11711183 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2F1DF13B1 for ; Wed, 12 Aug 2020 19:15:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 169EE208B3 for ; Wed, 12 Aug 2020 19:15:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="IPTNf+AA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726640AbgHLTPg (ORCPT ); Wed, 12 Aug 2020 15:15:36 -0400 Received: from linux.microsoft.com ([13.77.154.182]:49308 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726635AbgHLTPf (ORCPT ); Wed, 12 Aug 2020 15:15:35 -0400 Received: from localhost.localdomain (c-73-172-233-15.hsd1.md.comcast.net [73.172.233.15]) by linux.microsoft.com (Postfix) with ESMTPSA id 99B6220B490D; Wed, 12 Aug 2020 12:15:33 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 99B6220B490D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597259734; bh=h0J5zXRS82FdnJWHfZ2GyfbHIqLimH6f5CETRRANugM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IPTNf+AAB/gHjcp2nEVZ6YE01NMHqQtqWFgNJwZIqNz/7TOAX7osA0GmBz4Nc6Xn0 yxQyzxWltKqjadSD71S8O00cedJjVAV0Z3qBhmEb2s49vO2o77OQi4n80GwzjRV19C L6WkY/oxHDSpefMCYmHlDx66SVcqQtePhVxmuT78= From: Daniel Burgener To: selinux@vger.kernel.org Cc: stephen.smalley.work@gmail.com, omosnace@redhat.com, paul@paul-moore.com, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk Subject: [PATCH v2 2/4] selinux: Refactor selinuxfs directory populating functions Date: Wed, 12 Aug 2020 15:15:23 -0400 Message-Id: <20200812191525.1120850-3-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200812191525.1120850-1-dburgener@linux.microsoft.com> References: <20200812191525.1120850-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Make sel_make_bools and sel_make_classes take the specific elements of selinux_fs_info that they need rather than the entire struct. This will allow a future patch to pass temporary elements that are not in the selinux_fs_info struct to these functions so that the original elements can be preserved until we are ready to perform the switch over. Signed-off-by: Daniel Burgener --- security/selinux/selinuxfs.c | 45 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fc914facb48f..9657c3acfc8f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -346,10 +346,12 @@ static const struct file_operations sel_policyvers_ops = { }; /* declaration for sel_write_load */ -static int sel_make_bools(struct selinux_fs_info *fsi, - struct selinux_policy *newpolicy); -static int sel_make_classes(struct selinux_fs_info *fsi, - struct selinux_policy *newpolicy); +static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir, + unsigned int *bool_num, char ***bool_pending_names, + unsigned int **bool_pending_values); +static int sel_make_classes(struct selinux_policy *newpolicy, + struct dentry *class_dir, + unsigned long *last_class_ino); /* declaration for sel_make_class_dirs */ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, @@ -541,13 +543,15 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi, sel_remove_old_policy_nodes(fsi); - ret = sel_make_bools(fsi, newpolicy); + ret = sel_make_bools(newpolicy, fsi->bool_dir, &fsi->bool_num, + &fsi->bool_pending_names, &fsi->bool_pending_values); if (ret) { pr_err("SELinux: failed to load policy booleans\n"); return ret; } - ret = sel_make_classes(fsi, newpolicy); + ret = sel_make_classes(newpolicy, fsi->class_dir, + &fsi->last_class_ino); if (ret) { pr_err("SELinux: failed to load policy classes\n"); return ret; @@ -1361,13 +1365,13 @@ static void sel_remove_entries(struct dentry *de) #define BOOL_DIR_NAME "booleans" -static int sel_make_bools(struct selinux_fs_info *fsi, - struct selinux_policy *newpolicy) +static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir, + unsigned int *bool_num, char ***bool_pending_names, + unsigned int **bool_pending_values) { int ret; ssize_t len; struct dentry *dentry = NULL; - struct dentry *dir = fsi->bool_dir; struct inode *inode = NULL; struct inode_security_struct *isec; char **names = NULL, *page; @@ -1386,12 +1390,12 @@ static int sel_make_bools(struct selinux_fs_info *fsi, for (i = 0; i < num; i++) { ret = -ENOMEM; - dentry = d_alloc_name(dir, names[i]); + dentry = d_alloc_name(bool_dir, names[i]); if (!dentry) goto out; ret = -ENOMEM; - inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); + inode = sel_make_inode(bool_dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR); if (!inode) { dput(dentry); goto out; @@ -1420,9 +1424,9 @@ static int sel_make_bools(struct selinux_fs_info *fsi, inode->i_ino = i|SEL_BOOL_INO_OFFSET; d_add(dentry, inode); } - fsi->bool_num = num; - fsi->bool_pending_names = names; - fsi->bool_pending_values = values; + *bool_num = num; + *bool_pending_names = names; + *bool_pending_values = values; free_page((unsigned long)page); return 0; @@ -1435,7 +1439,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi, kfree(names); } kfree(values); - sel_remove_entries(dir); + sel_remove_entries(bool_dir); return ret; } @@ -1882,8 +1886,9 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy, return rc; } -static int sel_make_classes(struct selinux_fs_info *fsi, - struct selinux_policy *newpolicy) +static int sel_make_classes(struct selinux_policy *newpolicy, + struct dentry *class_dir, + unsigned long *last_class_ino) { int rc, nclasses, i; @@ -1894,13 +1899,13 @@ static int sel_make_classes(struct selinux_fs_info *fsi, return rc; /* +2 since classes are 1-indexed */ - fsi->last_class_ino = sel_class_to_ino(nclasses + 2); + *last_class_ino = sel_class_to_ino(nclasses + 2); for (i = 0; i < nclasses; i++) { struct dentry *class_name_dir; - class_name_dir = sel_make_dir(fsi->class_dir, classes[i], - &fsi->last_class_ino); + class_name_dir = sel_make_dir(class_dir, classes[i], + last_class_ino); if (IS_ERR(class_name_dir)) { rc = PTR_ERR(class_name_dir); goto out; From patchwork Wed Aug 12 19:15:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11711187 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9B85F17CA for ; Wed, 12 Aug 2020 19:15:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7A1CE2087C for ; Wed, 12 Aug 2020 19:15:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="hOva4hYJ" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726676AbgHLTPg (ORCPT ); Wed, 12 Aug 2020 15:15:36 -0400 Received: from linux.microsoft.com ([13.77.154.182]:49318 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726641AbgHLTPf (ORCPT ); Wed, 12 Aug 2020 15:15:35 -0400 Received: from localhost.localdomain (c-73-172-233-15.hsd1.md.comcast.net [73.172.233.15]) by linux.microsoft.com (Postfix) with ESMTPSA id 66F1C20B490F; Wed, 12 Aug 2020 12:15:34 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 66F1C20B490F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597259735; bh=TWaa5J7FL27uITC423BFjVEEdl8/5m1i6QAGc4Mk748=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hOva4hYJRXvonlUrfkYrNKYzSAFdxngxjLgWb9GRx9nlZRkNv2x77vkzJJXv9fRac sC/4Clc6TfsYiV19d43DzkUgij6dJmT5t3wfhOioXm1nAeSXmMqQDueWm8kIMaAGsT V8HGo5ggoNYz7TWKjVWH6OAsDXz7yYhMD8FzT/0o= From: Daniel Burgener To: selinux@vger.kernel.org Cc: stephen.smalley.work@gmail.com, omosnace@redhat.com, paul@paul-moore.com, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk Subject: [PATCH v2 3/4] selinux: Standardize string literal usage for selinuxfs directory names Date: Wed, 12 Aug 2020 15:15:24 -0400 Message-Id: <20200812191525.1120850-4-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200812191525.1120850-1-dburgener@linux.microsoft.com> References: <20200812191525.1120850-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Switch class and policy_capabilities directory names to be referred to with global constants, consistent with booleans directory name. This will allow for easy consistency of naming in future development. Signed-off-by: Daniel Burgener --- security/selinux/selinuxfs.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 9657c3acfc8f..f09afdb90ddd 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -117,6 +117,10 @@ static void selinux_fs_info_free(struct super_block *sb) #define SEL_POLICYCAP_INO_OFFSET 0x08000000 #define SEL_INO_MASK 0x00ffffff +#define BOOL_DIR_NAME "booleans" +#define CLASS_DIR_NAME "class" +#define POLICYCAP_DIR_NAME "policy_capabilities" + #define TMPBUFLEN 12 static ssize_t sel_read_enforce(struct file *filp, char __user *buf, size_t count, loff_t *ppos) @@ -1363,8 +1367,6 @@ static void sel_remove_entries(struct dentry *de) shrink_dcache_parent(de); } -#define BOOL_DIR_NAME "booleans" - static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_dir, unsigned int *bool_num, char ***bool_pending_names, unsigned int **bool_pending_values) @@ -2080,14 +2082,14 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc) if (ret) goto err; - fsi->class_dir = sel_make_dir(sb->s_root, "class", &fsi->last_ino); + fsi->class_dir = sel_make_dir(sb->s_root, CLASS_DIR_NAME, &fsi->last_ino); if (IS_ERR(fsi->class_dir)) { ret = PTR_ERR(fsi->class_dir); fsi->class_dir = NULL; goto err; } - fsi->policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", + fsi->policycap_dir = sel_make_dir(sb->s_root, POLICYCAP_DIR_NAME, &fsi->last_ino); if (IS_ERR(fsi->policycap_dir)) { ret = PTR_ERR(fsi->policycap_dir); From patchwork Wed Aug 12 19:15:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11711193 X-Patchwork-Delegate: paul@paul-moore.com Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CB46C174A for ; Wed, 12 Aug 2020 19:15:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AEB1B206C3 for ; Wed, 12 Aug 2020 19:15:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="SDI5GfNo" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726678AbgHLTPi (ORCPT ); Wed, 12 Aug 2020 15:15:38 -0400 Received: from linux.microsoft.com ([13.77.154.182]:49332 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726627AbgHLTPg (ORCPT ); Wed, 12 Aug 2020 15:15:36 -0400 Received: from localhost.localdomain (c-73-172-233-15.hsd1.md.comcast.net [73.172.233.15]) by linux.microsoft.com (Postfix) with ESMTPSA id 3242020B4913; Wed, 12 Aug 2020 12:15:35 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 3242020B4913 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597259735; bh=Tenvf2ZFeve+L6GrtHxaPF1KS+dvmSgforU0bSg6Yik=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SDI5GfNoehUYwtHxuHbI88RgD9f5EAMnNqT5JfFkzYkVmVF5qiTdfTYjsszAQSu12 rfd/gvzAVn9DEVZvVxX8EPClcKeFznO5qHbIOwgdpU3ZtDjlkzWh1xFNddABKGHIE6 KLLVBtFR1Afegiow+H3kVMHV8vnykwiPt5tmwQM8= From: Daniel Burgener To: selinux@vger.kernel.org Cc: stephen.smalley.work@gmail.com, omosnace@redhat.com, paul@paul-moore.com, linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk Subject: [PATCH v2 4/4] selinux: Create new booleans and class dirs out of tree Date: Wed, 12 Aug 2020 15:15:25 -0400 Message-Id: <20200812191525.1120850-5-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200812191525.1120850-1-dburgener@linux.microsoft.com> References: <20200812191525.1120850-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org In order to avoid concurrency issues around selinuxfs resource availability during policy load, we first create new directories out of tree for reloaded resources, then swap them in, and finally delete the old versions. This fix focuses on concurrency in each of the three subtrees swapped, and not concurrency across the three trees. This means that it is still possible that subsequent reads to eg the booleans directory and the class directory during a policy load could see the old state for one and the new for the other. The problem of ensuring that policy loads are fully atomic from the perspective of userspace is larger than what is dealt with here. This commit focuses on ensuring that the directories contents always match either the new or the old policy state from the perspective of userspace. In the previous implementation, on policy load /sys/fs/selinux is updated by deleting the previous contents of /sys/fs/selinux/{class,booleans} and then recreating them. This means that there is a period of time when the contents of these directories do not exist which can cause race conditions as userspace relies on them for information about the policy. In addition, it means that error recovery in the event of failure is challenging. In order to demonstrate the race condition that this series fixes, you can use the following commands: while true; do cat /sys/fs/selinux/class/service/perms/status >/dev/null; done & while true; do load_policy; done; In the existing code, this will display errors fairly often as the class lookup fails. (In normal operation from systemd, this would result in a permission check which would be allowed or denied based on policy settings around unknown object classes.) After applying this patch series you should expect to no longer see such error messages. Signed-off-by: Daniel Burgener --- security/selinux/selinuxfs.c | 145 +++++++++++++++++++++++++++++------ 1 file changed, 120 insertions(+), 25 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index f09afdb90ddd..d3a19170210a 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -361,7 +362,11 @@ static int sel_make_classes(struct selinux_policy *newpolicy, static struct dentry *sel_make_dir(struct dentry *dir, const char *name, unsigned long *ino); -/* declaration for sel_remove_old_policy_nodes */ +/* declaration for sel_make_policy_nodes */ +static struct dentry *sel_make_disconnected_dir(struct super_block *sb, + unsigned long *ino); + +/* declaration for sel_make_policy_nodes */ static void sel_remove_entries(struct dentry *de); static ssize_t sel_read_mls(struct file *filp, char __user *buf, @@ -518,50 +523,108 @@ static const struct file_operations sel_policy_ops = { .llseek = generic_file_llseek, }; -static void sel_remove_old_policy_nodes(struct selinux_fs_info *fsi) +static void sel_remove_old_bool_data(unsigned int bool_num, char **bool_names, + unsigned int *bool_values) { u32 i; /* bool_dir cleanup */ - for (i = 0; i < fsi->bool_num; i++) - kfree(fsi->bool_pending_names[i]); - kfree(fsi->bool_pending_names); - kfree(fsi->bool_pending_values); - fsi->bool_num = 0; - fsi->bool_pending_names = NULL; - fsi->bool_pending_values = NULL; - - sel_remove_entries(fsi->bool_dir); - - /* class_dir cleanup */ - sel_remove_entries(fsi->class_dir); - - /* policycap_dir cleanup */ - sel_remove_entries(fsi->policycap_dir); + for (i = 0; i < bool_num; i++) + kfree(bool_names[i]); + kfree(bool_names); + kfree(bool_values); } static int sel_make_policy_nodes(struct selinux_fs_info *fsi, struct selinux_policy *newpolicy) { - int ret; + int ret = 0; + struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_dir, *tmp_policycap_dir, *old_dentry; + unsigned int tmp_bool_num, old_bool_num; + char **tmp_bool_names, **old_bool_names; + unsigned int *tmp_bool_values, *old_bool_values; + + tmp_parent = sel_make_disconnected_dir(fsi->sb, &fsi->last_ino); + if (IS_ERR(tmp_parent)) + return PTR_ERR(tmp_parent); - sel_remove_old_policy_nodes(fsi); + tmp_bool_dir = sel_make_dir(tmp_parent, BOOL_DIR_NAME, &fsi->last_ino); + if (IS_ERR(tmp_bool_dir)) { + ret = PTR_ERR(tmp_bool_dir); + goto out; + } + + tmp_class_dir = sel_make_dir(tmp_parent, CLASS_DIR_NAME, &fsi->last_ino); + if (IS_ERR(tmp_class_dir)) { + ret = PTR_ERR(tmp_class_dir); + goto out; + } + + tmp_policycap_dir = sel_make_dir(tmp_parent, POLICYCAP_DIR_NAME, &fsi->last_ino); + if (IS_ERR(tmp_policycap_dir)) { + ret = PTR_ERR(tmp_policycap_dir); + goto out; + } - ret = sel_make_bools(newpolicy, fsi->bool_dir, &fsi->bool_num, - &fsi->bool_pending_names, &fsi->bool_pending_values); + ret = sel_make_bools(newpolicy, tmp_bool_dir, &tmp_bool_num, + &tmp_bool_names, &tmp_bool_values); if (ret) { pr_err("SELinux: failed to load policy booleans\n"); - return ret; + goto out; } - ret = sel_make_classes(newpolicy, fsi->class_dir, + ret = sel_make_classes(newpolicy, tmp_class_dir, &fsi->last_class_ino); if (ret) { pr_err("SELinux: failed to load policy classes\n"); - return ret; + goto out; } - return 0; + // booleans + old_dentry = fsi->bool_dir; + lock_rename(tmp_bool_dir, old_dentry); + ret = vfs_rename(tmp_parent->d_inode, tmp_bool_dir, fsi->sb->s_root->d_inode, + fsi->bool_dir, NULL, RENAME_EXCHANGE); + if (ret) { + pr_err("Failed to update boolean directory\n"); + unlock_rename(tmp_bool_dir, old_dentry); + goto out; + } + + old_bool_num = fsi->bool_num; + old_bool_names = fsi->bool_pending_names; + old_bool_values = fsi->bool_pending_values; + + fsi->bool_num = tmp_bool_num; + fsi->bool_pending_names = tmp_bool_names; + fsi->bool_pending_values = tmp_bool_values; + + sel_remove_old_bool_data(old_bool_num, old_bool_names, old_bool_values); + + fsi->bool_dir = tmp_bool_dir; + unlock_rename(tmp_bool_dir, old_dentry); + + // classes + old_dentry = fsi->class_dir; + lock_rename(tmp_class_dir, old_dentry); + ret = vfs_rename(tmp_parent->d_inode, tmp_class_dir, fsi->sb->s_root->d_inode, + fsi->class_dir, NULL, RENAME_EXCHANGE); + if (ret) { + pr_err("Failed to update class directory\n"); + unlock_rename(tmp_class_dir, old_dentry); + goto out; + } + fsi->class_dir = tmp_class_dir; + unlock_rename(tmp_class_dir, old_dentry); + +out: + // Since the other temporary dirs are children of tmp_parent + // this will handle all the cleanup in the case of a failure before + // the swapover + sel_remove_entries(tmp_parent); + dput(tmp_parent); // d_genocide() only handles the children + + return ret; } static ssize_t sel_write_load(struct file *file, const char __user *buf, @@ -1984,6 +2047,38 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, return dentry; } +// vfs_rename() requires a rename operation to be defined. +int sel_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + if (!(flags & RENAME_EXCHANGE)) + return -EINVAL; + + return 0; +} + +const struct inode_operations sel_dir_inode_operations = { + .lookup = simple_lookup, + .rename = sel_rename, +}; + +static struct dentry *sel_make_disconnected_dir(struct super_block *sb, + unsigned long *ino) +{ + struct inode *inode = sel_make_inode(sb, S_IFDIR | S_IRUGO | S_IXUGO); + + if (!inode) + return ERR_PTR(-ENOMEM); + + inode->i_op = &sel_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + inode->i_ino = ++(*ino); + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inc_nlink(inode); + return d_obtain_alias(inode); +} + #define NULL_FILE_NAME "null" static int sel_fill_super(struct super_block *sb, struct fs_context *fc)