[PATCH v0] KEYS: Security LSM Hook for key_create_or_update

Casey Schaufler casey at schaufler-ca.com
Fri Oct 18 20:25:23 UTC 2019


On 10/18/2019 12:53 PM, Lakshmi Ramasubramanian wrote:
> Problem Statement:
> key_create_or_update function currently does not have
> a security LSM hook. The hook is needed to allow security
> subsystems to use key create or update information.

What security module(s) do you expect to use this?

> security_key_alloc LSM hook that is currently available is not
> providing enough information about the key (the key payload,
> the target keyring, etc.). Also, this LSM hook is only available
> for key create.
>
> Changes made:
> Adding a new LSM hook for key key_create_or_update,
> security_key_create_or_update, which is called after
>    => A newly created key is instantiated and linked to the target
>       keyring (__key_instantiate_and_link).
>    => An existing key is updated with a new payload (__key_update)
>
> security_key_create_or_update is passed the target keyring, key,
> cred, key creation flags, and a boolean flag indicating whether
> the key was newly created or updated.
>
> Security subsystems can use this hook for handling key create or update.
> For example, IMA subsystem can measure the key when it is created or
> updated.

IMA is not a Linux Security Module.

> Testing performed:
>   * Booted the kernel with this change.
>   * Executed keyctl tests from the Linux Test Project (LTP)
>   * Added a new key to a keyring and verified "key create" code path.
>     => In this case added a key to builtin_trusted_keys keyring.
>   * Added the same key again and verified "key update" code path.
>     => Add the same key to builtin_trusted_keys keyring.
>     => find_key_to_update found the key and LSM hook was
>        called for key update (create flag set to false).
>   * Forced the LSM hook (security_key_create_or_update) to
>     return an error and verified that the key was not added to
>     the keyring ("keyctl list <keyring>" does not list the key).
>
> Signed-off-by: Lakshmi Ramasubramanian <nramas at linux.microsoft.com>
> ---
>  include/linux/lsm_hooks.h | 13 +++++++
>  include/linux/security.h  | 10 +++++
>  security/keys/key.c       | 78 ++++++++++++++++++++++++++++++++++-----
>  security/security.c       |  8 ++++

You don't have a security module that provides this hook.
We don't accept interfaces without users.

>  4 files changed, 100 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index df1318d85f7d..2f2e95df62f3 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -1066,6 +1066,15 @@
>   *
>   * Security hooks affecting all Key Management operations
>   *
> + * @key_create_or_update:
> + *      Notification of key create or update.
> + *      @keyring points to the keyring to which the key belongs
> + *      @key points to the key being created or updated
> + *      @cred current cred
> + *      @flags is the allocation flags
> + *      @create flag set to true if the key was created.
> + *              flag set to false if the key was updated.
> + *      Return 0 if permission is granted, -ve error otherwise.
>   * @key_alloc:
>   *	Permit allocation of a key and assign security data. Note that key does
>   *	not have a serial number assigned at this point.
> @@ -1781,6 +1790,9 @@ union security_list_options {
>  
>  	/* key management security hooks */
>  #ifdef CONFIG_KEYS
> +	int (*key_create_or_update)(struct key *keyring, struct key *key,
> +				    const struct cred *cred,
> +				    unsigned long flags, bool create);
>  	int (*key_alloc)(struct key *key, const struct cred *cred,
>  				unsigned long flags);
>  	void (*key_free)(struct key *key);
> @@ -2026,6 +2038,7 @@ struct security_hook_heads {
>  	struct hlist_head xfrm_decode_session;
>  #endif	/* CONFIG_SECURITY_NETWORK_XFRM */
>  #ifdef CONFIG_KEYS
> +	struct hlist_head key_create_or_update;
>  	struct hlist_head key_alloc;
>  	struct hlist_head key_free;
>  	struct hlist_head key_permission;
> diff --git a/include/linux/security.h b/include/linux/security.h
> index 5f7441abbf42..27e1c0a3057b 100644
> --- a/include/linux/security.h
> +++ b/include/linux/security.h
> @@ -1672,6 +1672,9 @@ static inline int security_path_chroot(const struct path *path)
>  #ifdef CONFIG_KEYS
>  #ifdef CONFIG_SECURITY
>  
> +int security_key_create_or_update(struct key *keyring, struct key *key,
> +				  const struct cred *cred,
> +				  unsigned long flags, bool create);
>  int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags);
>  void security_key_free(struct key *key);
>  int security_key_permission(key_ref_t key_ref,
> @@ -1680,6 +1683,13 @@ int security_key_getsecurity(struct key *key, char **_buffer);
>  
>  #else
>  
> +int security_key_create_or_update(struct key *keyring, struct key *key,
> +				  const struct cred *cred,
> +				  unsigned long flags, bool create)
> +{
> +	return 0;
> +}
> +
>  static inline int security_key_alloc(struct key *key,
>  				     const struct cred *cred,
>  				     unsigned long flags)
> diff --git a/security/keys/key.c b/security/keys/key.c
> index 764f4c57913e..b913feaf196e 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -781,7 +781,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
>  }
>  
>  /**
> - * key_create_or_update - Update or create and instantiate a key.
> + * __key_create_or_update - Update or create and instantiate a key.
>   * @keyring_ref: A pointer to the destination keyring with possession flag.
>   * @type: The type of key.
>   * @description: The searchable description for the key.
> @@ -789,6 +789,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
>   * @plen: The length of @payload.
>   * @perm: The permissions mask for a new key.
>   * @flags: The quota flags for a new key.
> + * @create: Set to true if the key was newly created.
> + *          Set to false if the key was updated.
>   *
>   * Search the destination keyring for a key of the same description and if one
>   * is found, update it, otherwise create and instantiate a new one and create a
> @@ -805,13 +807,14 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
>   * On success, the possession flag from the keyring ref will be tacked on to
>   * the key ref before it is returned.
>   */
> -key_ref_t key_create_or_update(key_ref_t keyring_ref,
> -			       const char *type,
> -			       const char *description,
> -			       const void *payload,
> -			       size_t plen,
> -			       key_perm_t perm,
> -			       unsigned long flags)
> +static key_ref_t __key_create_or_update(key_ref_t keyring_ref,
> +					const char *type,
> +					const char *description,
> +					const void *payload,
> +					size_t plen,
> +					key_perm_t perm,
> +					unsigned long flags,
> +					bool *create)
>  {
>  	struct keyring_index_key index_key = {
>  		.description	= description,
> @@ -936,6 +939,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  		goto error_link_end;
>  	}
>  
> +	*create = true;
>  	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
>  
>  error_link_end:
> @@ -948,7 +952,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  error:
>  	return key_ref;
>  
> - found_matching_key:
> +found_matching_key:
>  	/* we found a matching key, so we're going to try to update it
>  	 * - we can drop the locks first as we have the key pinned
>  	 */
> @@ -964,9 +968,65 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  		}
>  	}
>  
> +	*create = false;
>  	key_ref = __key_update(key_ref, &prep);
>  	goto error_free_prep;
>  }
> +
> +/**
> + * key_create_or_update - Update or create and instantiate a key.
> + * @keyring_ref: A pointer to the destination keyring with possession flag.
> + * @type: The type of key.
> + * @description: The searchable description for the key.
> + * @payload: The data to use to instantiate or update the key.
> + * @plen: The length of @payload.
> + * @perm: The permissions mask for a new key.
> + * @flags: The quota flags for a new key.
> + *
> + * Calls the internal function __key_create_or_update.
> + * If successful calls the security LSM hook.
> + */
> +key_ref_t key_create_or_update(key_ref_t keyring_ref,
> +			       const char *type,
> +			       const char *description,
> +			       const void *payload,
> +			       size_t plen,
> +			       key_perm_t perm,
> +			       unsigned long flags)
> +{
> +	key_ref_t key_ref;
> +	struct key *keyring, *key = NULL;
> +	int ret = 0;
> +	bool create = false;
> +
> +	key_ref = __key_create_or_update(keyring_ref, type, description,
> +					 payload, plen, perm, flags,
> +					 &create);
> +	if (IS_ERR(key_ref))
> +		goto out;
> +
> +	keyring = key_ref_to_ptr(keyring_ref);
> +	key = key_ref_to_ptr(key_ref);
> +
> +	/* let the security module know about
> +	 * the created or updated key.
> +	 */
> +	ret = security_key_create_or_update(keyring, key,
> +					    current_cred(),
> +					    flags, create);
> +	if (ret < 0)
> +		goto security_error;
> +	else
> +		goto out;
> +
> +security_error:
> +	key_unlink(keyring, key);
> +	key_put(key);
> +	key_ref = ERR_PTR(ret);
> +
> +out:
> +	return key_ref;
> +}
>  EXPORT_SYMBOL(key_create_or_update);
>  
>  /**
> diff --git a/security/security.c b/security/security.c
> index 250ee2d76406..fc1e4984fb53 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -2280,6 +2280,14 @@ EXPORT_SYMBOL(security_skb_classify_flow);
>  
>  #ifdef CONFIG_KEYS
>  
> +int security_key_create_or_update(struct key *keyring, struct key *key,
> +				  const struct cred *cred,
> +				  unsigned long flags, bool create)
> +{
> +	return call_int_hook(key_create_or_update, 0,
> +			     keyring, key, cred, flags, create);
> +}
> +
>  int security_key_alloc(struct key *key, const struct cred *cred,
>  		       unsigned long flags)
>  {



More information about the Linux-security-module-archive mailing list