Re: [PATCH] keys: Move permissions checking decisions into the checking code

From: Casey Schaufler
Date: Thu May 14 2020 - 13:06:37 EST


On 5/14/2020 9:58 AM, David Howells wrote:
> How about this then?
>
> David
> ---
> commit fa37b6c7e2f86d16ede1e0e3cb73857152d51825
> Author: David Howells <dhowells@xxxxxxxxxx>
> Date: Thu May 14 17:48:55 2020 +0100
>
> keys: Move permissions checking decisions into the checking code
>
> Overhaul the permissions checking, moving the decisions of which permits to
> request for what operation and what overrides to allow into the permissions
> checking functions in keyrings, SELinux and Smack.
>
> To this end, the KEY_NEED_* constants are turned into an enum and expanded
> in number to cover operation types individually.
>
> Note that some more tweaking is probably needed to separate kernel uses,
> e.g. AFS using rxrpc keys, from direct userspace users.
>
> Some overrides are available and this needs to be handled specially:
>
> (1) KEY_FLAG_KEEP in key->flags - The key may not be deleted and/or things
> may not be removed from the keyring.
>
> (2) KEY_FLAG_ROOT_CAN_CLEAR in key->flags - The keyring can be cleared by
> CAP_SYS_ADMIN.
>
> (3) KEY_FLAG_ROOT_CAN_INVAL in key->flags - The key can be invalidated by
> CAP_SYS_ADMIN.
>
> (4) An appropriate auth token being set in cred->request_key_auth that
> gives a process transient permission to view and instantiate a key.
> This is used by the kernel to delegate instantiation to userspace.
>
> Note that this requires some tweaks to the testsuite as some of the error
> codes change.
>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> Reported-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx>
> cc: Jarkko Sakkinen <jarkko.sakkinen@xxxxxxxxxxxxxxx>
> cc: Paul Moore <paul@xxxxxxxxxxxxxx>
> cc: Stephen Smalley <stephen.smalley.work@xxxxxxxxx>
> cc: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
> cc: keyrings@xxxxxxxxxxxxxxx
> cc: selinux@xxxxxxxxxxxxxxx
>
<snip> ...

> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 8c61d175e195..ac9c93c48097 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -4230,13 +4230,15 @@ static void smack_key_free(struct key *key)
> * smack_key_permission - Smack access on a key
> * @key_ref: gets to the object
> * @cred: the credentials to use
> - * @perm: requested key permissions
> + * @need_perm: requested key permission
> *
> * Return 0 if the task has read and write to the object,
> * an error code otherwise
> */
> static int smack_key_permission(key_ref_t key_ref,
> - const struct cred *cred, unsigned perm)
> + const struct cred *cred,
> + enum key_need_perm need_perm,
> + unsigned int flags)
> {
> struct key *keyp;
> struct smk_audit_info ad;
> @@ -4244,12 +4246,6 @@ static int smack_key_permission(key_ref_t key_ref,
> int request = 0;
> int rc;
>
> - /*
> - * Validate requested permissions
> - */
> - if (perm & ~KEY_NEED_ALL)
> - return -EINVAL;
> -
> keyp = key_ref_to_ptr(key_ref);
> if (keyp == NULL)
> return -EINVAL;
> @@ -4265,6 +4261,71 @@ static int smack_key_permission(key_ref_t key_ref,
> if (tkp == NULL)
> return -EACCES;
>
> + /*
> + * Validate requested permissions
> + */
> + switch (need_perm) {
> + case KEY_NEED_ASSUME_AUTHORITY:
> + return 0;
> +
> + case KEY_NEED_DESCRIBE:
> + case KEY_NEED_GET_SECURITY:
> + request |= MAY_READ;
> + auth_can_override = true;
> + break;
> +
> + case KEY_NEED_CHOWN:
> + case KEY_NEED_INVALIDATE:
> + case KEY_NEED_JOIN:
> + case KEY_NEED_LINK:
> + case KEY_NEED_KEYRING_ADD:
> + case KEY_NEED_KEYRING_CLEAR:
> + case KEY_NEED_KEYRING_DELETE:
> + case KEY_NEED_REVOKE:
> + case KEY_NEED_SETPERM:
> + case KEY_NEED_SET_RESTRICTION:
> + case KEY_NEED_UPDATE:
> + request |= MAY_WRITE;
> + break;
> +
> + case KEY_NEED_INSTANTIATE:
> + auth_can_override = true;
> + break;
> +
> + case KEY_NEED_READ:
> + case KEY_NEED_SEARCH:
> + case KEY_NEED_USE:
> + case KEY_NEED_WATCH:
> + request |= MAY_READ;
> + break;
> +
> + case KEY_NEED_SET_TIMEOUT:
> + request |= MAY_WRITE;
> + auth_can_override = true;
> + break;
> +
> + case KEY_NEED_UNLINK:
> + return 0; /* Mustn't prevent this; KEY_FLAG_KEEP is already
> + * dealt with. */
> +
> + default:
> + WARN_ON(1);
> + return -EINVAL;
> + }
> +
> + /* Just allow the operation if the process has an authorisation token.
> + * The presence of the token means that the kernel delegated
> + * instantiation of a key to the process - which is problematic if we
> + * then say that the process isn't allowed to get the description of
> + * the key or actually instantiate it.
> + */
> + if (auth_can_override && cred->request_key_auth) {
> + struct request_key_auth *rka =
> + cred->request_key_auth->payload.data[0];
> + if (rka->target_key == key)
> + *_perm = 0;
> + }
> +
> if (smack_privileged_cred(CAP_MAC_OVERRIDE, cred))
> return 0;
>
> @@ -4273,10 +4334,6 @@ static int smack_key_permission(key_ref_t key_ref,
> ad.a.u.key_struct.key = keyp->serial;
> ad.a.u.key_struct.key_desc = keyp->description;
> #endif
> - if (perm & (KEY_NEED_READ | KEY_NEED_SEARCH | KEY_NEED_VIEW))
> - request |= MAY_READ;
> - if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR))
> - request |= MAY_WRITE;
> rc = smk_access(tkp, keyp->security, request, &ad);
> rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
> return rc;

Better. Thank you.