Re: [added to the 3.18 stable tree] KEYS: prevent keys from being removed from specified keyrings

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sasha,

Currently, the only user of this flag is the .ima_blacklist keyring.
Unless the .ima_blacklist keyring was backported, there is no reason to
backport this patch.

Mimi

On Wed, 2016-02-10 at 09:59 -0500, Sasha Levin wrote:
> From: Mimi Zohar <zohar@xxxxxxxxxxxxxxxxxx>
> 
> This patch has been added to the 3.18 stable tree. If you have any
> objections, please let us know.
> 
> ===============
> 
> [ Upstream commit d3600bcf9d64d88dc1d189a754dcfab960ce751f ]
> 
> Userspace should not be allowed to remove keys from certain keyrings
> (eg. blacklist), though the keys themselves can expire.
> 
> This patch defines a new key flag named KEY_FLAG_KEEP to prevent
> userspace from being able to unlink, revoke, invalidate or timed
> out a key on a keyring.  When this flag is set on the keyring, all
> keys subsequently added are flagged.
> 
> In addition, when this flag is set, the keyring itself can not be
> cleared.
> 
> Signed-off-by: Mimi Zohar <zohar@xxxxxxxxxxxxxxxxxx>
> Cc: David Howells <dhowells@xxxxxxxxxx>
> Signed-off-by: Sasha Levin <sasha.levin@xxxxxxxxxx>
> ---
>  include/linux/key.h    |  1 +
>  security/keys/key.c    |  6 +++++-
>  security/keys/keyctl.c | 56 +++++++++++++++++++++++++++++++++++++++++---------
>  3 files changed, 52 insertions(+), 11 deletions(-)
> 
> diff --git a/include/linux/key.h b/include/linux/key.h
> index e1d4715..2318331 100644
> --- a/include/linux/key.h
> +++ b/include/linux/key.h
> @@ -172,6 +172,7 @@ struct key {
>  #define KEY_FLAG_TRUSTED_ONLY	9	/* set if keyring only accepts links to trusted keys */
>  #define KEY_FLAG_BUILTIN	10	/* set if key is builtin */
>  #define KEY_FLAG_ROOT_CAN_INVAL	11	/* set if key can be invalidated by root without permission */
> +#define KEY_FLAG_KEEP		12	/* set if key should not be removed */
> 
>  	/* the key type and key description string
>  	 * - the desc is used to match a key against search criteria
> diff --git a/security/keys/key.c b/security/keys/key.c
> index e17ba6a..0b7aa0c 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -431,8 +431,12 @@ static int __key_instantiate_and_link(struct key *key,
>  				awaken = 1;
> 
>  			/* and link it into the destination keyring */
> -			if (keyring)
> +			if (keyring) {
> +				if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
> +					set_bit(KEY_FLAG_KEEP, &key->flags);
> +
>  				__key_link(key, _edit);
> +			}
> 
>  			/* disable the authorisation key */
>  			if (authkey)
> diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
> index fee27fe..700c204 100644
> --- a/security/keys/keyctl.c
> +++ b/security/keys/keyctl.c
> @@ -364,11 +364,14 @@ error:
>   * and any links to the key will be automatically garbage collected after a
>   * certain amount of time (/proc/sys/kernel/keys/gc_delay).
>   *
> + * Keys with KEY_FLAG_KEEP set should not be revoked.
> + *
>   * If successful, 0 is returned.
>   */
>  long keyctl_revoke_key(key_serial_t id)
>  {
>  	key_ref_t key_ref;
> +	struct key *key;
>  	long ret;
> 
>  	key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
> @@ -383,8 +386,13 @@ long keyctl_revoke_key(key_serial_t id)
>  		}
>  	}
> 
> -	key_revoke(key_ref_to_ptr(key_ref));
> -	ret = 0;
> +	key = key_ref_to_ptr(key_ref);
> +	if (test_bit(KEY_FLAG_KEEP, &key->flags))
> +		return -EPERM;
> +	else {
> +		key_revoke(key);
> +		ret = 0;
> +	}
> 
>  	key_ref_put(key_ref);
>  error:
> @@ -398,11 +406,14 @@ error:
>   * The key and any links to the key will be automatically garbage collected
>   * immediately.
>   *
> + * Keys with KEY_FLAG_KEEP set should not be invalidated.
> + *
>   * If successful, 0 is returned.
>   */
>  long keyctl_invalidate_key(key_serial_t id)
>  {
>  	key_ref_t key_ref;
> +	struct key *key;
>  	long ret;
> 
>  	kenter("%d", id);
> @@ -426,8 +437,13 @@ long keyctl_invalidate_key(key_serial_t id)
>  	}
> 
>  invalidate:
> -	key_invalidate(key_ref_to_ptr(key_ref));
> -	ret = 0;
> +	key = key_ref_to_ptr(key_ref);
> +	if (test_bit(KEY_FLAG_KEEP, &key->flags))
> +		ret = -EPERM;
> +	else {
> +		key_invalidate(key);
> +		ret = 0;
> +	}
>  error_put:
>  	key_ref_put(key_ref);
>  error:
> @@ -439,12 +455,13 @@ error:
>   * Clear the specified keyring, creating an empty process keyring if one of the
>   * special keyring IDs is used.
>   *
> - * The keyring must grant the caller Write permission for this to work.  If
> - * successful, 0 will be returned.
> + * The keyring must grant the caller Write permission and not have
> + * KEY_FLAG_KEEP set for this to work.  If successful, 0 will be returned.
>   */
>  long keyctl_keyring_clear(key_serial_t ringid)
>  {
>  	key_ref_t keyring_ref;
> +	struct key *keyring;
>  	long ret;
> 
>  	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
> @@ -466,7 +483,11 @@ long keyctl_keyring_clear(key_serial_t ringid)
>  	}
> 
>  clear:
> -	ret = keyring_clear(key_ref_to_ptr(keyring_ref));
> +	keyring = key_ref_to_ptr(keyring_ref);
> +	if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
> +		ret = -EPERM;
> +	else
> +		ret = keyring_clear(keyring);
>  error_put:
>  	key_ref_put(keyring_ref);
>  error:
> @@ -517,11 +538,14 @@ error:
>   * itself need not grant the caller anything.  If the last link to a key is
>   * removed then that key will be scheduled for destruction.
>   *
> + * Keys or keyrings with KEY_FLAG_KEEP set should not be unlinked.
> + *
>   * If successful, 0 will be returned.
>   */
>  long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
>  {
>  	key_ref_t keyring_ref, key_ref;
> +	struct key *keyring, *key;
>  	long ret;
> 
>  	keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
> @@ -536,7 +560,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
>  		goto error2;
>  	}
> 
> -	ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
> +	keyring = key_ref_to_ptr(keyring_ref);
> +	key = key_ref_to_ptr(key_ref);
> +	if (test_bit(KEY_FLAG_KEEP, &keyring->flags) &&
> +	    test_bit(KEY_FLAG_KEEP, &key->flags))
> +		ret = -EPERM;
> +	else
> +		ret = key_unlink(keyring, key);
> 
>  	key_ref_put(key_ref);
>  error2:
> @@ -1319,6 +1349,8 @@ error:
>   * the current time.  The key and any links to the key will be automatically
>   * garbage collected after the timeout expires.
>   *
> + * Keys with KEY_FLAG_KEEP set should not be timed out.
> + *
>   * If successful, 0 is returned.
>   */
>  long keyctl_set_timeout(key_serial_t id, unsigned timeout)
> @@ -1350,10 +1382,14 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
> 
>  okay:
>  	key = key_ref_to_ptr(key_ref);
> -	key_set_timeout(key, timeout);
> +	if (test_bit(KEY_FLAG_KEEP, &key->flags))
> +		ret = -EPERM;
> +	else {
> +		key_set_timeout(key, timeout);
> +		ret = 0;
> +	}
>  	key_put(key);
> 
> -	ret = 0;
>  error:
>  	return ret;
>  }


--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]