All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
To: <paul@paul-moore.com>
Cc: <alexander.kozhevnikov@huawei.com>, <artem.kuzin@huawei.com>,
	<hw.likun@huawei.com>, <igor.baranov@huawei.com>,
	<jamorris@linux.microsoft.com>,
	<linux-security-module@vger.kernel.org>,
	<selinux@vger.kernel.org>, <stephen.smalley.work@gmail.com>,
	<xiujianfeng@huawei.com>, <yusongping@huawei.com>,
	<anton.sirazetdinov@huawei.com>
Subject: [RFC PATCH 2/7] selinux: support per-namespace superblock security structures
Date: Mon, 18 Apr 2022 17:45:47 +0800	[thread overview]
Message-ID: <20220418094552.128898-3-alexander.kozhevnikov@huawei.com> (raw)
In-Reply-To: <20220418094552.128898-1-alexander.kozhevnikov@huawei.com>

From: Igor Baranov <igor.baranov@huawei.com>

This port of commit
https://github.com/stephensmalley/selinux-kernel/commit/3378718ef7d4a837f32c63bdfcc0b70342cdd55d
Rebased to working-selinuxns and refactored.

Extend the superblock security structure to include a reference
to the associated selinux namespace, and turn it into a list so
that we can maintain per-superblock security state for each namespace.
This is necessary because the superblock SIDs and labeling behavior
are per selinux namespace.  It further enables one to context-mount
a filesystem with a particular context in one namespace while using
xattrs in another, e.g. one might context mount a container filesystem
in the init selinux namespace to provide MCS-style isolation of the
containers while using per-file xattrs within the container to support
conventional SELinux targeted policy.

Introduce a superblock_security() helper to return the superblock
security blob for the current selinux namespace and replace direct uses
of sb->s_security with calls to it.

Also revert the changes made by
commit a64c54cf0811b8032fdab8c9d52576f0370837fa ("SELinux: pass a
superblock to security_fs_use") so that access to the superblock
security structure is properly encapsulated and we can support
per-namespace structures.

This change has similar problems as with the inode security structure
change, see the list of issues in that commit.

Not-signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c            | 90 ++++++++++++++++++++++++++---
 security/selinux/include/objsec.h   | 20 ++++++-
 security/selinux/include/security.h |  3 +-
 security/selinux/ss/services.c      | 19 +++---
 4 files changed, 112 insertions(+), 20 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 8d88b6bec24b..a1716ce534dd 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -613,7 +613,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 {
 	const struct cred *cred = current_cred();
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
-	struct dentry *root = sbsec->sb->s_root;
+	struct dentry *root = sb->s_root;
 	struct selinux_mnt_opts *opts = mnt_opts;
 	struct inode_security_struct *root_isec;
 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
@@ -730,7 +730,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 		 * Determine the labeling behavior to use for this
 		 * filesystem type.
 		 */
-		rc = security_fs_use(current_selinux_state, sb);
+		rc = security_fs_use(current_selinux_state, sb->s_type->name,
+				     &sbsec->behavior, &sbsec->sid);
 		if (rc) {
 			pr_warn("%s: security_fs_use(%s) returned %d\n",
 					__func__, sb->s_type->name, rc);
@@ -924,7 +925,8 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 
 	if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
 		!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
-		rc = security_fs_use(current_selinux_state, newsb);
+		rc = security_fs_use(current_selinux_state, newsb->s_type->name,
+				     &newsbsec->behavior, &newsbsec->sid);
 		if (rc)
 			goto out;
 	}
@@ -1094,7 +1096,7 @@ static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
 			return rc;
 	}
 	if (sbsec->flags & ROOTCONTEXT_MNT) {
-		struct dentry *root = sbsec->sb->s_root;
+		struct dentry *root = sb->s_root;
 		struct inode_security_struct *isec = backing_inode_security(root);
 		seq_putc(m, ',');
 		seq_puts(m, ROOTCONTEXT_STR);
@@ -2564,21 +2566,94 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 
 /* superblock security operations */
 
-static int selinux_sb_alloc_security(struct super_block *sb)
+static void sbsec_head_init(struct super_block *sb,
+			    struct superblock_security_head *sbsech)
 {
-	struct superblock_security_struct *sbsec = selinux_superblock(sb);
+	INIT_LIST_HEAD(&sbsech->head);
+	spin_lock_init(&sbsech->lock);
+}
 
+static struct superblock_security_struct *
+sbsec_alloc(struct superblock_security_head *sbsech)
+{
+	struct superblock_security_struct *sbsec;
+
+	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_NOFS);
+	if (!sbsec)
+		return NULL;
 	mutex_init(&sbsec->lock);
 	INIT_LIST_HEAD(&sbsec->isec_head);
 	spin_lock_init(&sbsec->isec_lock);
-	sbsec->sb = sb;
+	sbsec->sbsech = sbsech;
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
+	sbsec->state = get_selinux_state(current_selinux_state);
+
+	return sbsec;
+}
+
+struct superblock_security_struct *
+find_sbsec(struct superblock_security_head *sbsech)
+{
+	struct superblock_security_struct *cur, *new;
+
+	cur = container_of(sbsech->head.next, struct superblock_security_struct, sbsec_list);
+	if (cur->state == current_selinux_state)
+		return cur;
 
+	spin_lock(&sbsech->lock);
+	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
+		if (cur->state == current_selinux_state)
+			goto unlock;
+	}
+	spin_unlock(&sbsech->lock);
+
+	new = sbsec_alloc(sbsech);
+	if (!new) {
+		cur = NULL;
+		goto out;
+	}
+
+	spin_lock(&sbsech->lock);
+	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
+		if (cur->state == current_selinux_state)
+			goto unlock;
+	}
+	list_add(&new->sbsec_list, &sbsech->head);
+	cur = new;
+unlock:
+	spin_unlock(&sbsech->lock);
+out:
+	return cur;
+}
+
+static int selinux_sb_alloc_security(struct super_block *sb)
+{
+	struct superblock_security_struct *sbsec;
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(sb);
+
+	sbsec_head_init(sb, sbsech);
+	sbsec = sbsec_alloc(sbsech);
+	if (!sbsec)
+		return -ENOMEM;
+	spin_lock(&sbsech->lock);
+	list_add(&sbsec->sbsec_list, &sbsech->head);
+	spin_unlock(&sbsech->lock);
 	return 0;
 }
 
+static void selinux_sb_free_security(struct super_block *sb)
+{
+	struct superblock_security_struct *entry, *tmp;
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(sb);
+
+	list_for_each_entry_safe(entry, tmp, &sbsech->head, sbsec_list) {
+		put_selinux_state(entry->state);
+		kfree(entry);
+	}
+}
+
 static inline int opt_len(const char *s)
 {
 	bool open_quote = false;
@@ -7224,6 +7299,7 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 		      selinux_msg_queue_alloc_security),
 	LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
+	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
 	LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
 	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index f456bb5782a3..6ad1db45b0d9 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -51,8 +51,13 @@ struct file_security_struct {
 	u32 pseqno;		/* Policy seqno at the time of file open */
 };
 
+struct superblock_security_head {
+	struct list_head head;		/* list head of superblock_security_struct */
+	spinlock_t lock;
+};
+
 struct superblock_security_struct {
-	struct super_block *sb;		/* back pointer to sb object */
+	struct superblock_security_head *sbsech;	/* back pointer to superbock_security_head */
 	u32 sid;			/* SID of file system superblock */
 	u32 def_sid;			/* default SID for labeling */
 	u32 mntpoint_sid;		/* SECURITY_FS_USE_MNTPOINT context for files */
@@ -61,6 +66,8 @@ struct superblock_security_struct {
 	struct mutex lock;
 	struct list_head isec_head;
 	spinlock_t isec_lock;
+	struct selinux_state *state;	/* pointer to selinux_state */
+	struct list_head sbsec_list;
 };
 
 struct msg_security_struct {
@@ -176,10 +183,19 @@ static inline u32 current_sid(void)
 	return tsec->sid;
 }
 
-static inline struct superblock_security_struct *selinux_superblock(
+static inline struct superblock_security_head *selinux_head_of_superblock(
 					const struct super_block *superblock)
 {
 	return superblock->s_security + selinux_blob_sizes.lbs_superblock;
 }
 
+extern struct superblock_security_struct *
+find_sbsec(struct superblock_security_head *sbsech);
+
+static inline struct superblock_security_struct *selinux_superblock(
+					const struct super_block *superblock)
+{
+	return find_sbsec(selinux_head_of_superblock(superblock));
+}
+
 #endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 1a7d76f0faf3..a5b698aae38c 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -410,7 +410,8 @@ int security_get_allow_unknown(struct selinux_state *state);
 #define SECURITY_FS_USE_NATIVE		7 /* use native label support */
 #define SECURITY_FS_USE_MAX		7 /* Highest SECURITY_FS_USE_XXX */
 
-int security_fs_use(struct selinux_state *state, struct super_block *sb);
+int security_fs_use(struct selinux_state *state, const char *fstype,
+		    unsigned short *behavior, u32 *sid);
 
 int security_genfs_sid(struct selinux_state *state,
 		       const char *fstype, char *name, u16 sclass,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2c9e77ca4754..548acdecafa8 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2868,19 +2868,18 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy,
  * security_fs_use - Determine how to handle labeling for a filesystem.
  * @sb: superblock in question
  */
-int security_fs_use(struct selinux_state *state, struct super_block *sb)
+int security_fs_use(struct selinux_state *state, const char *fstype,
+		    unsigned short *behavior, u32 *sid)
 {
 	struct selinux_policy *policy;
 	struct policydb *policydb;
 	struct sidtab *sidtab;
 	int rc = 0;
 	struct ocontext *c;
-	struct superblock_security_struct *sbsec = selinux_superblock(sb);
-	const char *fstype = sb->s_type->name;
 
 	if (!selinux_initialized(state)) {
-		sbsec->behavior = SECURITY_FS_USE_NONE;
-		sbsec->sid = SECINITSID_UNLABELED;
+		*behavior = SECURITY_FS_USE_NONE;
+		*sid = SECINITSID_UNLABELED;
 		return 0;
 	}
 
@@ -2897,22 +2896,22 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
 	}
 
 	if (c) {
-		sbsec->behavior = c->v.behavior;
+		*behavior = c->v.behavior;
 		if (!c->sid[0]) {
 			rc = sidtab_context_to_sid(sidtab, &c->context[0],
 						   &c->sid[0]);
 			if (rc)
 				goto out;
 		}
-		sbsec->sid = c->sid[0];
+		*sid = c->sid[0];
 	} else {
 		rc = __security_genfs_sid(policy, fstype, "/",
-					SECCLASS_DIR, &sbsec->sid);
+					SECCLASS_DIR, sid);
 		if (rc) {
-			sbsec->behavior = SECURITY_FS_USE_NONE;
+			*behavior = SECURITY_FS_USE_NONE;
 			rc = 0;
 		} else {
-			sbsec->behavior = SECURITY_FS_USE_GENFS;
+			*behavior = SECURITY_FS_USE_GENFS;
 		}
 	}
 
-- 
2.34.1


  parent reply	other threads:[~2022-04-18  9:46 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <22c0d7a1-b658-64ce-f099-0b3617ef8e38@huawei.com>
     [not found] ` <CAEjxPJ5-w83HMRGuDHHqMthkju3bxT0gZ-EiiTE=t5UhQqQ_ug@mail.gmail.com>
2021-07-19 13:54   ` issues about selinux namespace xiujianfeng
2021-07-20  2:56     ` Paul Moore
2021-07-21 13:12       ` xiujianfeng
2022-02-16 12:52       ` [RFC PATCH 0/1] SELinux-namespaces Igor Baranov
2022-02-16 12:52         ` [RFC PATCH 1/1] selinuxns: Replace state pointer with namespace id Igor Baranov
2022-02-16 17:08         ` [RFC PATCH 0/1] SELinux-namespaces Casey Schaufler
2022-02-16 20:47         ` Paul Moore
2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
2022-04-18  9:45             ` [RFC PATCH 1/7] LSM: Infrastructure management of the superblock Alexander Kozhevnikov
2022-04-18  9:45             ` Alexander Kozhevnikov [this message]
2022-04-18  9:45             ` [RFC PATCH 3/7] SELINUXNS: Fix initilization of the superblock security under spinlock Alexander Kozhevnikov
2022-04-18  9:45             ` [RFC PATCH 4/7] SELINUXNS: Namespacing for xattrs Alexander Kozhevnikov
2022-04-18  9:45             ` [RFC PATCH 5/7] SELINUXNS: Migrate all open files and all vma to new namespace Alexander Kozhevnikov
2022-04-18  9:45             ` [RFC PATCH 6/7] SELINUXNS: Fixing superblock security structure memory leakage Alexander Kozhevnikov
2022-04-18  9:45             ` [RFC PATCH 7/7] SELINUXNS: Fixing concurrency issues Alexander Kozhevnikov

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=20220418094552.128898-3-alexander.kozhevnikov@huawei.com \
    --to=alexander.kozhevnikov@huawei.com \
    --cc=anton.sirazetdinov@huawei.com \
    --cc=artem.kuzin@huawei.com \
    --cc=hw.likun@huawei.com \
    --cc=igor.baranov@huawei.com \
    --cc=jamorris@linux.microsoft.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=paul@paul-moore.com \
    --cc=selinux@vger.kernel.org \
    --cc=stephen.smalley.work@gmail.com \
    --cc=xiujianfeng@huawei.com \
    --cc=yusongping@huawei.com \
    /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.