All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paul Moore <paul@paul-moore.com>
To: David Howells <dhowells@redhat.com>
Cc: keyrings@vger.kernel.org, selinux@vger.kernel.org,
	linux-security-module@vger.kernel.org
Subject: Re: Problem with 9ba09998baa9 ("selinux: Implement the watch_key security hook") in linux-next
Date: Wed, 22 Apr 2020 19:20:17 +0000	[thread overview]
Message-ID: <CAHC9VhQnORRaRapbb1wrUsxweJCRJ+X+RdvKw8_U0pT0fuxZ6A@mail.gmail.com> (raw)
In-Reply-To: <2136640.1587472186@warthog.procyon.org.uk>

On Tue, Apr 21, 2020 at 8:29 AM David Howells <dhowells@redhat.com> wrote:
> Paul Moore <paul@paul-moore.com> wrote:
>
> > ... in particular it is the fifth argument to avc_has_perm(),
> > "KEY_NEED_VIEW" which is a problem.  KEY_NEED_VIEW is not a SELinux
> > permission and would likely result in odd behavior when passed to
> > avc_has_perm().
>
> I think it works because KEY_NEED_VIEW happens to coincide with KEY__VIEW.  It
> should just use KEY__VIEW instead.

Yes, it looks like it.  To be clear, it is dangerous to rely on
permission values from outside SELinux aligning with SELinux
permissions; changing the outside permission values w/o adjusting the
SELinux hook code to do the necessary translation will result in some
scary behavior (wrong permission checks).

> > it probably makes the most sense to pull the permission mapping in
> > selinux_key_permission() out into a separate function, e.g.
> > key_perm_to_av(...)
>
> Agreed.  How about the attached patch?  I wonder if I should do bit-by-bit
> translation rather than using a switch?  But then it's difficult to decide
> what it means if someone passes in two KEY_NEED_* flags OR'd together - is it
> either or both?

Comments inline.

> > and then use this newly created mapping function in [...]
> > selinux_watch_key()
>
> No, I think I should just hard-code KEY__VIEW there.

FWIW, my comment was based on a version of linux-next where you were
making policycap based permission adjustments to KEY_VIEW and I
thought you would want the same adjustments to be applied to both
access control points.  That code appears to now be gone in
linux-next.

> ---
> commit 70d1d82aa014ae4511976b4d80c17138006dddec
> Author: David Howells <dhowells@redhat.com>
> Date:   Tue Apr 21 13:15:16 2020 +0100
>
>     selinux: Fix use of KEY_NEED_* instead of KEY__* perms
>
>     selinux_key_getsecurity() is passing the KEY_NEED_* permissions to
>     security_sid_to_context() instead of the KEY__* values.  It happens to work
>     because the values are all coincident.
>
>     Fixes: d720024e94de ("[PATCH] selinux: add hooks for key subsystem")
>     Reported-by: Paul Moore <paul@paul-moore.com>
>     Signed-off-by: David Howells <dhowells@redhat.com>
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 0b4e32161b77..32f7fa538c5f 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6539,12 +6539,27 @@ static void selinux_key_free(struct key *k)
>         kfree(ksec);
>  }
>
> +static unsigned int selinux_keyperm_to_av(unsigned int need_perm)
> +{
> +       switch (need_perm) {
> +       case KEY_NEED_VIEW:     return KEY__VIEW;
> +       case KEY_NEED_READ:     return KEY__READ;
> +       case KEY_NEED_WRITE:    return KEY__WRITE;
> +       case KEY_NEED_SEARCH:   return KEY__SEARCH;
> +       case KEY_NEED_LINK:     return KEY__LINK;
> +       case KEY_NEED_SETATTR:  return KEY__SETATTR;
> +       default:
> +               return 0;
> +       }

Regarding your question of permission translation via switch-statement
as opposed to bit-by-bit comparison, I think it depends on if multiple
permissions are going to be required in a single call to the hook.
The failure mode for the code above if multiple permissions are
requested is not very good, it defaults to *no* permission which means
that if someone requested KEY_NEED_SEARCH|KEY_NEED_VIEW (or some other
combination) then the SELinux check would not check any permissions
... that seems wrong to me.

If we want to stick with a switch statement I think we should have it
return -EPERM for the default case to protect against this.  We don't
need the full 32-bits afforded us by the unsigned int.

> +}
> +
>  static int selinux_key_permission(key_ref_t key_ref,
>                                   const struct cred *cred,
> -                                 unsigned perm)
> +                                 unsigned need_perm)
>  {
>         struct key *key;
>         struct key_security_struct *ksec;
> +       unsigned int perm;
>         u32 sid;
>
>         /* if no specific permissions are requested, we skip the
> @@ -6553,6 +6568,7 @@ static int selinux_key_permission(key_ref_t key_ref,
>         if (perm = 0)
>                 return 0;
>
> +       perm = selinux_keyperm_to_av(need_perm);

... and add a check for (perm < 0) as discussed above if we stick with
the switch statement.

>         sid = cred_sid(cred);
>
>         key = key_ref_to_ptr(key_ref);
>

-- 
paul moore
www.paul-moore.com

WARNING: multiple messages have this Message-ID (diff)
From: Paul Moore <paul@paul-moore.com>
To: David Howells <dhowells@redhat.com>
Cc: keyrings@vger.kernel.org, selinux@vger.kernel.org,
	linux-security-module@vger.kernel.org
Subject: Re: Problem with 9ba09998baa9 ("selinux: Implement the watch_key security hook") in linux-next
Date: Wed, 22 Apr 2020 15:20:17 -0400	[thread overview]
Message-ID: <CAHC9VhQnORRaRapbb1wrUsxweJCRJ+X+RdvKw8_U0pT0fuxZ6A@mail.gmail.com> (raw)
In-Reply-To: <2136640.1587472186@warthog.procyon.org.uk>

On Tue, Apr 21, 2020 at 8:29 AM David Howells <dhowells@redhat.com> wrote:
> Paul Moore <paul@paul-moore.com> wrote:
>
> > ... in particular it is the fifth argument to avc_has_perm(),
> > "KEY_NEED_VIEW" which is a problem.  KEY_NEED_VIEW is not a SELinux
> > permission and would likely result in odd behavior when passed to
> > avc_has_perm().
>
> I think it works because KEY_NEED_VIEW happens to coincide with KEY__VIEW.  It
> should just use KEY__VIEW instead.

Yes, it looks like it.  To be clear, it is dangerous to rely on
permission values from outside SELinux aligning with SELinux
permissions; changing the outside permission values w/o adjusting the
SELinux hook code to do the necessary translation will result in some
scary behavior (wrong permission checks).

> > it probably makes the most sense to pull the permission mapping in
> > selinux_key_permission() out into a separate function, e.g.
> > key_perm_to_av(...)
>
> Agreed.  How about the attached patch?  I wonder if I should do bit-by-bit
> translation rather than using a switch?  But then it's difficult to decide
> what it means if someone passes in two KEY_NEED_* flags OR'd together - is it
> either or both?

Comments inline.

> > and then use this newly created mapping function in [...]
> > selinux_watch_key()
>
> No, I think I should just hard-code KEY__VIEW there.

FWIW, my comment was based on a version of linux-next where you were
making policycap based permission adjustments to KEY_VIEW and I
thought you would want the same adjustments to be applied to both
access control points.  That code appears to now be gone in
linux-next.

> ---
> commit 70d1d82aa014ae4511976b4d80c17138006dddec
> Author: David Howells <dhowells@redhat.com>
> Date:   Tue Apr 21 13:15:16 2020 +0100
>
>     selinux: Fix use of KEY_NEED_* instead of KEY__* perms
>
>     selinux_key_getsecurity() is passing the KEY_NEED_* permissions to
>     security_sid_to_context() instead of the KEY__* values.  It happens to work
>     because the values are all coincident.
>
>     Fixes: d720024e94de ("[PATCH] selinux: add hooks for key subsystem")
>     Reported-by: Paul Moore <paul@paul-moore.com>
>     Signed-off-by: David Howells <dhowells@redhat.com>
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 0b4e32161b77..32f7fa538c5f 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -6539,12 +6539,27 @@ static void selinux_key_free(struct key *k)
>         kfree(ksec);
>  }
>
> +static unsigned int selinux_keyperm_to_av(unsigned int need_perm)
> +{
> +       switch (need_perm) {
> +       case KEY_NEED_VIEW:     return KEY__VIEW;
> +       case KEY_NEED_READ:     return KEY__READ;
> +       case KEY_NEED_WRITE:    return KEY__WRITE;
> +       case KEY_NEED_SEARCH:   return KEY__SEARCH;
> +       case KEY_NEED_LINK:     return KEY__LINK;
> +       case KEY_NEED_SETATTR:  return KEY__SETATTR;
> +       default:
> +               return 0;
> +       }

Regarding your question of permission translation via switch-statement
as opposed to bit-by-bit comparison, I think it depends on if multiple
permissions are going to be required in a single call to the hook.
The failure mode for the code above if multiple permissions are
requested is not very good, it defaults to *no* permission which means
that if someone requested KEY_NEED_SEARCH|KEY_NEED_VIEW (or some other
combination) then the SELinux check would not check any permissions
... that seems wrong to me.

If we want to stick with a switch statement I think we should have it
return -EPERM for the default case to protect against this.  We don't
need the full 32-bits afforded us by the unsigned int.

> +}
> +
>  static int selinux_key_permission(key_ref_t key_ref,
>                                   const struct cred *cred,
> -                                 unsigned perm)
> +                                 unsigned need_perm)
>  {
>         struct key *key;
>         struct key_security_struct *ksec;
> +       unsigned int perm;
>         u32 sid;
>
>         /* if no specific permissions are requested, we skip the
> @@ -6553,6 +6568,7 @@ static int selinux_key_permission(key_ref_t key_ref,
>         if (perm == 0)
>                 return 0;
>
> +       perm = selinux_keyperm_to_av(need_perm);

... and add a check for (perm < 0) as discussed above if we stick with
the switch statement.

>         sid = cred_sid(cred);
>
>         key = key_ref_to_ptr(key_ref);
>

-- 
paul moore
www.paul-moore.com

  reply	other threads:[~2020-04-22 19:20 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-04-17 15:48 Problem with 9ba09998baa9 ("selinux: Implement the watch_key security hook") in linux-next Paul Moore
2020-04-17 15:48 ` Paul Moore
2020-04-17 16:32 ` Richard Haines
2020-04-17 16:32   ` Richard Haines
2020-04-17 16:59   ` Paul Moore
2020-04-17 16:59     ` Paul Moore
2020-04-21 12:29 ` David Howells
2020-04-21 12:29   ` David Howells
2020-04-22 19:20   ` Paul Moore [this message]
2020-04-22 19:20     ` Paul Moore
2020-04-22 21:09     ` Paul Moore
2020-04-22 21:09       ` Paul Moore
2020-04-24 23:43   ` David Howells
2020-04-24 23:43     ` David Howells
2020-04-26 20:53     ` Paul Moore
2020-04-26 20:53       ` Paul Moore
2020-04-27 14:12     ` [PATCH] selinux: Fix use of KEY_NEED_* instead of KEY__* perms David Howells
2020-04-27 14:12       ` David Howells
2020-04-27 14:36       ` Stephen Smalley
2020-04-27 14:36         ` Stephen Smalley
2020-04-27 15:24         ` Paul Moore
2020-04-27 15:24           ` Paul Moore
2020-04-27 17:02       ` Stephen Smalley
2020-04-27 17:02         ` Stephen Smalley
2020-04-27 22:17         ` Paul Moore
2020-04-27 22:17           ` Paul Moore
2020-04-28 12:54 ` [PATCH] selinux: Fix use of KEY_NEED_* instead of KEY__* perms [v2] David Howells
2020-04-28 12:54   ` David Howells
2020-04-28 14:32   ` Stephen Smalley
2020-04-28 14:32     ` Stephen Smalley
2020-04-28 15:57   ` David Howells
2020-04-28 15:57     ` David Howells
2020-04-28 16:19     ` Stephen Smalley
2020-04-28 16:19       ` Stephen Smalley
2020-05-01 16:37       ` Paul Moore
2020-05-01 16:37         ` Paul Moore
2020-05-12 22:33       ` [PATCH] keys: Make the KEY_NEED_* perms an enum rather than a mask David Howells
2020-05-12 22:33         ` David Howells
2020-05-13  1:04         ` Paul Moore
2020-05-13  1:04           ` Paul Moore
2020-05-13 12:58         ` Stephen Smalley
2020-05-13 12:58           ` Stephen Smalley
2020-05-13 15:25         ` Casey Schaufler
2020-05-13 15:25           ` Casey Schaufler
2020-05-13 23:13         ` David Howells
2020-05-13 23:13           ` David Howells
2020-05-14 12:08           ` Stephen Smalley
2020-05-14 12:08             ` Stephen Smalley
2020-05-14 14:45             ` Stephen Smalley
2020-05-14 14:45               ` Stephen Smalley
2020-05-13 23:16         ` David Howells
2020-05-13 23:16           ` David Howells
2020-05-13 23:25         ` David Howells
2020-05-13 23:25           ` David Howells
2020-05-14 11:00         ` Jarkko Sakkinen
2020-05-14 11:00           ` Jarkko Sakkinen
2020-05-14 16:58         ` [PATCH] keys: Move permissions checking decisions into the checking code David Howells
2020-05-14 16:58           ` David Howells
2020-05-14 17:06           ` Casey Schaufler
2020-05-14 17:06             ` Casey Schaufler
2020-05-15 15:06           ` Stephen Smalley
2020-05-15 15:06             ` Stephen Smalley
2020-05-15 16:45           ` David Howells
2020-05-15 16:45             ` David Howells
2020-05-15 18:55             ` Stephen Smalley
2020-05-15 18:55               ` Stephen Smalley
2020-05-15 19:10               ` Casey Schaufler
2020-05-15 19:10                 ` Casey Schaufler
2020-05-15 22:27             ` David Howells
2020-05-15 22:27               ` David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAHC9VhQnORRaRapbb1wrUsxweJCRJ+X+RdvKw8_U0pT0fuxZ6A@mail.gmail.com \
    --to=paul@paul-moore.com \
    --cc=dhowells@redhat.com \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=selinux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.