selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: issues about selinux namespace
       [not found] ` <CAEjxPJ5-w83HMRGuDHHqMthkju3bxT0gZ-EiiTE=t5UhQqQ_ug@mail.gmail.com>
@ 2021-07-19 13:54   ` xiujianfeng
  2021-07-20  2:56     ` Paul Moore
  0 siblings, 1 reply; 15+ messages in thread
From: xiujianfeng @ 2021-07-19 13:54 UTC (permalink / raw)
  To: Stephen Smalley, jamorris; +Cc: Likun(OSLab), linux-security-module, selinux

thanks stepthen,  I've found James's patch in 
https://lwn.net/Articles/737949/,

but it seems can't resolve my questions, so any futher discussion would 
be helpfull and welcome.

在 2021/7/14 20:11, Stephen Smalley 写道:
> Please take your email to the selinux@vger.kernel.org. You are the
> second person to ask about selinux namespaces within the past week or
> so. I did upstream the refactoring and encapsulation of the data
> structures and code via the selinux_state patches, so those are in the
> mainline kernel these days, and Paul Moore and I have periodically
> re-based the remaining patches on top of upstream over in the
> https://github.com/SELinuxProject/selinux-kernel/tree/working-selinuxns
> branch. However, I had to drop the inode and superblock per-ns patches
> temporarily because of changes to LSM (inode blob management moved to
> the LSM framework out of the security modules), so that would need to
> be revisited. There was a separate patch from James Morris to support
> per-namespace security.selinux extended attributes; you can dig that
> out from the history or mailing lists if you want to revive that. I
> won't be able to look at it again until October at the earliest.
>
> On Wed, Jul 14, 2021 at 6:54 AM xiujianfeng <xiujianfeng@huawei.com> wrote:
>> Hi Stephen,
>>
>> I am writing to discuss about selinux namespace because I found your
>> previous work on github and I think selinux namespace is helpful to
>> harden container security. So I try to do further work but there are
>> some issues mentioned in the commit message and I have no idea how to
>> fix them, it would be great if I can get help from you.
>> First is about selinux hook functions, we need to update each hook to
>> perform its processing on current namespace and all of its ancestors,
>> for object, we can have different sid/tag in different namespace based
>> on inode namespace support, but for task, do we need to maintain each
>> security context generated in the corresponding namespace?
>> Second is the lifecycle management of on-disk inode labels. it's not
>> easy to handle this, should we clean all corresponding labels on disk
>> when namespace exit? if we do this, it may cost long time to iterate
>> inode on disk and must relabel files when container restart, if not, the
>> inode xattr space maybe full and cannot write label again when new
>> namespace starts.
>> BTW, do you have plan to finish the work?
>>
>> I look forward to receiving your reply.
>>
>> Best wishes.
> .

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: issues about selinux namespace
  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
  0 siblings, 2 replies; 15+ messages in thread
From: Paul Moore @ 2021-07-20  2:56 UTC (permalink / raw)
  To: xiujianfeng
  Cc: Stephen Smalley, jamorris, Likun(OSLab), linux-security-module, selinux

On Mon, Jul 19, 2021 at 9:55 AM xiujianfeng <xiujianfeng@huawei.com> wrote:
>
> thanks stepthen,  I've found James's patch in
> https://lwn.net/Articles/737949/,
>
> but it seems can't resolve my questions, so any futher discussion would
> be helpfull and welcome.
>
> 在 2021/7/14 20:11, Stephen Smalley 写道:
> > Please take your email to the selinux@vger.kernel.org. You are the
> > second person to ask about selinux namespaces within the past week or
> > so. I did upstream the refactoring and encapsulation of the data
> > structures and code via the selinux_state patches, so those are in the
> > mainline kernel these days, and Paul Moore and I have periodically
> > re-based the remaining patches on top of upstream over in the
> > https://github.com/SELinuxProject/selinux-kernel/tree/working-selinuxns
> > branch. However, I had to drop the inode and superblock per-ns patches
> > temporarily because of changes to LSM (inode blob management moved to
> > the LSM framework out of the security modules), so that would need to
> > be revisited. There was a separate patch from James Morris to support
> > per-namespace security.selinux extended attributes; you can dig that
> > out from the history or mailing lists if you want to revive that. I
> > won't be able to look at it again until October at the earliest.
> >
> > On Wed, Jul 14, 2021 at 6:54 AM xiujianfeng <xiujianfeng@huawei.com> wrote:
> >> Hi Stephen,
> >>
> >> I am writing to discuss about selinux namespace because I found your
> >> previous work on github and I think selinux namespace is helpful to
> >> harden container security. So I try to do further work but there are
> >> some issues mentioned in the commit message and I have no idea how to
> >> fix them, it would be great if I can get help from you.
> >> First is about selinux hook functions, we need to update each hook to
> >> perform its processing on current namespace and all of its ancestors,
> >> for object, we can have different sid/tag in different namespace based
> >> on inode namespace support, but for task, do we need to maintain each
> >> security context generated in the corresponding namespace?
> >> Second is the lifecycle management of on-disk inode labels. it's not
> >> easy to handle this, should we clean all corresponding labels on disk
> >> when namespace exit? if we do this, it may cost long time to iterate
> >> inode on disk and must relabel files when container restart, if not, the
> >> inode xattr space maybe full and cannot write label again when new
> >> namespace starts.
> >> BTW, do you have plan to finish the work?
> >>
> >> I look forward to receiving your reply.
> >>
> >> Best wishes.

I understand that many mail clients do not encourage inline/bottom
replies, but when posting to the various Linux Kernel mailing lists
please make the effort to reply inline, or at the bottom, as
appropriate.

Namespacing the SELinux kernel code is a rather tricky thing, both
with respect to the design and the mechanics of the implementation.  I
don't think we have a concrete idea yet on how we want to proceed in
all of the areas mentioned; designs - and implementations - have been
offered, but I think we are missing someone to drive the topic forward
with demonstrations, sample implementations, etc.  It is never a bad
idea to ask how you can help a project, but in this case I think the
answer is to step back for a moment, describe your use-case/problem,
explain how you envision a namespaced SELinux helping you resolve
this, and finally how you would want the namespaced SELinux
implementation to work (how would you interact with it both via policy
and runtime management).

On a personal note, the regular rebasing of the SELinux namespace work
has suffered lately due to other time commitments at work.  I have
recently (today) started a new position which should allow me to
dedicate much more of my working hours to upstream development; it may
take me a couple of weeks to get settled in, but you can expect the
regular rebasing of selinux/working-selinuxns to resume in the future.

-- 
paul moore
www.paul-moore.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: issues about selinux namespace
  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
  1 sibling, 0 replies; 15+ messages in thread
From: xiujianfeng @ 2021-07-21 13:12 UTC (permalink / raw)
  To: Paul Moore
  Cc: Stephen Smalley, jamorris, Likun(OSLab), linux-security-module, selinux


在 2021/7/20 10:56, Paul Moore 写道:
> On Mon, Jul 19, 2021 at 9:55 AM xiujianfeng <xiujianfeng@huawei.com> wrote:
>> thanks stepthen,  I've found James's patch in
>> https://lwn.net/Articles/737949/,
>>
>> but it seems can't resolve my questions, so any futher discussion would
>> be helpfull and welcome.
>>
>> 在 2021/7/14 20:11, Stephen Smalley 写道:
>>> Please take your email to the selinux@vger.kernel.org. You are the
>>> second person to ask about selinux namespaces within the past week or
>>> so. I did upstream the refactoring and encapsulation of the data
>>> structures and code via the selinux_state patches, so those are in the
>>> mainline kernel these days, and Paul Moore and I have periodically
>>> re-based the remaining patches on top of upstream over in the
>>> https://github.com/SELinuxProject/selinux-kernel/tree/working-selinuxns
>>> branch. However, I had to drop the inode and superblock per-ns patches
>>> temporarily because of changes to LSM (inode blob management moved to
>>> the LSM framework out of the security modules), so that would need to
>>> be revisited. There was a separate patch from James Morris to support
>>> per-namespace security.selinux extended attributes; you can dig that
>>> out from the history or mailing lists if you want to revive that. I
>>> won't be able to look at it again until October at the earliest.
>>>
>>> On Wed, Jul 14, 2021 at 6:54 AM xiujianfeng <xiujianfeng@huawei.com> wrote:
>>>> Hi Stephen,
>>>>
>>>> I am writing to discuss about selinux namespace because I found your
>>>> previous work on github and I think selinux namespace is helpful to
>>>> harden container security. So I try to do further work but there are
>>>> some issues mentioned in the commit message and I have no idea how to
>>>> fix them, it would be great if I can get help from you.
>>>> First is about selinux hook functions, we need to update each hook to
>>>> perform its processing on current namespace and all of its ancestors,
>>>> for object, we can have different sid/tag in different namespace based
>>>> on inode namespace support, but for task, do we need to maintain each
>>>> security context generated in the corresponding namespace?
>>>> Second is the lifecycle management of on-disk inode labels. it's not
>>>> easy to handle this, should we clean all corresponding labels on disk
>>>> when namespace exit? if we do this, it may cost long time to iterate
>>>> inode on disk and must relabel files when container restart, if not, the
>>>> inode xattr space maybe full and cannot write label again when new
>>>> namespace starts.
>>>> BTW, do you have plan to finish the work?
>>>>
>>>> I look forward to receiving your reply.
>>>>
>>>> Best wishes.
> I understand that many mail clients do not encourage inline/bottom
> replies, but when posting to the various Linux Kernel mailing lists
> please make the effort to reply inline, or at the bottom, as
> appropriate.
>
> Namespacing the SELinux kernel code is a rather tricky thing, both
> with respect to the design and the mechanics of the implementation.  I
> don't think we have a concrete idea yet on how we want to proceed in
> all of the areas mentioned; designs - and implementations - have been
> offered, but I think we are missing someone to drive the topic forward
> with demonstrations, sample implementations, etc.  It is never a bad
> idea to ask how you can help a project, but in this case I think the
> answer is to step back for a moment, describe your use-case/problem,
> explain how you envision a namespaced SELinux helping you resolve
> this, and finally how you would want the namespaced SELinux
> implementation to work (how would you interact with it both via policy
> and runtime management).

thanks for you reply, I digged the history disscussion from 
https://marc.info/?l=selinux&m=150696042210126&w=2

and find one use-case: Running multiple android instances on a single 
host, this is the same as mine.

Anyway, I'll make a try.

>
> On a personal note, the regular rebasing of the SELinux namespace work
> has suffered lately due to other time commitments at work.  I have
> recently (today) started a new position which should allow me to
> dedicate much more of my working hours to upstream development; it may
> take me a couple of weeks to get settled in, but you can expect the
> regular rebasing of selinux/working-selinuxns to resume in the future.
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 0/1] SELinux-namespaces
  2021-07-20  2:56     ` Paul Moore
  2021-07-21 13:12       ` xiujianfeng
@ 2022-02-16 12:52       ` Igor Baranov
  2022-02-16 12:52         ` [RFC PATCH 1/1] selinuxns: Replace state pointer with namespace id Igor Baranov
                           ` (2 more replies)
  1 sibling, 3 replies; 15+ messages in thread
From: Igor Baranov @ 2022-02-16 12:52 UTC (permalink / raw)
  To: paul
  Cc: hw.likun, jamorris, linux-security-module, selinux,
	stephen.smalley.work, xiujianfeng, alexander.kozhevnikov,
	yusongping, artem.kuzin, Igor Baranov

Hi all!
Our team at Huawei decided to revive the work on SELinux namespaces.
We took https://github.com/stephensmalley/selinux-kernel/tree/working-selinuxns
as a basis with some patches from selinuxns-xattr.
We reworked them significantly, fixing and adding functionality.
As a result we managed to run a CentOS Docker container with SELinux in enforcing mode!

We would like to start our discussion with the smallest, but most basic
change: we gave each namespace a unique identifier.
It is assigned to a namespace from the global counter
that is incremented each time you create it.

All the objects which in the original patchset kept a pointer to their
namespace now store its identifier. It's needed only to determine whether
an object belongs to our (in the current context) namespace or not.
The aim of this change is to reduce the height of the Babel tower of pointers,
because in the original patch there was such a mess and such bugs,
that we decided to cut this Gordian knot, removing some pointers altogether.

This is a very small part of our changes, but we see the point of discussing
more when we come to this.

Particularly because there are alternative approaches,
such as Casey Schaufler's suggestion, which is mentioned
in http://namei.org/presentations/selinux_namespacing_lca2018.pdf
"How to deal with secids (32-bit IDs) which are passed to core kernel and
cached there - Make them global" which seems quite promising for us too.
In the case of this approach, it is not necessary to store the namespace ID
in objects, because it can be deduced from sid. But a detailed study of
this area reveals some painful challenges. For example: fragmentation of
the global sid space when loading/unloading different policies. And the
depth of the rabbit hole is not obvious from current positions. This is a
separate big topic.

Igor Baranov (1):
  Replace state pointer with namespace id

 security/selinux/hooks.c            | 29 ++++++++++++++++++++++++-----
 security/selinux/include/objsec.h   |  4 +++-
 security/selinux/include/security.h |  2 ++
 3 files changed, 29 insertions(+), 6 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 1/1] selinuxns: Replace state pointer with namespace id
  2022-02-16 12:52       ` [RFC PATCH 0/1] SELinux-namespaces Igor Baranov
@ 2022-02-16 12:52         ` Igor Baranov
  2022-02-16 17:08         ` [RFC PATCH 0/1] SELinux-namespaces Casey Schaufler
  2022-02-16 20:47         ` Paul Moore
  2 siblings, 0 replies; 15+ messages in thread
From: Igor Baranov @ 2022-02-16 12:52 UTC (permalink / raw)
  To: paul
  Cc: hw.likun, jamorris, linux-security-module, selinux,
	stephen.smalley.work, xiujianfeng, alexander.kozhevnikov,
	yusongping, artem.kuzin, Igor Baranov

All the objects which in the original patchset kept a pointer to their
namespace now store its identifier. It's needed only to determine whether
an object belongs to our (in the current context) namespace or not.
The aim of this change is to reduce the height of the Babel tower of pointers.

Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c            | 29 ++++++++++++++++++++++++-----
 security/selinux/include/objsec.h   |  4 +++-
 security/selinux/include/security.h |  2 ++
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a1716ce534dd..69bc8a5fc5b4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -106,6 +106,9 @@
 /* SECMARK reference count */
 static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
+/* Sequential namespace id */
+static atomic64_t selinux_namespace_id = ATOMIC_INIT(0);
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 static int selinux_enforcing_boot __initdata;
 
@@ -812,6 +815,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 			goto out;
 
 		root_isec->sid = rootcontext_sid;
+		root_isec->namespace_id = current_selinux_state->id;
 		root_isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -1556,6 +1560,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
 		isec->initialized = LABEL_INITIALIZED;
 		isec->sid = sid;
+		isec->namespace_id = current_selinux_state->id;
 	}
 
 out_unlock:
@@ -2588,7 +2593,7 @@ sbsec_alloc(struct superblock_security_head *sbsech)
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-	sbsec->state = get_selinux_state(current_selinux_state);
+	sbsec->namespace_id = current_selinux_state->id;
 
 	return sbsec;
 }
@@ -2599,12 +2604,12 @@ 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)
+	if (cur->namespace_id == current_selinux_state->id)
 		return cur;
 
 	spin_lock(&sbsech->lock);
 	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
-		if (cur->state == current_selinux_state)
+		if (cur->namespace_id == current_selinux_state->id)
 			goto unlock;
 	}
 	spin_unlock(&sbsech->lock);
@@ -2617,7 +2622,7 @@ find_sbsec(struct superblock_security_head *sbsech)
 
 	spin_lock(&sbsech->lock);
 	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
-		if (cur->state == current_selinux_state)
+		if (cur->namespace_id == current_selinux_state->id)
 			goto unlock;
 	}
 	list_add(&new->sbsec_list, &sbsech->head);
@@ -2649,7 +2654,6 @@ static void selinux_sb_free_security(struct super_block *sb)
 	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);
 	}
 }
@@ -2911,6 +2915,7 @@ static int selinux_inode_alloc_security(struct inode *inode)
 	isec->sclass = SECCLASS_FILE;
 	isec->task_sid = sid;
 	isec->initialized = LABEL_INVALID;
+	isec->namespace_id = current_selinux_state->id;
 
 	return 0;
 }
@@ -2985,6 +2990,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 		struct inode_security_struct *isec = selinux_inode(inode);
 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
 		isec->sid = newsid;
+		isec->namespace_id = current_selinux_state->id;
 		isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -3320,6 +3326,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 
@@ -3479,6 +3486,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 	return 0;
@@ -3636,6 +3644,7 @@ static int selinux_file_alloc_security(struct file *file)
 
 	fsec->sid = sid;
 	fsec->fown_sid = sid;
+	fsec->namespace_id = current_selinux_state->id;
 
 	return 0;
 }
@@ -3950,6 +3959,7 @@ static int selinux_file_open(struct file *file)
 	 */
 	fsec->isid = isec->sid;
 	fsec->pseqno = avc_policy_seqno(current_selinux_state);
+	fsec->namespace_id = current_selinux_state->id;
 	/*
 	 * Since the inode label or policy seqno may have changed
 	 * between the selinux_inode_permission check and the saving
@@ -4268,6 +4278,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 }
@@ -4634,6 +4645,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 	isec->sclass = sclass;
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 
 	if (sock->sk) {
@@ -4930,6 +4942,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 	newisec = inode_security_novalidate(SOCK_INODE(newsock));
 	newisec->sclass = sclass;
 	newisec->sid = sid;
+	newisec->namespace_id = current_selinux_state->id;
 	newisec->initialized = LABEL_INITIALIZED;
 
 	return 0;
@@ -7332,6 +7345,11 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 static void selinux_state_free(struct work_struct *work);
 
+u64 selinux_new_state_id(void)
+{
+	return atomic64_fetch_add(1, &selinux_namespace_id);
+}
+
 int selinux_state_create(struct selinux_state *parent, struct selinux_state **state)
 {
 	struct selinux_state *newstate;
@@ -7341,6 +7359,7 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 	if (!newstate)
 		return -ENOMEM;
 
+	newstate->id = selinux_new_state_id();
 	refcount_set(&newstate->count, 1);
 	INIT_WORK(&newstate->work, selinux_state_free);
 
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6ad1db45b0d9..24ef0bc68eda 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -42,6 +42,7 @@ struct inode_security_struct {
 	u16 sclass;		/* security class of this object */
 	unsigned char initialized;	/* initialization flag */
 	spinlock_t lock;
+	u64 namespace_id;	/* pointer to selinux_state */
 };
 
 struct file_security_struct {
@@ -49,6 +50,7 @@ struct file_security_struct {
 	u32 fown_sid;		/* SID of file owner (for SIGIO) */
 	u32 isid;		/* SID of inode at the time of file open */
 	u32 pseqno;		/* Policy seqno at the time of file open */
+	u64 namespace_id;
 };
 
 struct superblock_security_head {
@@ -66,7 +68,7 @@ struct superblock_security_struct {
 	struct mutex lock;
 	struct list_head isec_head;
 	spinlock_t isec_lock;
-	struct selinux_state *state;	/* pointer to selinux_state */
+	u64 namespace_id;           /* id of selinux_state */
 	struct list_head sbsec_list;
 };
 
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index a5b698aae38c..b80622770543 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,8 +111,10 @@ struct selinux_state {
 	struct selinux_policy __rcu *policy;
 	struct mutex policy_mutex;
 	struct selinux_state *parent;
+	u64 id;
 } __randomize_layout;
 
+u64 selinux_new_state_id(void);
 int selinux_state_create(struct selinux_state *parent, struct selinux_state **state);
 void __put_selinux_state(struct selinux_state *state);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 0/1] SELinux-namespaces
  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         ` Casey Schaufler
  2022-02-16 20:47         ` Paul Moore
  2 siblings, 0 replies; 15+ messages in thread
From: Casey Schaufler @ 2022-02-16 17:08 UTC (permalink / raw)
  To: Igor Baranov, paul
  Cc: hw.likun, jamorris, linux-security-module, selinux,
	stephen.smalley.work, xiujianfeng, alexander.kozhevnikov,
	yusongping, artem.kuzin, Casey Schaufler

On 2/16/2022 4:52 AM, Igor Baranov wrote:
> Hi all!
> Our team at Huawei decided to revive the work on SELinux namespaces.
> We took https://github.com/stephensmalley/selinux-kernel/tree/working-selinuxns
> as a basis with some patches from selinuxns-xattr.
> We reworked them significantly, fixing and adding functionality.
> As a result we managed to run a CentOS Docker container with SELinux in enforcing mode!
>
> We would like to start our discussion with the smallest, but most basic
> change: we gave each namespace a unique identifier.
> It is assigned to a namespace from the global counter
> that is incremented each time you create it.
>
> All the objects which in the original patchset kept a pointer to their
> namespace now store its identifier. It's needed only to determine whether
> an object belongs to our (in the current context) namespace or not.
> The aim of this change is to reduce the height of the Babel tower of pointers,
> because in the original patch there was such a mess and such bugs,
> that we decided to cut this Gordian knot, removing some pointers altogether.
>
> This is a very small part of our changes, but we see the point of discussing
> more when we come to this.
>
> Particularly because there are alternative approaches,
> such as Casey Schaufler's suggestion, which is mentioned
> in http://namei.org/presentations/selinux_namespacing_lca2018.pdf
> "How to deal with secids (32-bit IDs) which are passed to core kernel and
> cached there - Make them global" which seems quite promising for us too.

The promise of secids is that they are opaque identifiers and
thus only need to be meaningful to the policy engine.

> In the case of this approach, it is not necessary to store the namespace ID
> in objects, because it can be deduced from sid. But a detailed study of
> this area reveals some painful challenges. For example: fragmentation of
> the global sid space when loading/unloading different policies. And the
> depth of the rabbit hole is not obvious from current positions. This is a
> separate big topic.

The downside of secids is that eventually you do need to map them
to something meaningful to the policy engine. This is why I have always
(since 1986) objected to them. The SELinux implementation would be much
simpler without them. (I'm ignoring the networking implications for the
moment. :) ). Nonetheless, with separate AVC instances the mapping
should be (I've been told) straight forward.


>
> Igor Baranov (1):
>    Replace state pointer with namespace id
>
>   security/selinux/hooks.c            | 29 ++++++++++++++++++++++++-----
>   security/selinux/include/objsec.h   |  4 +++-
>   security/selinux/include/security.h |  2 ++
>   3 files changed, 29 insertions(+), 6 deletions(-)
>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RFC PATCH 0/1] SELinux-namespaces
  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
  2 siblings, 1 reply; 15+ messages in thread
From: Paul Moore @ 2022-02-16 20:47 UTC (permalink / raw)
  To: Igor Baranov
  Cc: hw.likun, jamorris, linux-security-module, selinux,
	stephen.smalley.work, xiujianfeng, alexander.kozhevnikov,
	yusongping, artem.kuzin

On Wed, Feb 16, 2022 at 7:52 AM Igor Baranov <igor.baranov@huawei.com> wrote:
>
> Hi all!
> Our team at Huawei decided to revive the work on SELinux namespaces.
> We took https://github.com/stephensmalley/selinux-kernel/tree/working-selinuxns
> as a basis with some patches from selinuxns-xattr.

Hello!

For reference there is a *slightly* more recent forward port of those
patches in the main SELinux repo under the working-selinuxns branch.
I haven't forward ported those patches since v5.10-rc1 as there are
some rather significant technical hurdles around persistent object
labeling which I don't believe have been adequately resolved yet.  The
prefixed/namespaces xattr approach that you mention above may work for
a limited number of namespaces, but I worry there is a scalability
issue that needs to be resolved; we can't simply keep adding xattrs to
inodes.

 * https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux.git

Also, are there rest of your patches online anywhere?  Patch 1/1 isn't
very interesting on its own.

-- 
paul-moore.com

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 0/7] SELinux-namespace
  2022-02-16 20:47         ` Paul Moore
@ 2022-04-18  9:45           ` Alexander Kozhevnikov
  2022-04-18  9:45             ` [RFC PATCH 1/7] LSM: Infrastructure management of the superblock Alexander Kozhevnikov
                               ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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

Continue with the previous discussion, we decided to do the following: publish all of our patches.
The aim of these series patches is to extend the functionality and
stability of selinux namespace base-on the existing work for a basic
PoC.

To try our patches you need to:
* Checkout https://github.com/stephensmalley/selinux-kernel/commit/3a3b3ad9bd266f0199a2db6c0aa15c343c2307f1
* Apply our patches.
* Compile the kernel and boot into it.
* Next, we recommend creating a privileged Docker container with a SELinux-based distribution (we used CentOS 7) with mapping /sys/fs/selinux:/sys/fs/selinux
* Then log into into the container and do the following:

# create new namespace with name "ns", unshare previous one
echo "ns" > /sys/fs/selinux/unshare; unshare --fork -m
# remount selinuxfs, load policy
umount /sys/fs/selinux; mount -t selinuxfs none /sys/fs/selinux/; load_policy
# relabel everything
restorecon / -Rv
# check xattr's
ls -Z
# now enter enforcing mode
setenforce 1
# check enforce
getenforce

First of all, there is a need to build the solid code base for the
workable PoC with the latest branch working-selinux, hence the related
commits picked from the sources comprise the first two patches.
And the rest five patches are the major work, detailed description
can be check in each commit message:

  (1) Infrastructure management of the superblock
  (2) support per-namespace superblock security structures
  (3) Fix initilization of the superblock security under spinlock
  (4) Namespacing for xattrs
  (5) Migrate all open files and all vma to new namespace
  (6) Fixing superblock security structure memory leakage
  (7) Fixing concurrency issues

Hope the initial efforts in this direction could re-initiate the discussion.
Thanks.

 README.SELINUX-NAMESPACES           |  22 +
 include/linux/lsm_hooks.h           |   1 +
 security/security.c                 |  46 +-
 security/selinux/hooks.c            | 682 +++++++++++++++++++++-------
 security/selinux/include/objsec.h   |  41 +-
 security/selinux/include/security.h |  23 +-
 security/selinux/selinuxfs.c        | 368 +++++++++++----
 security/selinux/ss/services.c      |  32 +-
 security/smack/smack.h              |   6 +
 security/smack/smack_lsm.c          |  35 +-
 10 files changed, 950 insertions(+), 306 deletions(-)
 create mode 100644 README.SELINUX-NAMESPACES

-- 
2.34.1

Alexander Kozhevnikov,
Igor Baranov,

Advanced Software Technology Lab

Huawei

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [RFC PATCH 1/7] LSM: Infrastructure management of the superblock
  2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
@ 2022-04-18  9:45             ` Alexander Kozhevnikov
  2022-04-18  9:45             ` [RFC PATCH 2/7] selinux: support per-namespace superblock security structures Alexander Kozhevnikov
                               ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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

From 6618c9c9b6aba516a32cd38798055c061c7e4455 Mon Sep 17 00:00:00 2001
From: Casey Schaufler <casey@schaufler-ca.com>
Date: Thu, 22 Apr 2021 17:41:15 +0200
Subject: [PATCH 1/4] LSM: Infrastructure management of the superblock
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Move management of the superblock->sb_security blob out of the
individual security modules and into the security infrastructure.
Instead of allocating the blobs from within the modules, the modules
tell the infrastructure how much space is required, and the space is
allocated there.

Cc: John Johansen <john.johansen@canonical.com>
Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Signed-off-by: Mickaël Salaün <mic@linux.microsoft.com>
Reviewed-by: Stephen Smalley <stephen.smalley.work@gmail.com>
Acked-by: Serge Hallyn <serge@hallyn.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Link: https://lore.kernel.org/r/20210422154123.13086-6-mic@digikod.net
Signed-off-by: James Morris <jamorris@linux.microsoft.com>
---
 include/linux/lsm_hooks.h           |  1 +
 security/security.c                 | 46 +++++++++++++++++++----
 security/selinux/hooks.c            | 58 +++++++++++------------------
 security/selinux/include/objsec.h   | 16 ++++++++
 security/selinux/include/security.h | 10 -----
 security/selinux/ss/services.c      |  3 +-
 security/smack/smack.h              |  6 +++
 security/smack/smack_lsm.c          | 35 +++++------------
 8 files changed, 95 insertions(+), 80 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 9e2e3e63719d..29df5075b35d 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1550,6 +1550,7 @@ struct lsm_blob_sizes {
 	int	lbs_cred;
 	int	lbs_file;
 	int	lbs_inode;
+	int	lbs_superblock;
 	int	lbs_ipc;
 	int	lbs_msg_msg;
 	int	lbs_task;
diff --git a/security/security.c b/security/security.c
index 70a7ad357bc6..d60aa835b670 100644
--- a/security/security.c
+++ b/security/security.c
@@ -201,6 +201,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
 	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
 	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
 	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
 	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
 }
 
@@ -331,12 +332,13 @@ static void __init ordered_lsm_init(void)
 	for (lsm = ordered_lsms; *lsm; lsm++)
 		prepare_lsm(*lsm);
 
-	init_debug("cred blob size     = %d\n", blob_sizes.lbs_cred);
-	init_debug("file blob size     = %d\n", blob_sizes.lbs_file);
-	init_debug("inode blob size    = %d\n", blob_sizes.lbs_inode);
-	init_debug("ipc blob size      = %d\n", blob_sizes.lbs_ipc);
-	init_debug("msg_msg blob size  = %d\n", blob_sizes.lbs_msg_msg);
-	init_debug("task blob size     = %d\n", blob_sizes.lbs_task);
+	init_debug("cred blob size       = %d\n", blob_sizes.lbs_cred);
+	init_debug("file blob size       = %d\n", blob_sizes.lbs_file);
+	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
+	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
+	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
 
 	/*
 	 * Create any kmem_caches needed for blobs
@@ -668,6 +670,27 @@ static void __init lsm_early_task(struct task_struct *task)
 		panic("%s: Early task alloc failed.\n", __func__);
 }
 
+/**
+ * lsm_superblock_alloc - allocate a composite superblock blob
+ * @sb: the superblock that needs a blob
+ *
+ * Allocate the superblock blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_superblock_alloc(struct super_block *sb)
+{
+	if (blob_sizes.lbs_superblock == 0) {
+		sb->s_security = NULL;
+		return 0;
+	}
+
+	sb->s_security = kzalloc(blob_sizes.lbs_superblock, GFP_KERNEL);
+	if (sb->s_security == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
 /*
  * The default value of the LSM hook is defined in linux/lsm_hook_defs.h and
  * can be accessed with:
@@ -865,12 +888,21 @@ int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *
 
 int security_sb_alloc(struct super_block *sb)
 {
-	return call_int_hook(sb_alloc_security, 0, sb);
+	int rc = lsm_superblock_alloc(sb);
+
+	if (unlikely(rc))
+		return rc;
+	rc = call_int_hook(sb_alloc_security, 0, sb);
+	if (unlikely(rc))
+		security_sb_free(sb);
+	return rc;
 }
 
 void security_sb_free(struct super_block *sb)
 {
 	call_void_hook(sb_free_security, sb);
+	kfree(sb->s_security);
+	sb->s_security = NULL;
 }
 
 void security_free_mnt_opts(void **mnt_opts)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f31d1ddca601..8d88b6bec24b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -342,7 +342,7 @@ static void inode_free_security(struct inode *inode)
 
 	if (!isec)
 		return;
-	sbsec = inode->i_sb->s_security;
+	sbsec = selinux_superblock(inode->i_sb);
 	/*
 	 * As not all inode security structures are in a list, we check for
 	 * empty list outside of the lock to make sure that we won't waste
@@ -360,13 +360,6 @@ static void inode_free_security(struct inode *inode)
 	}
 }
 
-static void superblock_free_security(struct super_block *sb)
-{
-	struct superblock_security_struct *sbsec = sb->s_security;
-	sb->s_security = NULL;
-	kfree(sbsec);
-}
-
 struct selinux_mnt_opts {
 	const char *fscontext, *context, *rootcontext, *defcontext;
 };
@@ -478,7 +471,7 @@ static int selinux_is_genfs_special_handling(struct super_block *sb)
 
 static int selinux_is_sblabel_mnt(struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	/*
 	 * IMPORTANT: Double-check logic in this function when adding a new
@@ -506,7 +499,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
 
 static int sb_finish_set_opts(struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	struct dentry *root = sb->s_root;
 	struct inode *root_inode = d_backing_inode(root);
 	int rc = 0;
@@ -619,7 +612,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 				unsigned long *set_kern_flags)
 {
 	const struct cred *cred = current_cred();
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	struct dentry *root = sbsec->sb->s_root;
 	struct selinux_mnt_opts *opts = mnt_opts;
 	struct inode_security_struct *root_isec;
@@ -856,8 +849,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 static int selinux_cmp_sb_context(const struct super_block *oldsb,
 				    const struct super_block *newsb)
 {
-	struct superblock_security_struct *old = oldsb->s_security;
-	struct superblock_security_struct *new = newsb->s_security;
+	struct superblock_security_struct *old = selinux_superblock(oldsb);
+	struct superblock_security_struct *new = selinux_superblock(newsb);
 	char oldflags = old->flags & SE_MNTMASK;
 	char newflags = new->flags & SE_MNTMASK;
 
@@ -889,8 +882,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
 					unsigned long *set_kern_flags)
 {
 	int rc = 0;
-	const struct superblock_security_struct *oldsbsec = oldsb->s_security;
-	struct superblock_security_struct *newsbsec = newsb->s_security;
+	const struct superblock_security_struct *oldsbsec =
+						selinux_superblock(oldsb);
+	struct superblock_security_struct *newsbsec = selinux_superblock(newsb);
 
 	int set_fscontext =	(oldsbsec->flags & FSCONTEXT_MNT);
 	int set_context =	(oldsbsec->flags & CONTEXT_MNT);
@@ -1069,7 +1063,7 @@ static int show_sid(struct seq_file *m, u32 sid)
 
 static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	int rc;
 
 	if (!(sbsec->flags & SE_SBINITIALIZED))
@@ -1419,7 +1413,7 @@ 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);
 
-	sbsec = inode->i_sb->s_security;
+	sbsec = selinux_superblock(inode->i_sb);
 	if (!(sbsec->flags & SE_SBINITIALIZED)) {
 		/* Defer initialization until selinux_complete_init,
 		   after the initial policy is loaded and the security
@@ -1762,7 +1756,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
 				 const struct qstr *name, u16 tclass,
 				 u32 *_new_isid)
 {
-	const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
+	const struct superblock_security_struct *sbsec =
+						selinux_superblock(dir->i_sb);
 
 	if ((sbsec->flags & SE_SBINITIALIZED) &&
 	    (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
@@ -1793,7 +1788,7 @@ static int may_create(struct inode *dir,
 	int rc;
 
 	dsec = inode_security(dir);
-	sbsec = dir->i_sb->s_security;
+	sbsec = selinux_superblock(dir->i_sb);
 
 	sid = tsec->sid;
 
@@ -1942,7 +1937,7 @@ static int superblock_has_perm(const struct cred *cred,
 	struct superblock_security_struct *sbsec;
 	u32 sid = cred_sid(cred);
 
-	sbsec = sb->s_security;
+	sbsec = selinux_superblock(sb);
 	return avc_has_perm(cred_selinux_state(cred),
 			    sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
 }
@@ -2571,11 +2566,7 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 
 static int selinux_sb_alloc_security(struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec;
-
-	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
-	if (!sbsec)
-		return -ENOMEM;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 
 	mutex_init(&sbsec->lock);
 	INIT_LIST_HEAD(&sbsec->isec_head);
@@ -2584,16 +2575,10 @@ static int selinux_sb_alloc_security(struct super_block *sb)
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-	sb->s_security = sbsec;
 
 	return 0;
 }
 
-static void selinux_sb_free_security(struct super_block *sb)
-{
-	superblock_free_security(sb);
-}
-
 static inline int opt_len(const char *s)
 {
 	bool open_quote = false;
@@ -2672,7 +2657,7 @@ static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
 static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
 {
 	struct selinux_mnt_opts *opts = mnt_opts;
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	u32 sid;
 	int rc;
 
@@ -2910,7 +2895,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 	int rc;
 	char *context;
 
-	sbsec = dir->i_sb->s_security;
+	sbsec = selinux_superblock(dir->i_sb);
 
 	newsid = tsec->create_sid;
 
@@ -3155,7 +3140,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	if (!selinux_initialized(current_selinux_state))
 		return (inode_owner_or_capable(inode) ? 0 : -EPERM);
 
-	sbsec = inode->i_sb->s_security;
+	sbsec = selinux_superblock(inode->i_sb);
 	if (!(sbsec->flags & SBLABEL_MNT))
 		return -EOPNOTSUPP;
 
@@ -3397,13 +3382,14 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 				     const void *value, size_t size, int flags)
 {
 	struct inode_security_struct *isec = inode_security_novalidate(inode);
-	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+	struct superblock_security_struct *sbsec;
 	u32 newsid;
 	int rc;
 
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
 		return -EOPNOTSUPP;
 
+	sbsec = selinux_superblock(inode->i_sb);
 	if (!(sbsec->flags & SBLABEL_MNT))
 		return -EOPNOTSUPP;
 
@@ -6917,6 +6903,7 @@ struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
 	.lbs_inode = sizeof(struct inode_security_struct),
 	.lbs_ipc = sizeof(struct ipc_security_struct),
 	.lbs_msg_msg = sizeof(struct msg_security_struct),
+	.lbs_superblock = sizeof(struct superblock_security_struct),
 };
 
 #ifdef CONFIG_PERF_EVENTS
@@ -7017,7 +7004,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
 	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
 
-	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
 	LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
 	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index a24b97800111..f456bb5782a3 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -166,4 +166,20 @@ static inline struct ipc_security_struct *selinux_ipc(
 	return ipc->security + selinux_blob_sizes.lbs_ipc;
 }
 
+/*
+ * get the subjective security ID of the current task
+ */
+static inline u32 current_sid(void)
+{
+	const struct task_security_struct *tsec = selinux_cred(current_cred());
+
+	return tsec->sid;
+}
+
+static inline struct superblock_security_struct *selinux_superblock(
+					const struct super_block *superblock)
+{
+	return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+}
+
 #endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 8eb058e1182c..1a7d76f0faf3 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -151,16 +151,6 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
 	return cred->security + selinux_blob_sizes.lbs_cred;
 }
 
-/*
- * get the subjective security ID of the current task
- */
-static inline u32 current_sid(void)
-{
-	const struct task_security_struct *tsec = selinux_cred(current_cred());
-
-	return tsec->sid;
-}
-
 #define current_selinux_state (selinux_cred(current_cred())->state)
 
 #define cred_selinux_state(cred) (selinux_cred(cred)->state)
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index a89a5107c5d7..2c9e77ca4754 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -47,6 +47,7 @@
 #include <linux/sched.h>
 #include <linux/audit.h>
 #include <linux/vmalloc.h>
+#include <linux/lsm_hooks.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -2874,7 +2875,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
 	struct sidtab *sidtab;
 	int rc = 0;
 	struct ocontext *c;
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec = selinux_superblock(sb);
 	const char *fstype = sb->s_type->name;
 
 	if (!selinux_initialized(state)) {
diff --git a/security/smack/smack.h b/security/smack/smack.h
index e9e817d09785..d33d2a7b73a3 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -364,6 +364,12 @@ static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
 	return ipc->security + smack_blob_sizes.lbs_ipc;
 }
 
+static inline struct superblock_smack *smack_superblock(
+					const struct super_block *superblock)
+{
+	return superblock->s_security + smack_blob_sizes.lbs_superblock;
+}
+
 /*
  * Is the directory transmuting?
  */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 8ffbf951b7ed..8d8f70a99374 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -535,12 +535,7 @@ static int smack_syslog(int typefrom_file)
  */
 static int smack_sb_alloc_security(struct super_block *sb)
 {
-	struct superblock_smack *sbsp;
-
-	sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL);
-
-	if (sbsp == NULL)
-		return -ENOMEM;
+	struct superblock_smack *sbsp = smack_superblock(sb);
 
 	sbsp->smk_root = &smack_known_floor;
 	sbsp->smk_default = &smack_known_floor;
@@ -549,22 +544,10 @@ static int smack_sb_alloc_security(struct super_block *sb)
 	/*
 	 * SMK_SB_INITIALIZED will be zero from kzalloc.
 	 */
-	sb->s_security = sbsp;
 
 	return 0;
 }
 
-/**
- * smack_sb_free_security - free a superblock blob
- * @sb: the superblock getting the blob
- *
- */
-static void smack_sb_free_security(struct super_block *sb)
-{
-	kfree(sb->s_security);
-	sb->s_security = NULL;
-}
-
 struct smack_mnt_opts {
 	const char *fsdefault, *fsfloor, *fshat, *fsroot, *fstransmute;
 };
@@ -772,7 +755,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
 {
 	struct dentry *root = sb->s_root;
 	struct inode *inode = d_backing_inode(root);
-	struct superblock_smack *sp = sb->s_security;
+	struct superblock_smack *sp = smack_superblock(sb);
 	struct inode_smack *isp;
 	struct smack_known *skp;
 	struct smack_mnt_opts *opts = mnt_opts;
@@ -871,7 +854,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
  */
 static int smack_sb_statfs(struct dentry *dentry)
 {
-	struct superblock_smack *sbp = dentry->d_sb->s_security;
+	struct superblock_smack *sbp = smack_superblock(dentry->d_sb);
 	int rc;
 	struct smk_audit_info ad;
 
@@ -905,7 +888,7 @@ static int smack_bprm_creds_for_exec(struct linux_binprm *bprm)
 	if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
 		return 0;
 
-	sbsp = inode->i_sb->s_security;
+	sbsp = smack_superblock(inode->i_sb);
 	if ((sbsp->smk_flags & SMK_SB_UNTRUSTED) &&
 	    isp->smk_task != sbsp->smk_root)
 		return 0;
@@ -1157,7 +1140,7 @@ static int smack_inode_rename(struct inode *old_inode,
  */
 static int smack_inode_permission(struct inode *inode, int mask)
 {
-	struct superblock_smack *sbsp = inode->i_sb->s_security;
+	struct superblock_smack *sbsp = smack_superblock(inode->i_sb);
 	struct smk_audit_info ad;
 	int no_block = mask & MAY_NOT_BLOCK;
 	int rc;
@@ -1398,7 +1381,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
 	 */
 	if (strcmp(name, XATTR_NAME_SMACK) == 0) {
 		struct super_block *sbp = dentry->d_sb;
-		struct superblock_smack *sbsp = sbp->s_security;
+		struct superblock_smack *sbsp = smack_superblock(sbp);
 
 		isp->smk_inode = sbsp->smk_default;
 	} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
@@ -1668,7 +1651,7 @@ static int smack_mmap_file(struct file *file,
 	isp = smack_inode(file_inode(file));
 	if (isp->smk_mmap == NULL)
 		return 0;
-	sbsp = file_inode(file)->i_sb->s_security;
+	sbsp = smack_superblock(file_inode(file)->i_sb);
 	if (sbsp->smk_flags & SMK_SB_UNTRUSTED &&
 	    isp->smk_mmap != sbsp->smk_root)
 		return -EACCES;
@@ -3268,7 +3251,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
 		return;
 
 	sbp = inode->i_sb;
-	sbsp = sbp->s_security;
+	sbsp = smack_superblock(sbp);
 	/*
 	 * We're going to use the superblock default label
 	 * if there's no label on the file.
@@ -4653,6 +4636,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
 	.lbs_inode = sizeof(struct inode_smack),
 	.lbs_ipc = sizeof(struct smack_known *),
 	.lbs_msg_msg = sizeof(struct smack_known *),
+	.lbs_superblock = sizeof(struct superblock_smack),
 };
 
 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
@@ -4664,7 +4648,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
 	LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param),
 
 	LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
-	LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
 	LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts),
 	LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts),
 	LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 2/7] selinux: support per-namespace superblock security structures
  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
  2022-04-18  9:45             ` [RFC PATCH 3/7] SELINUXNS: Fix initilization of the superblock security under spinlock Alexander Kozhevnikov
                               ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 3/7] SELINUXNS: Fix initilization of the superblock security under spinlock
  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             ` [RFC PATCH 2/7] selinux: support per-namespace superblock security structures Alexander Kozhevnikov
@ 2022-04-18  9:45             ` Alexander Kozhevnikov
  2022-04-18  9:45             ` [RFC PATCH 4/7] SELINUXNS: Namespacing for xattrs Alexander Kozhevnikov
                               ` (3 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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

After porting 3378718ef7d4a837f32c63bdfcc0b70342cdd55d,
selinux_superblock() started being called from under spinlock, along
with kzalloc(GFP_NOFS), which causes a scheduling while atomic error.
The solution is to take the call to selinux_superblock() out from under
the spinlock.

Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a1716ce534dd..f02e31edae7c 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1408,13 +1408,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 	if (isec->initialized == LABEL_INITIALIZED)
 		return 0;
 
-	spin_lock(&isec->lock);
-	if (isec->initialized == LABEL_INITIALIZED)
-		goto out_unlock;
-
-	if (isec->sclass == SECCLASS_FILE)
-		isec->sclass = inode_mode_to_security_class(inode->i_mode);
-
 	sbsec = selinux_superblock(inode->i_sb);
 	if (!(sbsec->flags & SE_SBINITIALIZED)) {
 		/* Defer initialization until selinux_complete_init,
@@ -1424,9 +1417,15 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 		if (list_empty(&isec->list))
 			list_add(&isec->list, &sbsec->isec_head);
 		spin_unlock(&sbsec->isec_lock);
-		goto out_unlock;
+		return 0;
 	}
 
+	spin_lock(&isec->lock);
+	if (isec->initialized == LABEL_INITIALIZED)
+		goto out_unlock;
+
+	if (isec->sclass == SECCLASS_FILE)
+		isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	sclass = isec->sclass;
 	task_sid = isec->task_sid;
 	sid = isec->sid;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 4/7] SELINUXNS: Namespacing for xattrs
  2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
                               ` (2 preceding siblings ...)
  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             ` Alexander Kozhevnikov
  2022-04-18  9:45             ` [RFC PATCH 5/7] SELINUXNS: Migrate all open files and all vma to new namespace Alexander Kozhevnikov
                               ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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

In the original S. Smalley's inode_security_struct turned into a list
(see
https://github.com/stephensmalley/selinux-kernel/commit/efb2ddadfdd0e10e75b6aa5da2ed9841df6ef2f6)

This approach has a number of problems described in the commit-message
there. Besides, it dramatically increases implementation complexity (the
height of the Tower of Babel) and the resulting code had a number of
bugs, such as memory leaks.

We decided to try a completely different approach as an experiment.

So we introduced a unique identifier into the namespace. It is a 64-bit
number which grows monotonically each time you create a new namespace.

In inode_security_structure the pointer to the selinux state is replaced
by this ID, which is needed only for comparison: we need to determine
whether some inode_security_struct belongs to "our" namespace or not.
This got rid of the pointers.

Next is the most interesting part.
Instead of making a list of inode_security_struct, we decided to keep
only one instance of this structure.
It stores information about inode security from the namespace we last
read it from.
When we want to get the SID of a structure, we first compare its
namespace id with the id of the current namespace. If they match, we
just use the stored SID. If not, we re-read the SID from the xattr of
our namespace. All this logic is implemented in the update_sid()
function and its variations. We call this mechanism "carousel switch"
and it is somewhat similar to LRU-cache.

Among other changes in this commit:

* Instead of current_creds(), we decided to use current_real_creds().
This is because the credentials of the task can be spoofed (e.g. ovl_xattr_get).
Although objective and subjective credentials have different purposes,
they are almost always the same (see task_struct->real_creds).

* We drastically changed the way xattr's suffixes are handled.
While the original patchset modified the VFS subsystem code for this
(see
https://github.com/stephensmalley/selinux-kernel/commit/cf673d0f46ae88241f49f3d193403d40405d03a9),
we decided to intercept the set() and get() handlers in
super_block->s_xattr.

* Added README.SELINUX-NAMESPACES

Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 README.SELINUX-NAMESPACES           |  22 ++
 security/selinux/hooks.c            | 349 +++++++++++++++++++++++-----
 security/selinux/include/objsec.h   |   7 +-
 security/selinux/include/security.h |   8 +-
 security/selinux/selinuxfs.c        |  98 +++++---
 5 files changed, 388 insertions(+), 96 deletions(-)
 create mode 100644 README.SELINUX-NAMESPACES

diff --git a/README.SELINUX-NAMESPACES b/README.SELINUX-NAMESPACES
new file mode 100644
index 000000000000..401f702bb583
--- /dev/null
+++ b/README.SELINUX-NAMESPACES
@@ -0,0 +1,22 @@
+Introduction.
+This experimental patch is designed to enable namespaces mode for LSM SELinux.
+
+This work is based on Stephen Smalley's patches https://github.com/stephensmalley/selinux-kernel/tree/working-selinuxns
+Some of which have been applied here, some of which have been reworked/fixed.
+
+Usage
+# create new namespace with name "ns", unshare previous one
+echo "ns" > /sys/fs/selinux/unshare; unshare --fork -m
+
+# remount selinuxfs, load policy
+umount /sys/fs/selinux; mount -t selinuxfs none /sys/fs/selinux/; load_policy
+
+# relabel everything
+restorecon / -Rv
+
+# check xattr's
+ls -Z
+
+# now enter enforcing mode
+setenforce 1
+
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f02e31edae7c..b618c4e0ef36 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -106,6 +106,9 @@
 /* SECMARK reference count */
 static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
+/* Sequential namespace id */
+static atomic64_t selinux_namespace_id = ATOMIC_INIT(0);
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 static int selinux_enforcing_boot __initdata;
 
@@ -279,7 +282,8 @@ static int __inode_security_revalidate(struct inode *inode,
 	might_sleep_if(may_sleep);
 
 	if (selinux_initialized(current_selinux_state) &&
-	    isec->initialized != LABEL_INITIALIZED) {
+	    (isec->initialized != LABEL_INITIALIZED ||
+	     current_selinux_state->id != isec->namespace_id)) {
 		if (!may_sleep)
 			return -ECHILD;
 
@@ -288,6 +292,7 @@ static int __inode_security_revalidate(struct inode *inode,
 		 * @opt_dentry is NULL and no dentry for this inode can be
 		 * found; in that case, continue using the old label.
 		 */
+		isec->initialized = LABEL_INVALID;
 		inode_doinit_with_dentry(inode, dentry);
 	}
 	return 0;
@@ -497,6 +502,44 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
 	}
 }
 
+#define for_each_xattr_handler(handlers, handler)		\
+		for ((handler) = *(handlers)++;			\
+			(handler) != NULL;			\
+			(handler) = *(handlers)++)
+static const char *
+strcmp_prefix(const char *a, const char *a_prefix)
+{
+	while (*a_prefix && *a == *a_prefix) {
+		a++;
+		a_prefix++;
+	}
+	return *a_prefix ? NULL : a;
+}
+
+static int
+selinux_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
+		struct inode *inode, const char *name, void *value, size_t size)
+{
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(inode->i_sb);
+
+	if (strcmp(name, XATTR_SELINUX_SUFFIX) == 0 && selinux_initialized(current_selinux_state))
+		name = current_selinux_state->xattr_name;
+
+	return sbsech->xattr_handler->get(sbsech->xattr_handler, unused, inode, name, value, size);
+}
+
+static int selinux_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
+		struct inode *inode, const char *name, const void *value,
+		size_t size, int flags)
+{
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(inode->i_sb);
+
+	if (strcmp(name, XATTR_SELINUX_SUFFIX) == 0 && selinux_initialized(current_selinux_state))
+		name = current_selinux_state->xattr_name;
+
+	return sbsech->xattr_handler->set(sbsech->xattr_handler, unused, inode, name, value, size, flags);
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
@@ -505,29 +548,77 @@ static int sb_finish_set_opts(struct super_block *sb)
 	int rc = 0;
 
 	if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
-		/* Make sure that the xattr handler exists and that no
-		   error other than -ENODATA is returned by getxattr on
-		   the root directory.  -ENODATA is ok, as this may be
-		   the first boot of the SELinux kernel before we have
-		   assigned xattr values to the filesystem. */
-		if (!(root_inode->i_opflags & IOP_XATTR)) {
-			pr_warn("SELinux: (dev %s, type %s) has no "
-			       "xattr support\n", sb->s_id, sb->s_type->name);
-			rc = -EOPNOTSUPP;
-			goto out;
-		}
+		struct superblock_security_head *sbsech = selinux_head_of_superblock(sb);
+
+		/* Should check xattr support only once */
+		if (!sbsech->xattr_handler) {
+			const struct xattr_handler **handlers, *handler;
+			const struct xattr_handler *sec_handler = NULL;
+			const struct xattr_handler **s_xattr;
+			size_t count = 0;
+
+			/* Make sure that the xattr handler exists and that no
+			   error other than -ENODATA is returned by getxattr on
+			   the root directory.  -ENODATA is ok, as this may be
+			   the first boot of the SELinux kernel before we have
+			   assigned xattr values to the filesystem. */
+			if (!(root_inode->i_opflags & IOP_XATTR)) {
+				pr_warn("SELinux: (dev %s, type %s) has no "
+					   "xattr support\n", sb->s_id, sb->s_type->name);
+				rc = -EOPNOTSUPP;
+				goto out;
+			}
 
-		rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
-		if (rc < 0 && rc != -ENODATA) {
-			if (rc == -EOPNOTSUPP)
-				pr_warn("SELinux: (dev %s, type "
-				       "%s) has no security xattr handler\n",
-				       sb->s_id, sb->s_type->name);
-			else
-				pr_warn("SELinux: (dev %s, type "
-				       "%s) getxattr errno %d\n", sb->s_id,
-				       sb->s_type->name, -rc);
-			goto out;
+			rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
+			if (rc < 0 && rc != -ENODATA) {
+				if (rc == -EOPNOTSUPP)
+					pr_warn("SELinux: (dev %s, type "
+					   "%s) has no security xattr handler\n",
+						   sb->s_id, sb->s_type->name);
+				else
+					pr_warn("SELinux: (dev %s, type "
+						   "%s) getxattr errno %d\n", sb->s_id,
+						   sb->s_type->name, -rc);
+				goto out;
+			}
+
+			handlers = sb->s_xattr;
+			for_each_xattr_handler(handlers, handler) {
+				count++;
+			}
+
+			s_xattr = kzalloc((1 + count) * sizeof(struct xattr_handler *) +
+							sizeof(struct xattr_handler),
+					GFP_KERNEL);
+			memcpy(s_xattr, sb->s_xattr, count * sizeof(struct xattr_handler *));
+			handlers = s_xattr;
+			for_each_xattr_handler(handlers, handler) {
+				const char *n = strcmp_prefix(XATTR_NAME_SELINUX, xattr_prefix(handler));
+				if (n) {
+					if (!handler->prefix ^ !*n) {
+						if (*n)
+							continue;
+						break;
+					}
+					sec_handler = handler;
+					break;
+				}
+			}
+
+			if (sec_handler) {
+				struct xattr_handler *hooked_handler = (void *)(s_xattr + count + 1);
+
+				*hooked_handler = *sec_handler;
+				hooked_handler->set = selinux_xattr_set;
+				hooked_handler->get = selinux_xattr_get;
+				sbsech->xattr_handler = sec_handler;
+				sbsech->old_s_xattr = sb->s_xattr;
+				*--handlers = hooked_handler;
+				sb->s_xattr = s_xattr;
+				pr_info("SELinux: (dev %s, type %s) installed xattr hook\n", sb->s_id, sb->s_type->name);
+			} else {
+				kfree(s_xattr);
+			}
 		}
 	}
 
@@ -812,6 +903,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 			goto out;
 
 		root_isec->sid = rootcontext_sid;
+		root_isec->namespace_id = current_selinux_state->id;
 		root_isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -1395,6 +1487,102 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
 	return 0;
 }
 
+static int read_sid(struct inode *inode, u32 *psid)
+{
+	int rc;
+	struct superblock_security_struct *sbsec;
+	struct dentry *dentry;
+
+	sbsec = selinux_superblock(inode->i_sb);
+
+	if (sbsec->behavior == 0) {
+		*psid = SECINITSID_UNLABELED;
+		return 0;
+	}
+	if (sbsec->behavior != SECURITY_FS_USE_XATTR)
+		return -EINVAL;
+
+	dentry = d_find_alias(inode);
+
+	if (!dentry)
+		dentry = d_find_any_alias(inode);
+
+	if (!dentry)
+		return -EINVAL;
+
+	rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid, psid);
+
+	dput(dentry);
+	return rc;
+}
+
+static void update_sid_and_lock(struct inode_security_struct *isec)
+{
+	u32 sid;
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	sid = isec->sid;
+	if (nsid != cnsid) {
+		spin_unlock(&isec->lock);
+		if (read_sid(isec->inode, &sid) == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = sid;
+		}
+	}
+}
+static u32 update_sid(struct inode_security_struct *isec)
+{
+	u32 sid;
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	sid = isec->sid;
+	spin_unlock(&isec->lock);
+	if (nsid != cnsid) {
+		if (read_sid(isec->inode, &sid) == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = sid;
+			spin_unlock(&isec->lock);
+		}
+	}
+	return sid;
+}
+
+static int update_sid_rcu(struct inode_security_struct *isec, u32 *psid, bool rcu)
+{
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	*psid = isec->sid;
+	spin_unlock(&isec->lock);
+	if (nsid != cnsid) {
+		int err;
+
+		if (rcu)
+			return -ECHILD;
+
+		err = read_sid(isec->inode, psid);
+		if (err == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = *psid;
+			spin_unlock(&isec->lock);
+		} else {
+			return err;
+		}
+	}
+	return 0;
+}
+
 /* The inode's security attributes must be initialized before first use. */
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
 {
@@ -1555,6 +1743,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
 		isec->initialized = LABEL_INITIALIZED;
 		isec->sid = sid;
+		isec->namespace_id = current_selinux_state->id;
 	}
 
 out_unlock:
@@ -1651,7 +1840,7 @@ static int inode_has_perm(const struct cred *cred,
 	isec = selinux_inode(inode);
 
 	return avc_has_perm(cred_selinux_state(cred),
-			    sid, isec->sid, isec->sclass, perms, adp);
+			    sid, update_sid(isec), isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1781,7 +1970,7 @@ static int may_create(struct inode *dir,
 		      struct dentry *dentry,
 		      u16 tclass)
 {
-	const struct task_security_struct *tsec = selinux_cred(current_cred());
+	const struct task_security_struct *tsec = selinux_cred(current_real_cred());
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid;
@@ -1844,7 +2033,7 @@ static int may_link(struct inode *dir,
 	av = DIR__SEARCH;
 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
 	rc = avc_has_perm(current_selinux_state,
-			  sid, dsec->sid, SECCLASS_DIR, av, &ad);
+			  sid, update_sid(dsec), SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 
@@ -1865,7 +2054,7 @@ static int may_link(struct inode *dir,
 	}
 
 	rc = avc_has_perm(current_selinux_state,
-			  sid, isec->sid, isec->sclass, av, &ad);
+			  sid, update_sid(isec), isec->sclass, av, &ad);
 	return rc;
 }
 
@@ -1890,18 +2079,18 @@ static inline int may_rename(struct inode *old_dir,
 
 	ad.u.dentry = old_dentry;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, old_dsec->sid, SECCLASS_DIR,
+			  sid, update_sid(old_dsec), SECCLASS_DIR,
 			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
 	if (rc)
 		return rc;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, old_isec->sid,
+			  sid, update_sid(old_isec),
 			  old_isec->sclass, FILE__RENAME, &ad);
 	if (rc)
 		return rc;
 	if (old_is_dir && new_dir != old_dir) {
 		rc = avc_has_perm(current_selinux_state,
-				  sid, old_isec->sid,
+				  sid, update_sid(old_isec),
 				  old_isec->sclass, DIR__REPARENT, &ad);
 		if (rc)
 			return rc;
@@ -1912,14 +2101,14 @@ static inline int may_rename(struct inode *old_dir,
 	if (d_is_positive(new_dentry))
 		av |= DIR__REMOVE_NAME;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+			  sid, update_sid(new_dsec), SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 	if (d_is_positive(new_dentry)) {
 		new_isec = backing_inode_security(new_dentry);
 		new_is_dir = d_is_dir(new_dentry);
 		rc = avc_has_perm(current_selinux_state,
-				  sid, new_isec->sid,
+				  sid, update_sid(new_isec),
 				  new_isec->sclass,
 				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
 		if (rc)
@@ -2089,7 +2278,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
 
 	isec = backing_inode_security(dentry);
 	return avc_has_perm(current_selinux_state,
-			    sid, isec->sid, isec->sclass, file_to_av(file),
+			    sid, update_sid(isec), isec->sclass, file_to_av(file),
 			    &ad);
 }
 
@@ -2340,7 +2529,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 	} else {
 		/* Check for a default transition on this program. */
 		rc = security_transition_sid(current_selinux_state, old_tsec->sid,
-					     isec->sid, SECCLASS_PROCESS, NULL,
+					     update_sid(isec), SECCLASS_PROCESS, NULL,
 					     &new_tsec->sid);
 		if (rc)
 			return rc;
@@ -2359,7 +2548,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 
 	if (new_tsec->sid == old_tsec->sid) {
 		rc = avc_has_perm(current_selinux_state,
-				  old_tsec->sid, isec->sid,
+				  old_tsec->sid, update_sid(isec),
 				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
 		if (rc)
 			return rc;
@@ -2372,7 +2561,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 			return rc;
 
 		rc = avc_has_perm(current_selinux_state,
-				  new_tsec->sid, isec->sid,
+				  new_tsec->sid, update_sid(isec),
 				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
 		if (rc)
 			return rc;
@@ -2570,6 +2759,8 @@ static void sbsec_head_init(struct super_block *sb,
 {
 	INIT_LIST_HEAD(&sbsech->head);
 	spin_lock_init(&sbsech->lock);
+	sbsech->xattr_handler = NULL;
+	sbsech->old_s_xattr = NULL;
 }
 
 static struct superblock_security_struct *
@@ -2651,6 +2842,12 @@ static void selinux_sb_free_security(struct super_block *sb)
 		put_selinux_state(entry->state);
 		kfree(entry);
 	}
+	if (sbsech->old_s_xattr) {
+		const struct xattr_handler **s_xattr = sb->s_xattr;
+
+		sb->s_xattr = sbsech->old_s_xattr;
+		kfree(s_xattr);
+	}
 }
 
 static inline int opt_len(const char *s)
@@ -2910,6 +3107,7 @@ static int selinux_inode_alloc_security(struct inode *inode)
 	isec->sclass = SECCLASS_FILE;
 	isec->task_sid = sid;
 	isec->initialized = LABEL_INVALID;
+	isec->namespace_id = current_selinux_state->id;
 
 	return 0;
 }
@@ -2984,6 +3182,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 		struct inode_security_struct *isec = selinux_inode(inode);
 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
 		isec->sid = newsid;
+		isec->namespace_id = current_selinux_state->id;
 		isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -3060,7 +3259,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
 	struct inode_security_struct *isec;
-	u32 sid;
+	u32 sid, isid;
+	int rc;
 
 	validate_creds(cred);
 
@@ -3071,8 +3271,12 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
 	if (IS_ERR(isec))
 		return PTR_ERR(isec);
 
+	rc = update_sid_rcu(isec, &isid, rcu);
+	if (rc != 0)
+		return rc;
+
 	return avc_has_perm_flags(cred_selinux_state(cred),
-				  sid, isec->sid, isec->sclass, FILE__READ, &ad,
+				  sid, isid, isec->sclass, FILE__READ, &ad,
 				  rcu ? MAY_NOT_BLOCK : 0);
 }
 
@@ -3088,7 +3292,7 @@ static noinline int audit_inode_permission(struct inode *inode,
 	ad.u.inode = inode;
 
 	rc = slow_avc_audit(current_selinux_state,
-			    current_sid(), isec->sid, isec->sclass, perms,
+			    current_sid(), update_sid(isec), isec->sclass, perms,
 			    audited, denied, result, &ad);
 	if (rc)
 		return rc;
@@ -3102,7 +3306,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 	bool from_access;
 	bool no_block = mask & MAY_NOT_BLOCK;
 	struct inode_security_struct *isec;
-	u32 sid;
+	u32 sid, isid;
 	struct av_decision avd;
 	int rc, rc2;
 	u32 audited, denied;
@@ -3126,8 +3330,12 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 	if (IS_ERR(isec))
 		return PTR_ERR(isec);
 
+	rc = update_sid_rcu(isec, &isid, no_block);
+	if (rc != 0)
+		return rc;
+
 	rc = avc_has_perm_noaudit(cred_selinux_state(cred),
-				  sid, isec->sid, isec->sclass, perms,
+				  sid, isid, isec->sclass, perms,
 				  no_block ? AVC_NONBLOCKING : 0,
 				  &avd);
 	audited = avc_audit_required(perms, &avd, rc,
@@ -3198,7 +3406,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	struct inode_security_struct *isec;
 	struct superblock_security_struct *sbsec;
 	struct common_audit_data ad;
-	u32 newsid, sid = current_sid();
+	u32 newsid, backsid, sid = current_sid();
 	int rc = 0;
 
 	if (strcmp(name, XATTR_NAME_SELINUX)) {
@@ -3225,8 +3433,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	ad.u.dentry = dentry;
 
 	isec = backing_inode_security(dentry);
+	backsid = update_sid(isec);
 	rc = avc_has_perm(current_selinux_state,
-			  sid, isec->sid, isec->sclass,
+			  sid, backsid, isec->sclass,
 			  FILE__RELABELFROM, &ad);
 	if (rc)
 		return rc;
@@ -3270,7 +3479,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	if (rc)
 		return rc;
 
-	rc = security_validate_transition(current_selinux_state, isec->sid, newsid,
+	rc = security_validate_transition(current_selinux_state, backsid, newsid,
 					  sid, isec->sclass);
 	if (rc)
 		return rc;
@@ -3319,6 +3528,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 
@@ -3432,13 +3642,14 @@ 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.
 	 */
+	//TODO: optimize sequence. need to read xattr only once
 	isec = inode_security(inode);
 	if (has_cap_mac_admin(false))
 		error = security_sid_to_context_force(current_selinux_state,
-						      isec->sid, &context,
+						      update_sid(isec), &context,
 						      &size);
 	else
-		error = security_sid_to_context(current_selinux_state, isec->sid,
+		error = security_sid_to_context(current_selinux_state, update_sid(isec),
 						&context, &size);
 	if (error)
 		return error;
@@ -3478,6 +3689,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 	return 0;
@@ -3494,7 +3706,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
 static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
 {
 	struct inode_security_struct *isec = inode_security_novalidate(inode);
-	*secid = isec->sid;
+	*secid = update_sid(isec);
 }
 
 static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
@@ -3620,7 +3832,7 @@ static int selinux_file_permission(struct file *file, int mask)
 		return 0;
 
 	isec = inode_security(inode);
-	if (sid == fsec->sid && fsec->isid == isec->sid &&
+	if (sid == fsec->sid && fsec->isid == update_sid(isec) &&
 	    fsec->pseqno == avc_policy_seqno(current_selinux_state))
 		/* No change since file_open check. */
 		return 0;
@@ -3676,7 +3888,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
 
 	isec = inode_security(inode);
 	rc = avc_has_extended_perms(current_selinux_state,
-				    ssid, isec->sid, isec->sclass,
+				    ssid, update_sid(isec), isec->sclass,
 				    requested, driver, xperm, &ad);
 out:
 	return rc;
@@ -3947,6 +4159,7 @@ static int selinux_file_open(struct file *file)
 	 * Task label is already saved in the file security
 	 * struct as its SID.
 	 */
+	//TODO: namespace?
 	fsec->isid = isec->sid;
 	fsec->pseqno = avc_policy_seqno(current_selinux_state);
 	/*
@@ -4046,21 +4259,23 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
  * set the file creation context in a security record to the same as the
  * objective context of the specified inode
  */
+//TODO: namespace?
 static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 {
 	struct inode_security_struct *isec = inode_security(inode);
 	struct task_security_struct *tsec = selinux_cred(new);
 	u32 sid = current_sid();
+	u32 isid = update_sid(isec);
 	int ret;
 
 	ret = avc_has_perm(tsec->state,
-			   sid, isec->sid,
+			   sid, isid,
 			   SECCLASS_KERNEL_SERVICE,
 			   KERNEL_SERVICE__CREATE_FILES_AS,
 			   NULL);
 
 	if (ret == 0)
-		tsec->create_sid = isec->sid;
+		tsec->create_sid = isid;
 	return ret;
 }
 
@@ -4105,7 +4320,7 @@ static int selinux_kernel_module_from_file(struct file *file)
 
 	isec = inode_security(file_inode(file));
 	return avc_has_perm(current_selinux_state,
-			    sid, isec->sid, SECCLASS_SYSTEM,
+			    sid, update_sid(isec), SECCLASS_SYSTEM,
 				SYSTEM__MODULE_LOAD, &ad);
 }
 
@@ -4267,6 +4482,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 }
@@ -4633,6 +4849,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 	isec->sclass = sclass;
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 
 	if (sock->sk) {
@@ -4921,7 +5138,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 		return err;
 
 	isec = inode_security_novalidate(SOCK_INODE(sock));
-	spin_lock(&isec->lock);
+	update_sid_and_lock(isec);
 	sclass = isec->sclass;
 	sid = isec->sid;
 	spin_unlock(&isec->lock);
@@ -4929,6 +5146,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 	newisec = inode_security_novalidate(SOCK_INODE(newsock));
 	newisec->sclass = sclass;
 	newisec->sid = sid;
+	newisec->namespace_id = current_selinux_state->id;
 	newisec->initialized = LABEL_INITIALIZED;
 
 	return 0;
@@ -5213,7 +5431,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
 
 	if (sock && family == PF_UNIX) {
 		isec = inode_security_novalidate(SOCK_INODE(sock));
-		peer_secid = isec->sid;
+		peer_secid = update_sid(isec);
 	} else if (skb)
 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -5280,8 +5498,11 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 	struct sk_security_struct *sksec = sk->sk_security;
 
 	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
-	    sk->sk_family == PF_UNIX)
+	    sk->sk_family == PF_UNIX) {
 		isec->sid = sksec->sid;
+		//TODO: namespace?
+		//isec->namespace_id = ?
+	}
 	sksec->sclass = isec->sclass;
 }
 
@@ -7331,7 +7552,13 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 static void selinux_state_free(struct work_struct *work);
 
-int selinux_state_create(struct selinux_state *parent, struct selinux_state **state)
+u64 selinux_new_state_id(void)
+{
+	return atomic64_fetch_add(1, &selinux_namespace_id);
+}
+
+int selinux_state_create(struct selinux_state *parent, struct selinux_state **state,
+						const char *suffix)
 {
 	struct selinux_state *newstate;
 	int rc;
@@ -7340,6 +7567,7 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 	if (!newstate)
 		return -ENOMEM;
 
+	newstate->id = selinux_new_state_id();
 	refcount_set(&newstate->count, 1);
 	INIT_WORK(&newstate->work, selinux_state_free);
 
@@ -7352,7 +7580,12 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 
 	if (parent)
 		newstate->parent = get_selinux_state(parent);
-
+	strcpy(newstate->xattr_name, XATTR_SELINUX_SUFFIX);
+	rc = strlen(suffix);
+	if (rc) {
+		strcat(newstate->xattr_name, ".");
+		strncat(newstate->xattr_name, suffix, rc);
+	}
 	*state = newstate;
 	return 0;
 err:
@@ -7385,7 +7618,7 @@ static __init int selinux_init(void)
 {
 	pr_info("SELinux:  Initializing.\n");
 
-	if (selinux_state_create(NULL, &init_selinux_state))
+	if (selinux_state_create(NULL, &init_selinux_state, ""))
 		panic("SELinux: Could not create initial namespace\n");
 	enforcing_set(init_selinux_state, selinux_enforcing_boot);
 	init_selinux_state->checkreqprot = selinux_checkreqprot_boot;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6ad1db45b0d9..21566a1541f4 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -42,8 +42,10 @@ struct inode_security_struct {
 	u16 sclass;		/* security class of this object */
 	unsigned char initialized;	/* initialization flag */
 	spinlock_t lock;
+	u64 namespace_id;	/* pointer to selinux_state */
 };
 
+//TODO: namespace?
 struct file_security_struct {
 	u32 sid;		/* SID of open file description */
 	u32 fown_sid;		/* SID of file owner (for SIGIO) */
@@ -54,6 +56,9 @@ struct file_security_struct {
 struct superblock_security_head {
 	struct list_head head;		/* list head of superblock_security_struct */
 	spinlock_t lock;
+
+	const struct xattr_handler **old_s_xattr;
+	const struct xattr_handler *xattr_handler;
 };
 
 struct superblock_security_struct {
@@ -178,7 +183,7 @@ static inline struct ipc_security_struct *selinux_ipc(
  */
 static inline u32 current_sid(void)
 {
-	const struct task_security_struct *tsec = selinux_cred(current_cred());
+	const struct task_security_struct *tsec = selinux_cred(current_real_cred());
 
 	return tsec->sid;
 }
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index a5b698aae38c..0ab6b433dc9c 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,9 +111,13 @@ struct selinux_state {
 	struct selinux_policy __rcu *policy;
 	struct mutex policy_mutex;
 	struct selinux_state *parent;
+	u64 id;
+	char xattr_name[XATTR_NAME_MAX];
 } __randomize_layout;
 
-int selinux_state_create(struct selinux_state *parent, struct selinux_state **state);
+u64 selinux_new_state_id(void);
+int selinux_state_create(struct selinux_state *parent, struct selinux_state **state,
+						const char *suffix);
 void __put_selinux_state(struct selinux_state *state);
 
 void selinux_policy_free(struct selinux_policy *policy);
@@ -151,7 +155,7 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
 	return cred->security + selinux_blob_sizes.lbs_cred;
 }
 
-#define current_selinux_state (selinux_cred(current_cred())->state)
+#define current_selinux_state (selinux_cred(current_real_cred())->state)
 
 #define cred_selinux_state(cred) (selinux_cred(cred)->state)
 
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 9892527f2269..2da27f2fc2e3 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -31,6 +31,7 @@
 #include <linux/uaccess.h>
 #include <linux/kobject.h>
 #include <linux/ctype.h>
+#include <linux/xattr.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -347,10 +348,10 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
 	struct selinux_state *state = fsi->state;
-	char *page;
-	ssize_t length;
-	bool set;
-	int rc;
+	struct cred *cred;
+	struct task_security_struct *tsec;
+	char *suffix, *p;
+	ssize_t len;
 
 	if (state != current_selinux_state)
 		return -EPERM;
@@ -362,49 +363,76 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
-	rc = avc_has_perm(current_selinux_state, current_sid(),
+	len = avc_has_perm(current_selinux_state, current_sid(),
 			  SECINITSID_SECURITY, SECCLASS_SECURITY,
 			  SECURITY__UNSHARE, NULL);
-	if (rc)
-		return rc;
+	if (len)
+		return len;
 
-	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	if (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2)
+		return -EINVAL;
 
-	length = -EINVAL;
-	if (kstrtobool(page, &set))
-		goto out;
+	suffix = memdup_user_nul(buf, count);
+	if (IS_ERR(suffix))
+		return PTR_ERR(suffix);
 
-	if (set) {
-		struct cred *cred = prepare_creds();
-		struct task_security_struct *tsec;
+	len = strnlen(suffix, count);
 
-		if (!cred) {
-			length = -ENOMEM;
-			goto out;
-		}
-		tsec = selinux_cred(cred);
-		if (selinux_state_create(state, &tsec->state)) {
-			abort_creds(cred);
-			length = -ENOMEM;
-			goto out;
-		}
-		tsec->osid = tsec->sid = SECINITSID_KERNEL;
-		tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
-			tsec->sockcreate_sid = SECSID_NULL;
-		tsec->parent_cred = get_current_cred();
-		commit_creds(cred);
+	/* cleanup some trash at the end of string */
+	for (p = suffix + len - 1; p >= suffix && isspace(*p); p--)
+		*p = 0;
+
+	len = p - suffix + 1;
+
+
+	/* TODO: check for uniqueness! */
+/*
+	if (!strcmp("", suffix)) {
+		len = -EINVAL;
+		goto out;
 	}
+*/
+
+	cred = prepare_creds();
+	if (!cred) {
+		len = -ENOMEM;
+		goto out;
+	}
+	tsec = cred->security;
+	if (selinux_state_create(state, &tsec->state, suffix)) {
+		abort_creds(cred);
+		len = -ENOMEM;
+		goto out;
+	}
+
+	tsec->osid = tsec->sid = SECINITSID_KERNEL;
+	tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
+		tsec->sockcreate_sid = SECSID_NULL;
+	tsec->parent_cred = get_current_cred();
+	commit_creds(cred);
 
-	length = count;
 out:
-	kfree(page);
-	return length;
+	kfree(suffix);
+	return len < 0 ? len : count;
+}
+
+static ssize_t sel_read_unshare(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+	struct selinux_state *state = fsi->state;
+	size_t slen = sizeof(XATTR_SELINUX_SUFFIX);
+
+	if (state->id != current_selinux_state->id)
+		return -EPERM;
+
+	return simple_read_from_buffer(buf, count, ppos, state->xattr_name + slen,
+									strlen(state->xattr_name + slen));
 }
 
 static const struct file_operations sel_unshare_ops = {
 	.write		= sel_write_unshare,
+	.read		= sel_read_unshare,
 	.llseek		= generic_file_llseek,
 };
 
@@ -2174,7 +2202,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
 		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
 		[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
 					S_IWUGO},
-		[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200},
+		[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0600},
 		/* last one */ {""}
 	};
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 5/7] SELINUXNS: Migrate all open files and all vma to new namespace
  2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
                               ` (3 preceding siblings ...)
  2022-04-18  9:45             ` [RFC PATCH 4/7] SELINUXNS: Namespacing for xattrs Alexander Kozhevnikov
@ 2022-04-18  9:45             ` 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
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

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

When process switched to another namespace and loads a new policy, the
following problem occurs: the current open files in their
file_security_struct contain the sid's relevant to the loaded policy
in the old namespace. Under the new policy, they have completely
random (incorrect) values, and, as a rule, accessing such descriptors
leads to failure. For example, a process gets EACCES when writing to its
own stdout.

Our solution: reinitialize sid's and isid's to actual values in new policy
of all opened files, as well as of files referenced by process's VMA.

Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c     | 94 +++++++++++++++++++++++++++++++++++-
 security/selinux/selinuxfs.c |  2 +-
 2 files changed, 93 insertions(+), 3 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b618c4e0ef36..74d32b6a4855 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -91,6 +91,7 @@
 #include <uapi/linux/mount.h>
 #include <linux/fsnotify.h>
 #include <linux/fanotify.h>
+#include <linux/sched/mm.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -4159,8 +4160,7 @@ static int selinux_file_open(struct file *file)
 	 * Task label is already saved in the file security
 	 * struct as its SID.
 	 */
-	//TODO: namespace?
-	fsec->isid = isec->sid;
+	fsec->isid = update_sid(isec);
 	fsec->pseqno = avc_policy_seqno(current_selinux_state);
 	/*
 	 * Since the inode label or policy seqno may have changed
@@ -7659,6 +7659,8 @@ static void delayed_superblock_init(struct super_block *sb, void *unused)
 	selinux_set_mnt_opts(sb, NULL, 0, NULL);
 }
 
+static void migrate_files(void);
+
 void selinux_complete_init(void)
 {
 	pr_debug("SELinux:  Completing initialization.\n");
@@ -7666,6 +7668,9 @@ void selinux_complete_init(void)
 	/* Set up any superblocks initialized prior to the policy load. */
 	pr_debug("SELinux:  Setting up existing superblocks.\n");
 	iterate_supers(delayed_superblock_init, NULL);
+
+	if (current_selinux_state->id != 0)
+		migrate_files();
 }
 
 /* SELinux requires early initialization in order to label
@@ -7816,3 +7821,88 @@ int selinux_disable(struct selinux_state *state)
 	return 0;
 }
 #endif
+
+
+/* TODO: check&return errors? */
+static void migrate_fds(void)
+{
+	unsigned int fd;
+	struct files_struct *files = current->files;
+	u32 tsid = current_sid();
+
+	rcu_read_lock();
+	for (fd = 0; fd < files_fdtable(files)->max_fds; fd++) {
+		struct inode *inode;
+		struct file_security_struct *fsec;
+		struct file *file = fcheck_files(files, fd);
+
+		if (!file)
+			continue;
+
+		fsec = selinux_file(file);
+
+		fsec->sid = fsec->fown_sid = tsid;
+		inode = file_inode(file);
+		if (inode) {
+			get_file(file);
+			rcu_read_unlock();
+			fsec->isid = update_sid(inode_security(inode));
+			rcu_read_lock();
+			fput(file);
+		}
+	}
+	rcu_read_unlock();
+}
+
+static int migrate_vmas(void)
+{
+	int ret;
+	struct mempolicy *task_mempolicy;
+	struct vm_area_struct *vma;
+	u32 tsid = current_sid();
+	struct mm_struct *mm =  mm_access(current, PTRACE_MODE_READ | PTRACE_MODE_FSCREDS);
+
+	if (IS_ERR_OR_NULL(mm))
+		return PTR_ERR(mm);
+
+	ret = mmap_read_lock_killable(mm);
+	if (ret)
+		goto out_put_mm;
+
+	task_mempolicy = get_task_policy(current);
+	mpol_get(task_mempolicy);
+
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		struct file *file = vma->vm_file;
+		struct file_security_struct *fsec;
+		struct inode *inode;
+
+		if (!file)
+			continue;
+
+		fsec = selinux_file(file);
+
+		inode = file_inode(file);
+		if (inode)
+			fsec->isid = update_sid(inode_security(inode));
+
+		fsec->sid = fsec->fown_sid = tsid;
+	}
+
+	mpol_put(task_mempolicy);
+	mmap_read_unlock(mm);
+
+out_put_mm:
+	mmput(mm);
+
+	return ret;
+}
+
+/* TODO return error? */
+void migrate_files(void)
+{
+	migrate_fds();
+
+/* TODO: return error */
+	migrate_vmas();
+}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 2da27f2fc2e3..18c5383b87a9 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -2306,7 +2306,7 @@ static int selinuxfs_compare(struct super_block *sb, struct fs_context *fc)
 {
 	struct selinux_fs_info *fsi = sb->s_fs_info;
 
-	return (current_selinux_state == fsi->state);
+	return (current_selinux_state->id == fsi->state->id);
 }
 
 static int sel_get_tree(struct fs_context *fc)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 6/7] SELINUXNS: Fixing superblock security structure memory leakage
  2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
                               ` (4 preceding siblings ...)
  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             ` Alexander Kozhevnikov
  2022-04-18  9:45             ` [RFC PATCH 7/7] SELINUXNS: Fixing concurrency issues Alexander Kozhevnikov
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

List of sbsec per state added.
All sbsec attached to state are cleared at namespace creator process exit.

Sbsec state is also replaced with namespace id. Original code provided by Igor Baranov
with refactoring to ajust current changes in sbsec handling.

Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c            | 76 ++++++++++++++++++++++-------
 security/selinux/include/objsec.h   |  7 ++-
 security/selinux/include/security.h |  2 +
 security/selinux/selinuxfs.c        |  3 ++
 4 files changed, 67 insertions(+), 21 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 74d32b6a4855..e17175ff707d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -104,6 +104,9 @@
 #include "audit.h"
 #include "avc_ss.h"
 
+/* SUPERBLOCK STATE LOCK */
+static spinlock_t sb_state_lock;
+
 /* SECMARK reference count */
 static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
@@ -2755,11 +2758,21 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 
 /* superblock security operations */
 
+static void sbsec_counting_init(struct list_head *sb_count_head)
+{
+	//* INIT Superblocks counting list
+	INIT_LIST_HEAD(sb_count_head);
+}
+
+static void sbsec_counting_add(struct superblock_security_struct *sbsec, struct selinux_state *state)
+{
+	list_add(&sbsec->sbsec_count, &state->sb_count_head);
+}
+
 static void sbsec_head_init(struct super_block *sb,
 			    struct superblock_security_head *sbsech)
 {
 	INIT_LIST_HEAD(&sbsech->head);
-	spin_lock_init(&sbsech->lock);
 	sbsech->xattr_handler = NULL;
 	sbsech->old_s_xattr = NULL;
 }
@@ -2779,7 +2792,7 @@ sbsec_alloc(struct superblock_security_head *sbsech)
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
-	sbsec->state = get_selinux_state(current_selinux_state);
+	sbsec->namespace_id = current_selinux_state->id;
 
 	return sbsec;
 }
@@ -2787,18 +2800,18 @@ sbsec_alloc(struct superblock_security_head *sbsech)
 struct superblock_security_struct *
 find_sbsec(struct superblock_security_head *sbsech)
 {
-	struct superblock_security_struct *cur, *new;
+	struct superblock_security_struct *cur, *new, *tmp;
 
 	cur = container_of(sbsech->head.next, struct superblock_security_struct, sbsec_list);
-	if (cur->state == current_selinux_state)
+	if (cur->namespace_id == current_selinux_state->id)
 		return cur;
 
-	spin_lock(&sbsech->lock);
-	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
-		if (cur->state == current_selinux_state)
+	spin_lock(&sb_state_lock);
+	list_for_each_entry_safe(cur, tmp, &sbsech->head, sbsec_list) {
+		if (cur->namespace_id == current_selinux_state->id)
 			goto unlock;
 	}
-	spin_unlock(&sbsech->lock);
+	spin_unlock(&sb_state_lock);
 
 	new = sbsec_alloc(sbsech);
 	if (!new) {
@@ -2806,15 +2819,22 @@ find_sbsec(struct superblock_security_head *sbsech)
 		goto out;
 	}
 
-	spin_lock(&sbsech->lock);
-	list_for_each_entry(cur, &sbsech->head, sbsec_list) {
-		if (cur->state == current_selinux_state)
-			goto unlock;
+	spin_lock(&sb_state_lock);
+	list_for_each_entry_safe(cur, tmp,  &sbsech->head, sbsec_list) {
+		if (cur->namespace_id == current_selinux_state->id)
+			goto free_unlock;
 	}
 	list_add(&new->sbsec_list, &sbsech->head);
+	sbsec_counting_add(new, current_selinux_state);
 	cur = new;
+	goto unlock;
+
+free_unlock:
+	spin_unlock(&sb_state_lock);
+	kfree(new);
+	return cur;
 unlock:
-	spin_unlock(&sbsech->lock);
+	spin_unlock(&sb_state_lock);
 out:
 	return cur;
 }
@@ -2828,9 +2848,10 @@ static int selinux_sb_alloc_security(struct super_block *sb)
 	sbsec = sbsec_alloc(sbsech);
 	if (!sbsec)
 		return -ENOMEM;
-	spin_lock(&sbsech->lock);
+	spin_lock(&sb_state_lock);
 	list_add(&sbsec->sbsec_list, &sbsech->head);
-	spin_unlock(&sbsech->lock);
+	sbsec_counting_add(sbsec, current_selinux_state);
+	spin_unlock(&sb_state_lock);
 	return 0;
 }
 
@@ -2840,7 +2861,7 @@ static void selinux_sb_free_security(struct super_block *sb)
 	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);
+		list_del(&entry->sbsec_count); // Remove sbsec from list of sb-s for this namespace
 		kfree(entry);
 	}
 	if (sbsech->old_s_xattr) {
@@ -2851,6 +2872,16 @@ static void selinux_sb_free_security(struct super_block *sb)
 	}
 }
 
+static void selinux_state_sb_free_list(struct selinux_state *state)
+{
+	struct superblock_security_struct *cur, *tmp;
+
+	list_for_each_entry_safe(cur, tmp, &state->sb_count_head, sbsec_count) {
+		list_del(&cur->sbsec_list);
+		kfree(cur);
+	};
+}
+
 static inline int opt_len(const char *s)
 {
 	bool open_quote = false;
@@ -4191,6 +4222,12 @@ static void selinux_cred_free(struct cred *cred)
 {
 	struct task_security_struct *tsec = selinux_cred(cred);
 
+	if (tsec->state->owner_cred == cred) {
+		/* Free all sb security for this state here - do only once */
+		selinux_state_sb_free_list(tsec->state);
+		tsec->state->owner_cred = NULL;
+	};
+
 	put_selinux_state(tsec->state);
 	if (tsec->parent_cred)
 		put_cred(tsec->parent_cred);
@@ -7573,7 +7610,7 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 
 	mutex_init(&newstate->status_lock);
 	mutex_init(&newstate->policy_mutex);
-
+	sbsec_counting_init(&newstate->sb_count_head);
 	rc = selinux_avc_create(&newstate->avc);
 	if (rc)
 		goto err;
@@ -7587,6 +7624,7 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 		strncat(newstate->xattr_name, suffix, rc);
 	}
 	*state = newstate;
+	pr_info("SELinux: State create.\n");
 	return 0;
 err:
 	kfree(newstate);
@@ -7598,6 +7636,8 @@ static void selinux_state_free(struct work_struct *work)
 	struct selinux_state *parent, *state =
 		container_of(work, struct selinux_state, work);
 
+	pr_info("SELinux: State free.\n");
+
 	do {
 		parent = state->parent;
 		if (state->status_page)
@@ -7623,6 +7663,8 @@ static __init int selinux_init(void)
 	enforcing_set(init_selinux_state, selinux_enforcing_boot);
 	init_selinux_state->checkreqprot = selinux_checkreqprot_boot;
 
+	spin_lock_init(&sb_state_lock);
+
 	/* Set the security state for the initial task. */
 	cred_init_security();
 
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 21566a1541f4..6d9c63c57620 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -55,8 +55,6 @@ struct file_security_struct {
 
 struct superblock_security_head {
 	struct list_head head;		/* list head of superblock_security_struct */
-	spinlock_t lock;
-
 	const struct xattr_handler **old_s_xattr;
 	const struct xattr_handler *xattr_handler;
 };
@@ -69,10 +67,11 @@ struct superblock_security_struct {
 	unsigned short behavior;	/* labeling behavior */
 	unsigned short flags;		/* which mount options were specified */
 	struct mutex lock;
-	struct list_head isec_head;
 	spinlock_t isec_lock;
-	struct selinux_state *state;	/* pointer to selinux_state */
+	struct list_head isec_head;
+	u64 namespace_id;           /* id of selinux_state */
 	struct list_head sbsec_list;
+	struct list_head sbsec_count;
 };
 
 struct msg_security_struct {
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 0ab6b433dc9c..48021a7fb92f 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,6 +111,8 @@ struct selinux_state {
 	struct selinux_policy __rcu *policy;
 	struct mutex policy_mutex;
 	struct selinux_state *parent;
+	const struct cred *owner_cred;  /* cred of process created this state */
+	struct list_head sb_count_head;
 	u64 id;
 	char xattr_name[XATTR_NAME_MAX];
 } __randomize_layout;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 18c5383b87a9..5a29516d81a8 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -410,6 +410,9 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 		tsec->sockcreate_sid = SECSID_NULL;
 	tsec->parent_cred = get_current_cred();
 	commit_creds(cred);
+	tsec->state->owner_cred = current_cred();
+	pr_debug("SELINUXNS: State init finished owner cred pntr = %p - %p\n",
+			 &tsec->state, tsec->state->owner_cred);
 
 out:
 	kfree(suffix);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RFC PATCH 7/7] SELINUXNS: Fixing concurrency issues
  2022-04-18  9:45           ` [RFC PATCH 0/7] SELinux-namespace Alexander Kozhevnikov
                               ` (5 preceding siblings ...)
  2022-04-18  9:45             ` [RFC PATCH 6/7] SELINUXNS: Fixing superblock security structure memory leakage Alexander Kozhevnikov
@ 2022-04-18  9:45             ` Alexander Kozhevnikov
  6 siblings, 0 replies; 15+ messages in thread
From: Alexander Kozhevnikov @ 2022-04-18  9:45 UTC (permalink / raw)
  To: paul
  Cc: alexander.kozhevnikov, artem.kuzin, hw.likun, igor.baranov,
	jamorris, linux-security-module, selinux, stephen.smalley.work,
	xiujianfeng, yusongping, anton.sirazetdinov

1) Fix of filesystem info ZERO pointer dereference due to concurrency race.
It was possible for selinuxfs info structure to be cleared when it is still in use.
The decision was not to use locks to avoid this but just add zero pointer checks
in the code and assign NULL to the pointer before actual structure clearance.

2) Fix for selinuxfs mutex concurrency.
As it is possible to have the same selinuxfs filesystem mounted in different states
we need a global mutex lock on all write operations in selinuxns.

3) Inode deferred initialization list removed.
This list attached to sbsec was used to do deferred isec init after selinux state
init was complete.
This functionality is anyway implemented now through revalidate procedure.
List looks obsolete now.

Signed-off-by: Alexander Kozhevnikov <alexander.kozhevnikov@huawei.com>
Signed-off-by: Igor Baranov <igor.baranov@huawei.com>
---
 security/selinux/hooks.c          |  56 +-----
 security/selinux/include/objsec.h |   1 -
 security/selinux/selinuxfs.c      | 275 +++++++++++++++++++++++-------
 security/selinux/ss/services.c    |  12 +-
 4 files changed, 227 insertions(+), 117 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e17175ff707d..db5bdfd7c3fb 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -346,27 +346,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
 
 static void inode_free_security(struct inode *inode)
 {
-	struct inode_security_struct *isec = selinux_inode(inode);
-	struct superblock_security_struct *sbsec;
-
-	if (!isec)
-		return;
-	sbsec = selinux_superblock(inode->i_sb);
-	/*
-	 * As not all inode security structures are in a list, we check for
-	 * empty list outside of the lock to make sure that we won't waste
-	 * time taking a lock doing nothing.
-	 *
-	 * The list_del_init() function can be safely called more than once.
-	 * It should not be possible for this function to be called with
-	 * concurrent list_add(), but for better safety against future changes
-	 * in the code, we use list_empty_careful() here.
-	 */
-	if (!list_empty_careful(&isec->list)) {
-		spin_lock(&sbsec->isec_lock);
-		list_del_init(&isec->list);
-		spin_unlock(&sbsec->isec_lock);
-	}
+ /* NOTHING TO DO NOW */
 }
 
 struct selinux_mnt_opts {
@@ -641,27 +621,6 @@ static int sb_finish_set_opts(struct super_block *sb)
 	/* Initialize the root inode. */
 	rc = inode_doinit_with_dentry(root_inode, root);
 
-	/* Initialize any other inodes associated with the superblock, e.g.
-	   inodes created prior to initial policy load or inodes created
-	   during get_sb by a pseudo filesystem that directly
-	   populates itself. */
-	spin_lock(&sbsec->isec_lock);
-	while (!list_empty(&sbsec->isec_head)) {
-		struct inode_security_struct *isec =
-				list_first_entry(&sbsec->isec_head,
-					   struct inode_security_struct, list);
-		struct inode *inode = isec->inode;
-		list_del_init(&isec->list);
-		spin_unlock(&sbsec->isec_lock);
-		inode = igrab(inode);
-		if (inode) {
-			if (!IS_PRIVATE(inode))
-				inode_doinit_with_dentry(inode, NULL);
-			iput(inode);
-		}
-		spin_lock(&sbsec->isec_lock);
-	}
-	spin_unlock(&sbsec->isec_lock);
 out:
 	return rc;
 }
@@ -1602,13 +1561,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
 	sbsec = selinux_superblock(inode->i_sb);
 	if (!(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. */
-		spin_lock(&sbsec->isec_lock);
-		if (list_empty(&isec->list))
-			list_add(&isec->list, &sbsec->isec_head);
-		spin_unlock(&sbsec->isec_lock);
 		return 0;
 	}
 
@@ -2786,8 +2738,6 @@ sbsec_alloc(struct superblock_security_head *sbsech)
 	if (!sbsec)
 		return NULL;
 	mutex_init(&sbsec->lock);
-	INIT_LIST_HEAD(&sbsec->isec_head);
-	spin_lock_init(&sbsec->isec_lock);
 	sbsec->sbsech = sbsech;
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
@@ -3133,7 +3083,6 @@ static int selinux_inode_alloc_security(struct inode *inode)
 	u32 sid = current_sid();
 
 	spin_lock_init(&isec->lock);
-	INIT_LIST_HEAD(&isec->list);
 	isec->inode = inode;
 	isec->sid = SECINITSID_UNLABELED;
 	isec->sclass = SECCLASS_FILE;
@@ -7654,6 +7603,8 @@ void __put_selinux_state(struct selinux_state *state)
 	schedule_work(&state->work);
 }
 
+extern struct mutex selinuxfs_mutex;
+
 static __init int selinux_init(void)
 {
 	pr_info("SELinux:  Initializing.\n");
@@ -7664,6 +7615,7 @@ static __init int selinux_init(void)
 	init_selinux_state->checkreqprot = selinux_checkreqprot_boot;
 
 	spin_lock_init(&sb_state_lock);
+	mutex_init(&selinuxfs_mutex);
 
 	/* Set the security state for the initial task. */
 	cred_init_security();
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6d9c63c57620..22b577540224 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -36,7 +36,6 @@ enum label_initialized {
 
 struct inode_security_struct {
 	struct inode *inode;	/* back pointer to inode object */
-	struct list_head list;	/* list of inode_security_struct */
 	u32 task_sid;		/* SID of creating task */
 	u32 sid;		/* SID of this object */
 	u16 sclass;		/* security class of this object */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5a29516d81a8..0cd609744c98 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -43,6 +43,8 @@
 #include "objsec.h"
 #include "conditional.h"
 
+struct mutex selinuxfs_mutex;    /* GLobal mutex for all selinuxfs access */
+
 enum sel_inos {
 	SEL_ROOT_INO = 2,
 	SEL_LOAD,	/* load policy */
@@ -102,15 +104,16 @@ static void selinux_fs_info_free(struct super_block *sb)
 	struct selinux_fs_info *fsi = sb->s_fs_info;
 	int i;
 
+	sb->s_fs_info = NULL;
 	if (fsi) {
 		put_selinux_state(fsi->state);
 		for (i = 0; i < fsi->bool_num; i++)
 			kfree(fsi->bool_pending_names[i]);
 		kfree(fsi->bool_pending_names);
 		kfree(fsi->bool_pending_values);
+		kfree(fsi);
 	}
-	kfree(sb->s_fs_info);
-	sb->s_fs_info = NULL;
+
 }
 
 #define SEL_INITCON_INO_OFFSET		0x01000000
@@ -131,6 +134,9 @@ static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
 	char tmpbuf[TMPBUFLEN];
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
 			   enforcing_enabled(fsi->state));
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -142,11 +148,15 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
 
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *page = NULL;
 	ssize_t length;
 	int old_value, new_value;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	if (state != current_selinux_state)
 		return -EPERM;
 
@@ -157,9 +167,13 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
+	mutex_lock(&selinuxfs_mutex);
+
 	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		goto out_unlock;
+	}
 
 	length = -EINVAL;
 	if (sscanf(page, "%d", &new_value) != 1)
@@ -192,6 +206,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
 	length = count;
 out:
 	kfree(page);
+out_unlock:
+	mutex_unlock(&selinuxfs_mutex);
 	return length;
 }
 #else
@@ -208,11 +224,17 @@ static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
 					size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char tmpbuf[TMPBUFLEN];
 	ssize_t length;
 	ino_t ino = file_inode(filp)->i_ino;
-	int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
+	int handle_unknown;
+
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
+	handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
 		security_get_reject_unknown(state) :
 		!security_get_allow_unknown(state);
 
@@ -228,7 +250,12 @@ static const struct file_operations sel_handle_unknown_ops = {
 static int sel_open_handle_status(struct inode *inode, struct file *filp)
 {
 	struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
-	struct page    *status = selinux_kernel_status_page(fsi->state);
+	struct page    *status;
+
+	if (fsi == NULL)
+		return -EINVAL;
+
+	status = selinux_kernel_status_page(fsi->state);
 
 	if (!status)
 		return -ENOMEM;
@@ -290,6 +317,9 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
 	int new_value;
 	int enforcing;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
@@ -316,8 +346,10 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
 		goto out;
 
 	if (new_value) {
+		mutex_lock(&selinuxfs_mutex);
 		enforcing = enforcing_enabled(fsi->state);
 		length = selinux_disable(fsi->state);
+		mutex_unlock(&selinuxfs_mutex);
 		if (length)
 			goto out;
 		audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
@@ -347,31 +379,33 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	struct cred *cred;
 	struct task_security_struct *tsec;
 	char *suffix, *p;
 	ssize_t len;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	if (state != current_selinux_state)
 		return -EPERM;
 
-	if (count >= PAGE_SIZE)
-		return -ENOMEM;
-
 	/* No partial writes. */
 	if (*ppos != 0)
 		return -EINVAL;
 
+	if ((count >= PAGE_SIZE) ||
+	    (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2))
+		return -EINVAL;
+
 	len = avc_has_perm(current_selinux_state, current_sid(),
 			  SECINITSID_SECURITY, SECCLASS_SECURITY,
 			  SECURITY__UNSHARE, NULL);
 	if (len)
 		return len;
 
-	if (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2)
-		return -EINVAL;
-
 	suffix = memdup_user_nul(buf, count);
 	if (IS_ERR(suffix))
 		return PTR_ERR(suffix);
@@ -423,14 +457,19 @@ static ssize_t sel_read_unshare(struct file *file, char __user *buf,
 				size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	size_t slen = sizeof(XATTR_SELINUX_SUFFIX);
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
+
 	if (state->id != current_selinux_state->id)
 		return -EPERM;
 
 	return simple_read_from_buffer(buf, count, ppos, state->xattr_name + slen,
-									strlen(state->xattr_name + slen));
+						strlen(state->xattr_name + slen));
 }
 
 static const struct file_operations sel_unshare_ops = {
@@ -480,6 +519,9 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
 	char tmpbuf[TMPBUFLEN];
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
 			   security_mls_enabled(fsi->state));
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -498,13 +540,17 @@ struct policy_load_memory {
 static int sel_open_policy(struct inode *inode, struct file *filp)
 {
 	struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	struct policy_load_memory *plm = NULL;
 	int rc;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	BUG_ON(filp->private_data);
 
-	mutex_lock(&fsi->state->policy_mutex);
+	mutex_lock(&selinuxfs_mutex);
 
 	rc = avc_has_perm(current_selinux_state,
 			  current_sid(), SECINITSID_SECURITY,
@@ -535,11 +581,11 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
 
 	filp->private_data = plm;
 
-	mutex_unlock(&fsi->state->policy_mutex);
+	mutex_unlock(&selinuxfs_mutex);
 
 	return 0;
 err:
-	mutex_unlock(&fsi->state->policy_mutex);
+	mutex_unlock(&selinuxfs_mutex);
 
 	if (plm)
 		vfree(plm->data);
@@ -552,6 +598,9 @@ static int sel_release_policy(struct inode *inode, struct file *filp)
 	struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
 	struct policy_load_memory *plm = filp->private_data;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	BUG_ON(!plm);
 
 	fsi->policy_opened = 0;
@@ -726,10 +775,13 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
 	ssize_t length;
 	void *data = NULL;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
-	mutex_lock(&fsi->state->policy_mutex);
+	mutex_lock(&selinuxfs_mutex);
 
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
@@ -773,7 +825,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
 		from_kuid(&init_user_ns, audit_get_loginuid(current)),
 		audit_get_sessionid(current));
 out:
-	mutex_unlock(&fsi->state->policy_mutex);
+	mutex_unlock(&selinuxfs_mutex);
 	vfree(data);
 	return length;
 }
@@ -786,16 +838,20 @@ static const struct file_operations sel_load_ops = {
 static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *canon = NULL;
 	u32 sid, len;
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
 	if (length)
-		goto out;
+		return length;
 
 	length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
 	if (length)
@@ -826,6 +882,9 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
 	char tmpbuf[TMPBUFLEN];
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot);
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
@@ -838,6 +897,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
 	ssize_t length;
 	unsigned int new_value;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
@@ -855,9 +917,13 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
+	mutex_lock(&selinuxfs_mutex);
+
 	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		goto out_unlock;
+	}
 
 	length = -EINVAL;
 	if (sscanf(page, "%u", &new_value) != 1)
@@ -875,6 +941,8 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
 	length = count;
 out:
 	kfree(page);
+out_unlock:
+	mutex_unlock(&selinuxfs_mutex);
 	return length;
 }
 static const struct file_operations sel_checkreqprot_ops = {
@@ -888,13 +956,17 @@ static ssize_t sel_write_validatetrans(struct file *file,
 					size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
 	char *req = NULL;
 	u32 osid, nsid, tsid;
 	u16 tclass;
 	int rc;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	if (state != current_selinux_state)
 		return -EPERM;
 
@@ -902,16 +974,16 @@ static ssize_t sel_write_validatetrans(struct file *file,
 			  current_sid(), SECINITSID_SECURITY,
 			  SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
 	if (rc)
-		goto out;
+		return rc;
 
 	rc = -ENOMEM;
 	if (count >= PAGE_SIZE)
-		goto out;
+		return rc;
 
 	/* No partial writes. */
 	rc = -EINVAL;
 	if (*ppos != 0)
-		goto out;
+		return rc;
 
 	req = memdup_user_nul(buf, count);
 	if (IS_ERR(req)) {
@@ -953,10 +1025,10 @@ static ssize_t sel_write_validatetrans(struct file *file,
 	if (!rc)
 		rc = count;
 out:
-	kfree(req);
-	kfree(oldcon);
-	kfree(newcon);
 	kfree(taskcon);
+	kfree(newcon);
+	kfree(oldcon);
+	kfree(req);
 	return rc;
 }
 
@@ -990,6 +1062,9 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
 	char *data;
 	ssize_t rv;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
@@ -1005,6 +1080,7 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
 		simple_transaction_set(file, rv);
 		rv = size;
 	}
+
 	return rv;
 }
 
@@ -1024,18 +1100,23 @@ static const struct file_operations transaction_ops = {
 static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *scon = NULL, *tcon = NULL;
 	u32 ssid, tsid;
 	u16 tclass;
 	struct av_decision avd;
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
+	state = fsi->state;
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
 	if (length)
-		goto out;
+		return length;
+
 
 	length = -ENOMEM;
 	scon = kzalloc(size + 1, GFP_KERNEL);
@@ -1075,7 +1156,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
 static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *scon = NULL, *tcon = NULL;
 	char *namebuf = NULL, *objname = NULL;
 	u32 ssid, tsid, newsid;
@@ -1085,6 +1166,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 	u32 len;
 	int nargs;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
@@ -1179,7 +1264,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
 static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *scon = NULL, *tcon = NULL;
 	u32 ssid, tsid, newsid;
 	u16 tclass;
@@ -1187,6 +1272,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
 	char *newcon = NULL;
 	u32 len;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
@@ -1240,7 +1329,7 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
 static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *con = NULL, *user = NULL, *ptr;
 	u32 sid, *sids = NULL;
 	ssize_t length;
@@ -1248,6 +1337,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 	int i, rc;
 	u32 len, nsids;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
@@ -1305,7 +1398,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
 static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *scon = NULL, *tcon = NULL;
 	u32 ssid, tsid, newsid;
 	u16 tclass;
@@ -1313,6 +1406,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
 	char *newcon = NULL;
 	u32 len;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
 			      SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
@@ -1388,7 +1485,10 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
 	const char *name = filep->f_path.dentry->d_name.name;
 
-	mutex_lock(&fsi->state->policy_mutex);
+	if (fsi == NULL)
+		return -EINVAL;
+
+	mutex_lock(&selinuxfs_mutex);
 
 	ret = -EINVAL;
 	if (index >= fsi->bool_num || strcmp(name,
@@ -1407,14 +1507,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
 	}
 	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
 			  fsi->bool_pending_values[index]);
-	mutex_unlock(&fsi->state->policy_mutex);
+	mutex_unlock(&selinuxfs_mutex);
 	ret = simple_read_from_buffer(buf, count, ppos, page, length);
 out_free:
 	free_page((unsigned long)page);
 	return ret;
 
 out_unlock:
-	mutex_unlock(&fsi->state->policy_mutex);
+	mutex_unlock(&selinuxfs_mutex);
 	goto out_free;
 }
 
@@ -1428,6 +1528,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
 	const char *name = filep->f_path.dentry->d_name.name;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
@@ -1438,11 +1541,13 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
-	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	mutex_lock(&selinuxfs_mutex);
 
-	mutex_lock(&fsi->state->policy_mutex);
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		goto out_unlock;
+	}
 
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
@@ -1467,8 +1572,10 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 	length = count;
 
 out:
-	mutex_unlock(&fsi->state->policy_mutex);
 	kfree(page);
+out_unlock:
+	mutex_unlock(&selinuxfs_mutex);
+
 	return length;
 }
 
@@ -1487,6 +1594,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 	ssize_t length;
 	int new_value;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	if (fsi->state != current_selinux_state)
 		return -EPERM;
 
@@ -1497,11 +1607,13 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 	if (*ppos != 0)
 		return -EINVAL;
 
-	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	mutex_lock(&selinuxfs_mutex);
 
-	mutex_lock(&fsi->state->policy_mutex);
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		goto out_unlock;
+	}
 
 	length = avc_has_perm(current_selinux_state,
 			      current_sid(), SECINITSID_SECURITY,
@@ -1523,8 +1635,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 		length = count;
 
 out:
-	mutex_unlock(&fsi->state->policy_mutex);
 	kfree(page);
+out_unlock:
+	mutex_unlock(&selinuxfs_mutex);
 	return length;
 }
 
@@ -1622,10 +1735,14 @@ static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
 					    size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char tmpbuf[TMPBUFLEN];
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
 			   avc_get_cache_threshold(state->avc));
 	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -1637,11 +1754,15 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
 
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *page;
 	ssize_t ret;
 	unsigned int new_value;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	if (state != current_selinux_state)
 		return -EPERM;
 
@@ -1659,9 +1780,13 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
 	if (*ppos != 0)
 		return -EINVAL;
 
+	mutex_lock(&selinuxfs_mutex);
+
 	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	if (IS_ERR(page)) {
+		ret = PTR_ERR(page);
+		goto out_unlock;
+	}
 
 	ret = -EINVAL;
 	if (sscanf(page, "%u", &new_value) != 1)
@@ -1672,6 +1797,8 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
 	ret = count;
 out:
 	kfree(page);
+out_unlock:
+	mutex_unlock(&selinuxfs_mutex);
 	return ret;
 }
 
@@ -1679,10 +1806,14 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
 				       size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *page;
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	page = (char *)__get_free_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
@@ -1699,10 +1830,14 @@ static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
 					size_t count, loff_t *ppos)
 {
 	struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
-	struct selinux_state *state = fsi->state;
+	struct selinux_state *state;
 	char *page;
 	ssize_t length;
 
+	if (fsi == NULL)
+		return -EINVAL;
+	state = fsi->state;
+
 	page = (char *)__get_free_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
@@ -1817,6 +1952,9 @@ static int sel_make_avc_files(struct dentry *dir)
 #endif
 	};
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	for (i = 0; i < ARRAY_SIZE(files); i++) {
 		struct inode *inode;
 		struct dentry *dentry;
@@ -1848,6 +1986,9 @@ static int sel_make_ss_files(struct dentry *dir)
 		{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
 	};
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	for (i = 0; i < ARRAY_SIZE(files); i++) {
 		struct inode *inode;
 		struct dentry *dentry;
@@ -1878,6 +2019,9 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
 	u32 sid, len;
 	ssize_t ret;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	sid = file_inode(file)->i_ino&SEL_INO_MASK;
 	ret = security_sid_to_context(fsi->state, sid, &con, &len);
 	if (ret)
@@ -1979,6 +2123,9 @@ static ssize_t sel_read_policycap(struct file *file, char __user *buf,
 	ssize_t length;
 	unsigned long i_ino = file_inode(file)->i_ino;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK);
 	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
 
@@ -2040,6 +2187,9 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
 	struct inode *inode = NULL;
 	int rc;
 
+	if (fsi == NULL)
+		return -EINVAL;
+
 	dentry = d_alloc_name(dir, "index");
 	if (!dentry)
 		return -ENOMEM;
@@ -2218,6 +2368,10 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
 		goto err;
 
 	fsi = sb->s_fs_info;
+
+	if (fsi == NULL)
+		goto err;
+
 	fsi->bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &fsi->last_ino);
 	if (IS_ERR(fsi->bool_dir)) {
 		ret = PTR_ERR(fsi->bool_dir);
@@ -2309,6 +2463,9 @@ static int selinuxfs_compare(struct super_block *sb, struct fs_context *fc)
 {
 	struct selinux_fs_info *fsi = sb->s_fs_info;
 
+	if (fsi == NULL)
+		return 0;
+
 	return (current_selinux_state->id == fsi->state->id);
 }
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 548acdecafa8..5e1f0486add1 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -67,6 +67,8 @@
 #include "audit.h"
 #include "policycap_names.h"
 
+extern struct mutex selinuxfs_mutex;    /* GLobal mutex for all selinuxfs access */
+
 /* Forward declaration. */
 static int context_struct_to_string(struct policydb *policydb,
 				    struct context *context,
@@ -2165,7 +2167,7 @@ void selinux_policy_cancel(struct selinux_state *state,
 	struct selinux_policy *oldpolicy;
 
 	oldpolicy = rcu_dereference_protected(state->policy,
-					lockdep_is_held(&state->policy_mutex));
+					lockdep_is_held(&selinuxfs_mutex));
 
 	sidtab_cancel_convert(oldpolicy->sidtab);
 	selinux_policy_free(policy);
@@ -2189,7 +2191,7 @@ void selinux_policy_commit(struct selinux_state *state,
 	u32 seqno;
 
 	oldpolicy = rcu_dereference_protected(state->policy,
-					lockdep_is_held(&state->policy_mutex));
+					lockdep_is_held(&selinuxfs_mutex));
 
 	/* If switching between different policy types, log MLS status */
 	if (oldpolicy) {
@@ -2283,7 +2285,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
 	}
 
 	oldpolicy = rcu_dereference_protected(state->policy,
-					lockdep_is_held(&state->policy_mutex));
+					lockdep_is_held(&selinuxfs_mutex));
 
 	/* Preserve active boolean values from the old policy */
 	rc = security_preserve_bools(oldpolicy, newpolicy);
@@ -2983,7 +2985,7 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
 		return -EINVAL;
 
 	oldpolicy = rcu_dereference_protected(state->policy,
-					lockdep_is_held(&state->policy_mutex));
+					lockdep_is_held(&selinuxfs_mutex));
 
 	/* Consistency check on number of booleans, should never fail */
 	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
@@ -3888,7 +3890,7 @@ int security_read_policy(struct selinux_state *state,
 	struct policy_file fp;
 
 	policy = rcu_dereference_protected(
-			state->policy, lockdep_is_held(&state->policy_mutex));
+			state->policy, lockdep_is_held(&selinuxfs_mutex));
 	if (!policy)
 		return -EINVAL;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-04-18  9:46 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [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             ` [RFC PATCH 2/7] selinux: support per-namespace superblock security structures Alexander Kozhevnikov
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).