[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250520120000.25501-44-stephen.smalley.work@gmail.com>
Date: Tue, 20 May 2025 07:59:40 -0400
From: Stephen Smalley <stephen.smalley.work@...il.com>
To: selinux@...r.kernel.org
Cc: paul@...l-moore.com,
omosnace@...hat.com,
netdev@...r.kernel.org,
Stephen Smalley <stephen.smalley.work@...il.com>
Subject: [PATCH v3 42/42] selinux: init inode from nearest initialized namespace
Previously inode_doinit_with_dentry() was only checking sbsec->flags
to see if it should defer the inode security blob initialization,
which was fine when there was only a single SELinux state/namespace
since that could only be set if the state was initialized. However,
with the introduction of SELinux namespaces, the superblock could be
initialized in the parent (or other ancestor) namespace but the
current namespace may not yet be initialized (i.e. the namespace was
unshared but no policy has yet been loaded into it). Check for this
case, and if uninitialized, find the nearest ancestor SELinux
namespace that is initialized and use it instead. In the case where
the init SELinux namespace was never initialized (i.e. no policy
loaded on the host), then defer initialization of the inode.
Signed-off-by: Stephen Smalley <stephen.smalley.work@...il.com>
---
security/selinux/hooks.c | 45 +++++++++++++++++------------
security/selinux/include/security.h | 6 ++--
2 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index dcb97a636aa2..06a5ffaebafd 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1332,10 +1332,9 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_SOCKET;
}
-static int selinux_genfs_get_sid(struct dentry *dentry,
- u16 tclass,
- u16 flags,
- u32 *sid)
+static int selinux_genfs_get_sid(struct selinux_state *state,
+ struct dentry *dentry, u16 tclass,
+ u16 flags, u32 *sid)
{
int rc;
struct super_block *sb = dentry->d_sb;
@@ -1358,8 +1357,8 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++;
}
}
- rc = security_genfs_sid(current_selinux_state, sb->s_type->name,
- path, tclass, sid);
+ rc = security_genfs_sid(state, sb->s_type->name, path,
+ tclass, sid);
if (rc == -ENOENT) {
/* No match in policy, mark as unlabeled. */
*sid = SECINITSID_UNLABELED;
@@ -1370,7 +1369,9 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
return rc;
}
-static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
+static int inode_doinit_use_xattr(struct selinux_state *state,
+ struct inode *inode,
+ struct dentry *dentry,
u32 def_sid, u32 *sid)
{
#define INITCONTEXTLEN 255
@@ -1413,8 +1414,8 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
return 0;
}
- rc = security_context_to_sid_default(current_selinux_state, context, rc,
- sid, def_sid, GFP_NOFS);
+ rc = security_context_to_sid_default(state, context, rc, sid,
+ def_sid, GFP_NOFS);
if (rc) {
char *dev = inode->i_sb->s_id;
unsigned long ino = inode->i_ino;
@@ -1434,6 +1435,7 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
/* The inode's security attributes must be initialized before first use. */
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
{
+ struct selinux_state *state = current_selinux_state;
struct superblock_security_struct *sbsec = NULL;
struct inode_security_struct *isec = selinux_inode(inode);
u32 task_sid, sid = 0;
@@ -1451,8 +1453,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (isec->sclass == SECCLASS_FILE)
isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ /*
+ * Find an initialized state to use.
+ */
+ while (state && !selinux_initialized(state))
+ state = state->parent;
+
sbsec = selinux_superblock(inode->i_sb);
- if (!(sbsec->flags & SE_SBINITIALIZED)) {
+ if (!state || !(sbsec->flags & SE_SBINITIALIZED)) {
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
@@ -1509,8 +1517,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_invalid;
}
- rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
- &sid);
+ rc = inode_doinit_use_xattr(state, inode, dentry,
+ sbsec->def_sid, &sid);
dput(dentry);
if (rc)
goto out;
@@ -1523,8 +1531,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid;
/* Try to obtain a transition SID. */
- rc = security_transition_sid(current_selinux_state, task_sid, sid,
- sclass, NULL, &sid);
+ rc = security_transition_sid(state, task_sid, sid, sclass,
+ NULL, &sid);
if (rc)
goto out;
break;
@@ -1537,7 +1545,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if ((sbsec->flags & SE_SBGENFS) &&
(!S_ISLNK(inode->i_mode) ||
- selinux_policycap_genfs_seclabel_symlinks())) {
+ selinux_policycap_genfs_seclabel_symlinks(state))) {
/* We must have a dentry to determine the label on
* procfs inodes */
if (opt_dentry) {
@@ -1564,7 +1572,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
*/
if (!dentry)
goto out_invalid;
- rc = selinux_genfs_get_sid(dentry, sclass,
+ rc = selinux_genfs_get_sid(state, dentry, sclass,
sbsec->flags, &sid);
if (rc) {
dput(dentry);
@@ -1573,8 +1581,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if ((sbsec->flags & SE_SBGENFS_XATTR) &&
(inode->i_opflags & IOP_XATTR)) {
- rc = inode_doinit_use_xattr(inode, dentry,
- sid, &sid);
+ rc = inode_doinit_use_xattr(state, inode,
+ dentry, sid,
+ &sid);
if (rc) {
dput(dentry);
goto out;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index a9ef6d97b88d..22de64287b4d 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -259,11 +259,11 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void)
->policycap[POLICYDB_CAP_NNP_NOSUID_TRANSITION]);
}
-static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
+static inline bool
+selinux_policycap_genfs_seclabel_symlinks(struct selinux_state *state)
{
return READ_ONCE(
- current_selinux_state
- ->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
+ state->policycap[POLICYDB_CAP_GENFS_SECLABEL_SYMLINKS]);
}
static inline bool selinux_policycap_ioctl_skip_cloexec(void)
--
2.49.0
Powered by blists - more mailing lists