From patchwork Fri Oct 16 13:48:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11841759 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 EDEF114B2 for ; Fri, 16 Oct 2020 13:48:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C451420897 for ; Fri, 16 Oct 2020 13:48:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="DHlIoR8n" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408418AbgJPNsv (ORCPT ); Fri, 16 Oct 2020 09:48:51 -0400 Received: from linux.microsoft.com ([13.77.154.182]:53638 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408409AbgJPNsv (ORCPT ); Fri, 16 Oct 2020 09:48:51 -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 1E0B720B4907; Fri, 16 Oct 2020 06:48:50 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 1E0B720B4907 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1602856130; bh=r+BR3vI76WcZDNjqS+OVDMPcwfxUrXkhD0IUUjWisCY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DHlIoR8nsvhZ3dPADbvY+V6RKx3/bfJjBc3NGjs16h+WFYMXMASfKy/ftv1/tmvDr onqmYWScqNj9SdYh5pCUJRpl2SjxaCfUQ3xE9uEEp5WCXXHi6xlXbILl5OsPc4exW5 4ouzHos4F2jENc8ghPCZejhfH3gHAea0CRKoA6EI= From: Daniel Burgener To: stable@vger.kernel.org Cc: stephen.smalley.work@gmail.com, paul@paul-moore.com, selinux@vger.kernel.org, jmorris@namei.org, sashal@kernel.org Subject: [PATCH v5.4 v2 1/4] selinux: Create function for selinuxfs directory cleanup Date: Fri, 16 Oct 2020 09:48:32 -0400 Message-Id: <20201016134835.1886478-2-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201016134835.1886478-1-dburgener@linux.microsoft.com> References: <20201016134835.1886478-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org upstream commit aeecf4a3fb11954cb10b8bc57e1661a6e4e9f3a9 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 | 39 +++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index e9eaff90cbcc..092c7295f78d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -348,6 +348,9 @@ static int sel_make_policycap(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) { @@ -502,10 +505,32 @@ 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); + +} + static int sel_make_policy_nodes(struct selinux_fs_info *fsi) { int ret; + sel_remove_old_policy_nodes(fsi); + ret = sel_make_bools(fsi); if (ret) { pr_err("SELinux: failed to load policy booleans\n"); @@ -1336,17 +1361,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) @@ -1798,9 +1812,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(fsi->state, &classes, &nclasses); if (rc) return rc; From patchwork Fri Oct 16 13:48:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11841761 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 7E2EE14B2 for ; Fri, 16 Oct 2020 13:48:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5ED7720848 for ; Fri, 16 Oct 2020 13:48:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="hRx7csBO" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408422AbgJPNsw (ORCPT ); Fri, 16 Oct 2020 09:48:52 -0400 Received: from linux.microsoft.com ([13.77.154.182]:53644 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408409AbgJPNsw (ORCPT ); Fri, 16 Oct 2020 09:48:52 -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 E5FEE20B9C34; Fri, 16 Oct 2020 06:48:50 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com E5FEE20B9C34 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1602856131; bh=WxRrzRxB6Tzhbb5S6Jo+h31cIl/BtlfpCGyDVhikmwY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hRx7csBOtHSnR3fRQKMAppJ6beRi15jsToi7qPeLsVhJYDZFuPFeGFPLx8hrD7rCv D8BVVnwl5SYI1QywhfKScrNBQG/o42tDezBzApHmT8upWHc9/i7jlxznSsx9C0t9uR o/UpelSU1dpA+2vBQyCNFggyTOfDEKhrQOI8/LnU= From: Daniel Burgener To: stable@vger.kernel.org Cc: stephen.smalley.work@gmail.com, paul@paul-moore.com, selinux@vger.kernel.org, jmorris@namei.org, sashal@kernel.org Subject: [PATCH v5.4 v2 2/4] selinux: Refactor selinuxfs directory populating functions Date: Fri, 16 Oct 2020 09:48:33 -0400 Message-Id: <20201016134835.1886478-3-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201016134835.1886478-1-dburgener@linux.microsoft.com> References: <20201016134835.1886478-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org upstream commit 66ec384ad3044d63c9726493a412a2ad5317eae5 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 | 40 +++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 092c7295f78d..ea21f3ef4a6f 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -340,8 +340,11 @@ static const struct file_operations sel_policyvers_ops = { }; /* declaration for sel_write_load */ -static int sel_make_bools(struct selinux_fs_info *fsi); -static int sel_make_classes(struct selinux_fs_info *fsi); +static int sel_make_bools(struct selinux_fs_info *fsi, struct dentry *bool_dir, + unsigned int *bool_num, char ***bool_pending_names, + unsigned int **bool_pending_values); +static int sel_make_classes(struct selinux_fs_info *fsi, struct dentry *class_dir, + unsigned long *last_class_ino); static int sel_make_policycap(struct selinux_fs_info *fsi); /* declaration for sel_make_class_dirs */ @@ -531,13 +534,15 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi) sel_remove_old_policy_nodes(fsi); - ret = sel_make_bools(fsi); + ret = sel_make_bools(fsi, 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); + ret = sel_make_classes(fsi, fsi->class_dir, + &fsi->last_class_ino); if (ret) { pr_err("SELinux: failed to load policy classes\n"); return ret; @@ -1348,12 +1353,13 @@ static void sel_remove_entries(struct dentry *de) #define BOOL_DIR_NAME "booleans" -static int sel_make_bools(struct selinux_fs_info *fsi) +static int sel_make_bools(struct selinux_fs_info *fsi, struct dentry *bool_dir, + unsigned int *bool_num, char ***bool_pending_names, + unsigned int **bool_pending_values) { int i, 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; @@ -1372,12 +1378,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; @@ -1406,9 +1412,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; @@ -1421,7 +1427,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; } @@ -1806,7 +1812,9 @@ static int sel_make_class_dir_entries(char *classname, int index, return rc; } -static int sel_make_classes(struct selinux_fs_info *fsi) +static int sel_make_classes(struct selinux_fs_info *fsi, + struct dentry *class_dir, + unsigned long *last_class_ino) { int rc, nclasses, i; @@ -1817,13 +1825,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 Fri Oct 16 13:48:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11841763 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 B8C441752 for ; Fri, 16 Oct 2020 13:48:53 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9B8F720848 for ; Fri, 16 Oct 2020 13:48:53 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="khczLff8" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408423AbgJPNsx (ORCPT ); Fri, 16 Oct 2020 09:48:53 -0400 Received: from linux.microsoft.com ([13.77.154.182]:53652 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408420AbgJPNsw (ORCPT ); Fri, 16 Oct 2020 09:48:52 -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 B94852090E4E; Fri, 16 Oct 2020 06:48:51 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com B94852090E4E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1602856132; bh=ovyUeHRUrJVB/2XX0dlO2H9mKISmJ1qs+lMXRGhA8nE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=khczLff8+r+jlEKUfwYVWVzOwqVwX9FQhag7BkX9diA9WAWQ895aNOaDHc46BnPPa k4aa6GK8CkRiWRyEvbf830fxWk41+lJlUY2kjHUVjK8fStDdTT8tKefrGKp+8IlLBW phTECAoSXa2aWGHbDBnzFIhVeJb6241HzHhW1Atw= From: Daniel Burgener To: stable@vger.kernel.org Cc: stephen.smalley.work@gmail.com, paul@paul-moore.com, selinux@vger.kernel.org, jmorris@namei.org, sashal@kernel.org Subject: [PATCH v5.4 v2 3/4] selinux: Standardize string literal usage for selinuxfs directory names Date: Fri, 16 Oct 2020 09:48:34 -0400 Message-Id: <20201016134835.1886478-4-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201016134835.1886478-1-dburgener@linux.microsoft.com> References: <20201016134835.1886478-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org upstream commit 613ba18798ac3cf257ecff65d490e8f1aa323588 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 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ea21f3ef4a6f..ae018aaa4391 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) @@ -2000,14 +2004,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 Fri Oct 16 13:48:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Burgener X-Patchwork-Id: 11841765 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 7F6761752 for ; Fri, 16 Oct 2020 13:48:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 554A420866 for ; Fri, 16 Oct 2020 13:48:55 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=linux.microsoft.com header.i=@linux.microsoft.com header.b="a4lXPFBB" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2408420AbgJPNsy (ORCPT ); Fri, 16 Oct 2020 09:48:54 -0400 Received: from linux.microsoft.com ([13.77.154.182]:53664 "EHLO linux.microsoft.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2408424AbgJPNsy (ORCPT ); Fri, 16 Oct 2020 09:48:54 -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 8C3F52090E53; Fri, 16 Oct 2020 06:48:52 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 8C3F52090E53 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1602856133; bh=DeUWgN3yBWalMHQyLzfr8O8D84GQfLjphHJk6/MG+Z0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=a4lXPFBBN5JW0ciABQqI4HtW86z5WLf1mbnDEvDE16DSr2NdLONQlrTnIHH+uuMlZ NBITs8hr9HiPORNnnf9lrOjd2Xt3KqZg/MaXuGgsE9oMZNfBs5V1SgOzFtATx1nE8E 6U8F5X3NyONSWnNj/lX+qjd5tXKIaopCw1v3t9CA= From: Daniel Burgener To: stable@vger.kernel.org Cc: stephen.smalley.work@gmail.com, paul@paul-moore.com, selinux@vger.kernel.org, jmorris@namei.org, sashal@kernel.org Subject: [PATCH v5.4 v2 4/4] selinux: Create new booleans and class dirs out of tree Date: Fri, 16 Oct 2020 09:48:35 -0400 Message-Id: <20201016134835.1886478-5-dburgener@linux.microsoft.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20201016134835.1886478-1-dburgener@linux.microsoft.com> References: <20201016134835.1886478-1-dburgener@linux.microsoft.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org upstream commit 0eea6091539b15572cd278b8d62893c058bdb292 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 two subtrees swapped, and not concurrency between the 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. This has been backported to 5.4 for inclusion in stable. Because prior to this series in the main kernel some refactoring of SELinux policy loading had been done, the backport required changing some function call arguments. The most significant change of note in the backport is as follows: In previous versions of the kernel, on a policy load, three directories in the selinuxfs were recreated: class, booleans and policy_capabilities. Changes to the selinuxfs code after 5.4 but prior to this series removed the recreation of the policy_capabilities code, so that was not modified in this series. For this backport, I left the existing recreation functionality of policy_capabilities intact, modifying only the class and booleans directories, as in the original series. Signed-off-by: Daniel Burgener --- security/selinux/selinuxfs.c | 119 +++++++++++++++++++++++++++-------- 1 file changed, 93 insertions(+), 26 deletions(-) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index ae018aaa4391..3716f49b547d 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -355,7 +356,11 @@ static int sel_make_policycap(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 */ +/* 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, @@ -512,53 +517,101 @@ 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); - + for (i = 0; i < bool_num; i++) + kfree(bool_names[i]); + kfree(bool_names); + kfree(bool_values); } +#define BOOL_DIR_NAME "booleans" + static int sel_make_policy_nodes(struct selinux_fs_info *fsi) { - int ret; + int ret = 0; + struct dentry *tmp_parent, *tmp_bool_dir, *tmp_class_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; + unsigned long tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */ - sel_remove_old_policy_nodes(fsi); + tmp_parent = sel_make_disconnected_dir(fsi->sb, &tmp_ino); + if (IS_ERR(tmp_parent)) + return PTR_ERR(tmp_parent); - ret = sel_make_bools(fsi, fsi->bool_dir, &fsi->bool_num, - &fsi->bool_pending_names, &fsi->bool_pending_values); + tmp_ino = fsi->bool_dir->d_inode->i_ino - 1; /* sel_make_dir will increment and set */ + tmp_bool_dir = sel_make_dir(tmp_parent, BOOL_DIR_NAME, &tmp_ino); + if (IS_ERR(tmp_bool_dir)) { + ret = PTR_ERR(tmp_bool_dir); + goto out; + } + + tmp_ino = fsi->class_dir->d_inode->i_ino - 1; /* sel_make_dir will increment and set */ + tmp_class_dir = sel_make_dir(tmp_parent, CLASS_DIR_NAME, &tmp_ino); + if (IS_ERR(tmp_class_dir)) { + ret = PTR_ERR(tmp_class_dir); + goto out; + } + + ret = sel_make_bools(fsi, 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(fsi, fsi->class_dir, + ret = sel_make_classes(fsi, tmp_class_dir, &fsi->last_class_ino); if (ret) { pr_err("SELinux: failed to load policy classes\n"); - return ret; + goto out; } ret = sel_make_policycap(fsi); if (ret) { pr_err("SELinux: failed to load policy capabilities\n"); - return ret; + goto out; } - return 0; + /* booleans */ + old_dentry = fsi->bool_dir; + lock_rename(tmp_bool_dir, old_dentry); + d_exchange(tmp_bool_dir, fsi->bool_dir); + + 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); + d_exchange(tmp_class_dir, fsi->class_dir); + 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, @@ -1355,8 +1408,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_fs_info *fsi, struct dentry *bool_dir, unsigned int *bool_num, char ***bool_pending_names, unsigned int **bool_pending_values) @@ -1914,6 +1965,22 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, return dentry; } +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 = &simple_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)