All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jonathan Lebon <jlebon@redhat.com>
To: selinux@vger.kernel.org
Cc: Jonathan Lebon <jlebon@redhat.com>
Subject: [PATCH] selinux: allow reading labels before policy is loaded
Date: Sat, 23 May 2020 15:51:31 -0400	[thread overview]
Message-ID: <20200523195130.409607-1-jlebon@redhat.com> (raw)

This patch does for `getxattr` what 3e3e24b4204 did for `setxattr`: it
allows querying the current SELinux label on disk before the policy is
loaded.

One of the motivations described in that commit message also drives this
patch: for Fedora CoreOS (and eventually RHEL CoreOS), we want to be
able to move the root filesystem for example from xfs to ext4, on first
boot, at initrd time.[1]

Because such an operation works at the filesystem level, we need to be
able to read the SELinux labels first from the original root, and apply
them to the files of the new root. Commit 3e3e24b4204 enabled the second
part of this process; this patch enables the first part.

[1] https://github.com/coreos/fedora-coreos-tracker/issues/94

Signed-off-by: Jonathan Lebon <jlebon@redhat.com>
---
 security/selinux/hooks.c | 55 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 50 insertions(+), 5 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 0b4e32161b7..3bbb9966697 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1317,8 +1317,11 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
 	return rc;
 }
 
-static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
-				  u32 def_sid, u32 *sid)
+/* Retrieves the raw context from the fs xattr. Returns 0 on success. */
+static int get_inode_raw_xattr_context(struct inode *inode,
+				       struct dentry *dentry,
+				       char **out_context,
+				       u32 *out_len)
 {
 #define INITCONTEXTLEN 255
 	char *context;
@@ -1354,13 +1357,31 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
 		if (rc != -ENODATA) {
 			pr_warn("SELinux: %s:  getxattr returned %d for dev=%s ino=%ld\n",
 				__func__, -rc, inode->i_sb->s_id, inode->i_ino);
-			return rc;
 		}
+		return rc;
+	}
+
+	*out_len = rc;
+	*out_context = context;
+	return 0;
+}
+
+static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
+				  u32 def_sid, u32 *sid)
+{
+	char *context;
+	u32 size;
+	int rc;
+
+	rc = get_inode_raw_xattr_context(inode, dentry, &context, &size);
+	if (rc < 0) {
+		if (rc != -ENODATA)
+			return rc;
 		*sid = def_sid;
 		return 0;
 	}
 
-	rc = security_context_to_sid_default(&selinux_state, context, rc, sid,
+	rc = security_context_to_sid_default(&selinux_state, context, size, sid,
 					     def_sid, GFP_NOFS);
 	if (rc) {
 		char *dev = inode->i_sb->s_id;
@@ -3333,10 +3354,34 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
 	int error;
 	char *context = NULL;
 	struct inode_security_struct *isec;
+	struct superblock_security_struct *sbsec;
 
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
 		return -EOPNOTSUPP;
 
+	isec = inode_security(inode);
+	sbsec = inode->i_sb->s_security;
+
+	/* Just return the raw context if the policy isn't even loaded since we
+	 * have no way to validate it anyway. This is symmetrical with allowing
+	 * setxattr without a policy. */
+	if (!selinux_state.initialized) {
+		/* See similar code in inode_doinit_with_dentry; for xattrs,
+		 * some filesystems really want a connected inode. If we don't
+		 * find one, just let fallback in case it corresponds to one of
+		 * the default sids. */
+		struct dentry *dentry = d_find_alias(inode);
+		if (!dentry)
+			dentry = d_find_any_alias(inode);
+
+		if (dentry) {
+			error = get_inode_raw_xattr_context(inode, dentry,
+							    &context, &size);
+			dput(dentry);
+			goto out;
+		}
+	}
+
 	/*
 	 * If the caller has CAP_MAC_ADMIN, then get the raw context
 	 * value even if it is not defined by current policy; otherwise,
@@ -3346,7 +3391,6 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
 	 * and lack of permission just means that we fall back to the
 	 * in-core context value, not a denial.
 	 */
-	isec = inode_security(inode);
 	if (has_cap_mac_admin(false))
 		error = security_sid_to_context_force(&selinux_state,
 						      isec->sid, &context,
@@ -3354,6 +3398,7 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
 	else
 		error = security_sid_to_context(&selinux_state, isec->sid,
 						&context, &size);
+out:
 	if (error)
 		return error;
 	error = size;
-- 
2.25.4


             reply	other threads:[~2020-05-23 19:56 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-23 19:51 Jonathan Lebon [this message]
2020-05-25 17:14 ` [PATCH] selinux: allow reading labels before policy is loaded Ondrej Mosnacek
2020-05-26 19:12   ` Jonathan Lebon
2020-05-27  8:23     ` Ondrej Mosnacek
2020-05-27 13:37       ` Stephen Smalley
2020-05-26 20:20   ` Jonathan Lebon
2020-05-27 22:06 Jonathan Lebon
2020-05-27 22:11 ` Jonathan Lebon
2020-05-28 13:42 ` Stephen Smalley
2020-05-28 14:58   ` Jonathan Lebon

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=20200523195130.409607-1-jlebon@redhat.com \
    --to=jlebon@redhat.com \
    --cc=selinux@vger.kernel.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.