diff mbox series

[v2,1/2] selinux: switch unnecessary GFP_ATOMIC allocs to GFP_KERNEL

Message ID 20200825065953.1566718-2-omosnace@redhat.com (mailing list archive)
State Changes Requested
Delegated to: Paul Moore
Headers show
Series selinux: Clean up GFP flag usage | expand

Commit Message

Ondrej Mosnacek Aug. 25, 2020, 6:59 a.m. UTC
There seems to be no reason to use GFP_ATOMIC in these cases.

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
 security/selinux/hooks.c       |  6 +++---
 security/selinux/ss/policydb.c | 10 +++++-----
 security/selinux/ss/services.c |  4 ++--
 3 files changed, 10 insertions(+), 10 deletions(-)

Comments

Stephen Smalley Aug. 25, 2020, 2:59 p.m. UTC | #1
On Tue, Aug 25, 2020 at 3:00 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> There seems to be no reason to use GFP_ATOMIC in these cases.
>
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
>  security/selinux/hooks.c       |  6 +++---
>  security/selinux/ss/policydb.c | 10 +++++-----
>  security/selinux/ss/services.c |  4 ++--
>  3 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 89d3753b7bd5d..4de962daffbde 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6854,7 +6854,7 @@ static int selinux_lockdown(enum lockdown_reason what)
>
>         if (WARN(invalid_reason, "Invalid lockdown reason")) {
>                 audit_log(audit_context(),
> -                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
> +                         GFP_KERNEL, AUDIT_SELINUX_ERR,
>                           "lockdown_reason=invalid");
>                 return -EINVAL;
>         }

Have you audited all callers of security_locked_down() to ensure that
they are never holding any locks around the call?  That's the only one
I saw that might be a problem now or in the future.

> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index a48fc1b337ba9..fa61a54bc1440 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -109,7 +109,7 @@ static int selinux_set_mapping(struct policydb *pol,
> @@ -2982,7 +2982,7 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
>                 int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
>
>                 if (new_state != old_state) {
> -                       audit_log(audit_context(), GFP_ATOMIC,
> +                       audit_log(audit_context(), GFP_KERNEL,
>                                 AUDIT_MAC_CONFIG_CHANGE,
>                                 "bool=%s val=%d old_val=%d auid=%u ses=%u",
>                                 sym_name(&newpolicy->policydb, SYM_BOOLS, i),

Note that this one shouldn't be back-ported prior to my refactoring
patches because previously this was called while holding the policy
rwlock.
Ondrej Mosnacek Aug. 25, 2020, 4:45 p.m. UTC | #2
On Tue, Aug 25, 2020 at 5:01 PM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
> On Tue, Aug 25, 2020 at 3:00 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
> >
> > There seems to be no reason to use GFP_ATOMIC in these cases.
> >
> > Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> > ---
> >  security/selinux/hooks.c       |  6 +++---
> >  security/selinux/ss/policydb.c | 10 +++++-----
> >  security/selinux/ss/services.c |  4 ++--
> >  3 files changed, 10 insertions(+), 10 deletions(-)
> >
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 89d3753b7bd5d..4de962daffbde 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -6854,7 +6854,7 @@ static int selinux_lockdown(enum lockdown_reason what)
> >
> >         if (WARN(invalid_reason, "Invalid lockdown reason")) {
> >                 audit_log(audit_context(),
> > -                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
> > +                         GFP_KERNEL, AUDIT_SELINUX_ERR,
> >                           "lockdown_reason=invalid");
> >                 return -EINVAL;
> >         }
>
> Have you audited all callers of security_locked_down() to ensure that
> they are never holding any locks around the call?  That's the only one
> I saw that might be a problem now or in the future.

Hm... didn't realize there were so many :) I'll try to go over them.

As a side note, it would be nice if we had the may (not) sleep
requirements documented somehow for each hook at the LSM level,
ideally with a might_sleep() check at the beginning of each
secuity_*() function that is expected to be called only from a
non-atomic context... Some hooks already have arguments that specify
this (inode_permission, inode_follow_link), but for others it is just
implicit. I'll put this on my long-term TODO list...

--
Ondrej Mosnacek
Software Engineer, Platform Security - SELinux kernel
Red Hat, Inc.
Stephen Smalley Aug. 26, 2020, 1:02 p.m. UTC | #3
On Tue, Aug 25, 2020 at 12:45 PM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> On Tue, Aug 25, 2020 at 5:01 PM Stephen Smalley
> <stephen.smalley.work@gmail.com> wrote:
> > On Tue, Aug 25, 2020 at 3:00 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
> > >
> > > There seems to be no reason to use GFP_ATOMIC in these cases.
> > >
> > > Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> > > ---
> > >  security/selinux/hooks.c       |  6 +++---
> > >  security/selinux/ss/policydb.c | 10 +++++-----
> > >  security/selinux/ss/services.c |  4 ++--
> > >  3 files changed, 10 insertions(+), 10 deletions(-)
> > >
> > > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > > index 89d3753b7bd5d..4de962daffbde 100644
> > > --- a/security/selinux/hooks.c
> > > +++ b/security/selinux/hooks.c
> > > @@ -6854,7 +6854,7 @@ static int selinux_lockdown(enum lockdown_reason what)
> > >
> > >         if (WARN(invalid_reason, "Invalid lockdown reason")) {
> > >                 audit_log(audit_context(),
> > > -                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
> > > +                         GFP_KERNEL, AUDIT_SELINUX_ERR,
> > >                           "lockdown_reason=invalid");
> > >                 return -EINVAL;
> > >         }
> >
> > Have you audited all callers of security_locked_down() to ensure that
> > they are never holding any locks around the call?  That's the only one
> > I saw that might be a problem now or in the future.
>
> Hm... didn't realize there were so many :) I'll try to go over them.
>
> As a side note, it would be nice if we had the may (not) sleep
> requirements documented somehow for each hook at the LSM level,
> ideally with a might_sleep() check at the beginning of each
> secuity_*() function that is expected to be called only from a
> non-atomic context... Some hooks already have arguments that specify
> this (inode_permission, inode_follow_link), but for others it is just
> implicit. I'll put this on my long-term TODO list...

Generally the core SELinux permission checking code assumes it can be
called from any context (including hardirq) and under any locking
conditions, and hooks that are for permission checking (not security
blob allocation/management) do the same.  This allows permission
checks to be performed while locks are held by the caller. and from
arbitrary contexts  I'd be inclined to just leave selinux_lockdown
unchanged given that it might be called anywhere much like capable().
Paul Moore Aug. 26, 2020, 1:51 p.m. UTC | #4
On Wed, Aug 26, 2020 at 9:02 AM Stephen Smalley
<stephen.smalley.work@gmail.com> wrote:
> Generally the core SELinux permission checking code assumes it can be
> called from any context (including hardirq) and under any locking
> conditions, and hooks that are for permission checking (not security
> blob allocation/management) do the same.  This allows permission
> checks to be performed while locks are held by the caller. and from
> arbitrary contexts  I'd be inclined to just leave selinux_lockdown
> unchanged given that it might be called anywhere much like capable().

Agreed.  The code paths relating to policy load, etc. are good
candidates for an ATOMIC->KERNEL conversion, assuming no other
constraints, but I'm somewhat nervous of converting stuff in hook.c
that doesn't have a hard sleep-ability defined.

The other question about this patchset is motivation: were you seeing
problem reports relating to SELinux memory failures when the system
was under pressure, or is this preemptive?

--
paul moore
www.paul-moore.com
Ondrej Mosnacek Aug. 26, 2020, 2:11 p.m. UTC | #5
On Wed, Aug 26, 2020 at 3:51 PM Paul Moore <paul@paul-moore.com> wrote:
> On Wed, Aug 26, 2020 at 9:02 AM Stephen Smalley
> <stephen.smalley.work@gmail.com> wrote:
> > Generally the core SELinux permission checking code assumes it can be
> > called from any context (including hardirq) and under any locking
> > conditions, and hooks that are for permission checking (not security
> > blob allocation/management) do the same.  This allows permission
> > checks to be performed while locks are held by the caller. and from
> > arbitrary contexts  I'd be inclined to just leave selinux_lockdown
> > unchanged given that it might be called anywhere much like capable().
>
> Agreed.  The code paths relating to policy load, etc. are good
> candidates for an ATOMIC->KERNEL conversion, assuming no other
> constraints, but I'm somewhat nervous of converting stuff in hook.c
> that doesn't have a hard sleep-ability defined.

OK, I can drop the selinux_lockdown() hunk then. The other hooks.c
hunks both have an existing GFP_KERNEL allocation in the same
function, so I'd tend to keep them for consistency. Or do you want me
to rather convert the GFP_KERNELs to GFP_ATOMICs there?

>
> The other question about this patchset is motivation: were you seeing
> problem reports relating to SELinux memory failures when the system
> was under pressure, or is this preemptive?

No, I just went over the GFP_* usage in security/selinux/ when scoping
how many GFP_ATOMIC ones could be changed to GFP_KERNEL after the
refcount patch and found these that could be switched right away.

--
Ondrej Mosnacek
Software Engineer, Platform Security - SELinux kernel
Red Hat, Inc.
Stephen Smalley Aug. 26, 2020, 2:17 p.m. UTC | #6
On Wed, Aug 26, 2020 at 10:12 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
>
> On Wed, Aug 26, 2020 at 3:51 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Aug 26, 2020 at 9:02 AM Stephen Smalley
> > <stephen.smalley.work@gmail.com> wrote:
> > > Generally the core SELinux permission checking code assumes it can be
> > > called from any context (including hardirq) and under any locking
> > > conditions, and hooks that are for permission checking (not security
> > > blob allocation/management) do the same.  This allows permission
> > > checks to be performed while locks are held by the caller. and from
> > > arbitrary contexts  I'd be inclined to just leave selinux_lockdown
> > > unchanged given that it might be called anywhere much like capable().
> >
> > Agreed.  The code paths relating to policy load, etc. are good
> > candidates for an ATOMIC->KERNEL conversion, assuming no other
> > constraints, but I'm somewhat nervous of converting stuff in hook.c
> > that doesn't have a hard sleep-ability defined.
>
> OK, I can drop the selinux_lockdown() hunk then. The other hooks.c
> hunks both have an existing GFP_KERNEL allocation in the same
> function, so I'd tend to keep them for consistency. Or do you want me
> to rather convert the GFP_KERNELs to GFP_ATOMICs there?

No, I was fine with the other parts of the patch just not the lockdown
one, because it can be called from many places like capable().
Paul Moore Aug. 26, 2020, 2:28 p.m. UTC | #7
On Wed, Aug 26, 2020 at 10:12 AM Ondrej Mosnacek <omosnace@redhat.com> wrote:
> On Wed, Aug 26, 2020 at 3:51 PM Paul Moore <paul@paul-moore.com> wrote:
> > On Wed, Aug 26, 2020 at 9:02 AM Stephen Smalley
> > <stephen.smalley.work@gmail.com> wrote:
> > > Generally the core SELinux permission checking code assumes it can be
> > > called from any context (including hardirq) and under any locking
> > > conditions, and hooks that are for permission checking (not security
> > > blob allocation/management) do the same.  This allows permission
> > > checks to be performed while locks are held by the caller. and from
> > > arbitrary contexts  I'd be inclined to just leave selinux_lockdown
> > > unchanged given that it might be called anywhere much like capable().
> >
> > Agreed.  The code paths relating to policy load, etc. are good
> > candidates for an ATOMIC->KERNEL conversion, assuming no other
> > constraints, but I'm somewhat nervous of converting stuff in hook.c
> > that doesn't have a hard sleep-ability defined.
>
> OK, I can drop the selinux_lockdown() hunk then. The other hooks.c
> hunks both have an existing GFP_KERNEL allocation in the same
> function, so I'd tend to keep them for consistency. Or do you want me
> to rather convert the GFP_KERNELs to GFP_ATOMICs there?

I was speaking generically in that I'm not comfortable converting
ATOMIC allocations to KERNEL allocations in the hooks.c layer without
some guarantee/constraint.  In the case of both _setxattr and
_setprocattr we are already doing KERNEL allocations in those
functions so switching the audit allocations to KERNEL isn't
necessarily changing the behavior of the SELinux hook, it can sleep
now regardless.

> > The other question about this patchset is motivation: were you seeing
> > problem reports relating to SELinux memory failures when the system
> > was under pressure, or is this preemptive?
>
> No, I just went over the GFP_* usage in security/selinux/ when scoping
> how many GFP_ATOMIC ones could be changed to GFP_KERNEL after the
> refcount patch and found these that could be switched right away.

Okay, thanks.
diff mbox series

Patch

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 89d3753b7bd5d..4de962daffbde 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3171,7 +3171,7 @@  static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 				audit_size = 0;
 			}
 			ab = audit_log_start(audit_context(),
-					     GFP_ATOMIC, AUDIT_SELINUX_ERR);
+					     GFP_KERNEL, AUDIT_SELINUX_ERR);
 			audit_log_format(ab, "op=setxattr invalid_context=");
 			audit_log_n_untrustedstring(ab, value, audit_size);
 			audit_log_end(ab);
@@ -6388,7 +6388,7 @@  static int selinux_setprocattr(const char *name, void *value, size_t size)
 				else
 					audit_size = size;
 				ab = audit_log_start(audit_context(),
-						     GFP_ATOMIC,
+						     GFP_KERNEL,
 						     AUDIT_SELINUX_ERR);
 				audit_log_format(ab, "op=fscreate invalid_context=");
 				audit_log_n_untrustedstring(ab, value, audit_size);
@@ -6854,7 +6854,7 @@  static int selinux_lockdown(enum lockdown_reason what)
 
 	if (WARN(invalid_reason, "Invalid lockdown reason")) {
 		audit_log(audit_context(),
-			  GFP_ATOMIC, AUDIT_SELINUX_ERR,
+			  GFP_KERNEL, AUDIT_SELINUX_ERR,
 			  "lockdown_reason=invalid");
 		return -EINVAL;
 	}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 9fccf417006b0..c1437de04e1d9 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -1577,7 +1577,7 @@  static int sens_read(struct policydb *p, struct symtab *s, void *fp)
 	__le32 buf[2];
 	u32 len;
 
-	levdatum = kzalloc(sizeof(*levdatum), GFP_ATOMIC);
+	levdatum = kzalloc(sizeof(*levdatum), GFP_KERNEL);
 	if (!levdatum)
 		return -ENOMEM;
 
@@ -1588,12 +1588,12 @@  static int sens_read(struct policydb *p, struct symtab *s, void *fp)
 	len = le32_to_cpu(buf[0]);
 	levdatum->isalias = le32_to_cpu(buf[1]);
 
-	rc = str_read(&key, GFP_ATOMIC, fp, len);
+	rc = str_read(&key, GFP_KERNEL, fp, len);
 	if (rc)
 		goto bad;
 
 	rc = -ENOMEM;
-	levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_ATOMIC);
+	levdatum->level = kmalloc(sizeof(*levdatum->level), GFP_KERNEL);
 	if (!levdatum->level)
 		goto bad;
 
@@ -1618,7 +1618,7 @@  static int cat_read(struct policydb *p, struct symtab *s, void *fp)
 	__le32 buf[3];
 	u32 len;
 
-	catdatum = kzalloc(sizeof(*catdatum), GFP_ATOMIC);
+	catdatum = kzalloc(sizeof(*catdatum), GFP_KERNEL);
 	if (!catdatum)
 		return -ENOMEM;
 
@@ -1630,7 +1630,7 @@  static int cat_read(struct policydb *p, struct symtab *s, void *fp)
 	catdatum->value = le32_to_cpu(buf[1]);
 	catdatum->isalias = le32_to_cpu(buf[2]);
 
-	rc = str_read(&key, GFP_ATOMIC, fp, len);
+	rc = str_read(&key, GFP_KERNEL, fp, len);
 	if (rc)
 		goto bad;
 
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index a48fc1b337ba9..fa61a54bc1440 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -109,7 +109,7 @@  static int selinux_set_mapping(struct policydb *pol,
 		i++;
 
 	/* Allocate space for the class records, plus one for class zero */
-	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
+	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_KERNEL);
 	if (!out_map->mapping)
 		return -ENOMEM;
 
@@ -2982,7 +2982,7 @@  int security_set_bools(struct selinux_state *state, u32 len, int *values)
 		int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
 
 		if (new_state != old_state) {
-			audit_log(audit_context(), GFP_ATOMIC,
+			audit_log(audit_context(), GFP_KERNEL,
 				AUDIT_MAC_CONFIG_CHANGE,
 				"bool=%s val=%d old_val=%d auid=%u ses=%u",
 				sym_name(&newpolicy->policydb, SYM_BOOLS, i),