Re: SELinux: How to split permissions for keys?
From: Richard Haines
Date: Mon Feb 03 2020 - 09:03:51 EST
On Mon, 2020-02-03 at 08:13 -0500, Stephen Smalley wrote:
> On 2/2/20 2:30 PM, Richard Haines wrote:
> > On Thu, 2020-01-23 at 15:35 -0500, Stephen Smalley wrote:
> > > On 1/23/20 10:46 AM, Stephen Smalley wrote:
> > > > On 1/23/20 10:12 AM, David Howells wrote:
> > > > > Hi Stephen,
> > > > >
> > > > > I have patches to split the permissions that are used for
> > > > > keys to
> > > > > make
> > > > > them a
> > > > > bit finer grained and easier to use - and also to move to
> > > > > ACLs
> > > > > rather
> > > > > than
> > > > > fixed masks. See patch "keys: Replace uid/gid/perm
> > > > > permissions
> > > > > checking with
> > > > > an ACL" here:
> > > > >
> > > > >
> > > > > https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-acl
> > > > >
> > > > >
> > > > >
> > > > > However, I may not have managed the permission mask
> > > > > transformation inside
> > > > > SELinux correctly. Could you lend an eyeball? The change to
> > > > > the
> > > > > permissions
> > > > > model is as follows:
> > > > >
> > > > > The SETATTR permission is split to create two new
> > > > > permissions:
> > > > > (1) SET_SECURITY - which allows the key's owner, group
> > > > > and
> > > > > ACL
> > > > > to be
> > > > > changed and a restriction to be placed on a
> > > > > keyring.
> > > > > (2) REVOKE - which allows a key to be revoked.
> > > > > The SEARCH permission is split to create:
> > > > > (1) SEARCH - which allows a keyring to be search and a
> > > > > key
> > > > > to be
> > > > > found.
> > > > > (2) JOIN - which allows a keyring to be joined as a
> > > > > session
> > > > > keyring.
> > > > > (3) INVAL - which allows a key to be invalidated.
> > > > > The WRITE permission is also split to create:
> > > > > (1) WRITE - which allows a key's content to be altered
> > > > > and
> > > > > links
> > > > > to be
> > > > > added, removed and replaced in a keyring.
> > > > > (2) CLEAR - which allows a keyring to be cleared
> > > > > completely.
> > > > > This is
> > > > > split out to make it possible to give just this to
> > > > > an
> > > > > administrator.
> > > > > (3) REVOKE - see above.
> > > > >
> > > > > The change to SELinux is attached below.
> > > > >
> > > > > Should the split be pushed down into the SELinux policy
> > > > > rather
> > > > > than
> > > > > trying to
> > > > > calculate it?
> > > >
> > > > My understanding is that you must provide full backward
> > > > compatibility
> > > > with existing policies; hence, you must ensure that you always
> > > > check the
> > > > same SELinux permission(s) for the same operation when using an
> > > > existing
> > > > policy.
> > > >
> > > > In order to support finer-grained distinctions in SELinux with
> > > > future
> > > > policies, you can define a new SELinux policy capability along
> > > > with
> > > > the
> > > > new permissions, and if the policy capability is enabled in the
> > > > policy,
> > > > check the new permissions rather than the old ones. A recent
> > > > example of
> > > > adding a new policy capability and using it can be seen in:
> > > > https://lore.kernel.org/selinux/20200116194530.8696-1-jeffv@xxxxxxxxxx/T/#u
> > > > although that patch was rejected for other reasons.
> > > >
> > > > Another example was when we introduced fine-grained
> > > > distinctions
> > > > for all
> > > > network address families, commit
> > > > da69a5306ab92e07224da54aafee8b1dccf024f6.
> > > >
> > > > The new policy capability also needs to be defined in libsepol
> > > > for
> > > > use
> > > > by the policy compiler; an example can be seen in:
> > > > https://lore.kernel.org/selinux/20170714164801.6346-1-sds@xxxxxxxxxxxxx/
> > > >
> > > > Then future policies can declare the policy capability when
> > > > they
> > > > are
> > > > ready to start using the new permissions instead of the old.
> > > >
> > > > > Thanks,
> > > > > David
> > > > > ---
> > > > > diff --git a/security/selinux/hooks.c
> > > > > b/security/selinux/hooks.c
> > > > > index 116b4d644f68..c8db5235b01f 100644
> > > > > --- a/security/selinux/hooks.c
> > > > > +++ b/security/selinux/hooks.c
> > > > > @@ -6556,6 +6556,7 @@ static int
> > > > > selinux_key_permission(key_ref_t
> > > > > key_ref,
> > > > > {
> > > > > struct key *key;
> > > > > struct key_security_struct *ksec;
> > > > > + unsigned oldstyle_perm;
> > > > > u32 sid;
> > > > > /* if no specific permissions are requested, we skip
> > > > > the
> > > > > @@ -6564,13 +6565,26 @@ static int
> > > > > selinux_key_permission(key_ref_t
> > > > > key_ref,
> > > > > if (perm == 0)
> > > > > return 0;
> > > > > + oldstyle_perm = perm & (KEY_NEED_VIEW | KEY_NEED_READ |
> > > > > KEY_NEED_WRITE |
> > > > > + KEY_NEED_SEARCH | KEY_NEED_LINK);
> > > > > + if (perm & KEY_NEED_SETSEC)
> > > > > + oldstyle_perm |= OLD_KEY_NEED_SETATTR;
> > > > > + if (perm & KEY_NEED_INVAL)
> > > > > + oldstyle_perm |= KEY_NEED_SEARCH;
> > > > > + if (perm & KEY_NEED_REVOKE && !(perm &
> > > > > OLD_KEY_NEED_SETATTR))
> > > > > + oldstyle_perm |= KEY_NEED_WRITE;
> > > > > + if (perm & KEY_NEED_JOIN)
> > > > > + oldstyle_perm |= KEY_NEED_SEARCH;
> > > > > + if (perm & KEY_NEED_CLEAR)
> > > > > + oldstyle_perm |= KEY_NEED_WRITE;
> > > > > +
> > > >
> > > > I don't know offhand if this ensures that the same SELinux
> > > > permission is
> > > > always checked as it would have been previously for the same
> > > > operation+arguments. That's what you have to preserve for
> > > > existing
> > > > policies.
> > >
> > > As Richard pointed out in his email, your key-acl series replaces
> > > two
> > > different old permissions (LINK, SEARCH) with a single permission
> > > (JOIN)
> > > in different callers, so by the time we reach the SELinux hook we
> > > cannot
> > > map it back unambiguously and provide full backward
> > > compatibility. The
> > > REVOKE case also seems fragile although there you seem to
> > > distinguish
> > > by
> > > sometimes passing in OLD_KEY_NEED_SETATTR and sometimes
> > > not? You'll
> > > have to fix the JOIN case to avoid userspace breakage.
> > >
> > > You may want to go ahead and explicitly translate all of the
> > > KEY_NEED
> > > permissions to SELinux permissions rather than passing the key
> > > permissions directly here to avoid requiring that the values
> > > always
> > > match. The SELinux permission symbols are of the form
> > > CLASS__PERMISSION
> > > (NB double underscore), e.g. KEY__SETATTR, generated
> > > automatically
> > > from
> > > the security/selinux/include/classmap.h tables to the
> > > security/selinux/av_permissions.h generated header. Most hooks
> > > perform
> > > such translation, e.g. file_mask_to_av(). You will almost
> > > certainly
> > > need to do this if/when you introduce support for the new
> > > permissions
> > > to
> > > SELinux.
> >
> > This problem has now been fixed in [1].
> > It passes the current selinux-test-suite (except test/fs_filesystem
> > regression).
> >
> > As the fix now includes a new 'key_perms' policy capability to
> > allow
> > use of the extended key permissions, I've updated libsepol and the
> > selinux-testsuite test/keys to test these.
> >
> > I'll submit two RFC patches that will allow [1] to be tested with
> > 'key_perms' true or false.
> >
> > [1]
> > https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/commit/?h=keys-next
>
> Was that kernel patch ever posted to selinux list and/or the selinux
> kernel maintainers? I don't recall seeing it. If not, please send
> it
> to the selinux list for review; at least one selinux maintainer
> should
> ack it before it gets accepted into any other tree.
>
>
Not formally. I did post it in a discussion about keys in [2]. Since
then it's been modified to support the split permissions.
I've extracted the patch from [1] and will post that to list for
comments.
[2]
https://lore.kernel.org/selinux/35455b30b5185780628e92c98ec8191c70f39bde.camel@xxxxxxxxxxxxxx/
>