lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1454932757.2648.143.camel@linux.vnet.ibm.com>
Date:	Mon, 08 Feb 2016 06:59:17 -0500
From:	Mimi Zohar <zohar@...ux.vnet.ibm.com>
To:	David Howells <dhowells@...hat.com>
Cc:	linux-security-module@...r.kernel.org, keyrings@...r.kernel.org,
	petkan@...-labs.com, linux-kernel@...r.kernel.org
Subject: Re: [RFC PATCH 07/20] KEYS: Add a facility to restrict new links
 into a keyring [ver #2]

On Tue, 2016-01-19 at 11:31 +0000, David Howells wrote:
> Add a facility whereby proposed new links to be added to a keyring can be
> vetted, permitting them to be rejected if necessary.  This can be used to
> block public keys from which the signature cannot be verified or for which
> the signature verification fails.  It could also be used to provide
> blacklisting.
> 
> This affects operations like add_key(), KEYCTL_LINK and KEYCTL_INSTANTIATE.
> 
> To this end:
> 
>  (1) A function pointer is added to the key struct that, if set, points to
>      the vetting function.  This is called as:
> 
> 	int (*restrict_link)(struct key *keyring,
> 			     const struct key_type *key_type,
> 			     unsigned long key_flags,
> 			     const union key_payload *key_payload),
> 
>      where 'keyring' will be the keyring being added to, key_type and
>      key_payload will describe the key being added and key_flags[*] can be
>      AND'ed with KEY_FLAG_TRUSTED.
> 
>      [*] This parameter will be removed in a later patch when
>      	 KEY_FLAG_TRUSTED is removed.
> 
>      The function should return 0 to allow the link to take place or an
>      error (typically -ENOKEY, -ENOPKG or -EKEYREJECTED) to reject the
>      link.
> 
>      The pointer should not be set directly, but rather should be set
>      through keyring_alloc().
> 
>      Note that if called during add_key(), preparse is called before this
>      method, but a key isn't actually allocated until after this function
>      is called.
> 
>  (2) KEY_ALLOC_BYPASS_RESTRICTION is added.  This can be passed to
>      key_create_or_update() or key_instantiate_and_link() to bypass the
>      restriction check.
> 
>  (3) KEY_FLAG_TRUSTED_ONLY is removed.  The entire contents of a keyring
>      with this restriction emplaced can be considered 'trustworthy' by
>      virtue of being in the keyring when that keyring is consulted.
> 
>  (4) key_alloc() and keyring_alloc() take an extra argument that will be
>      used to set restrict_link in the new key.  This ensures that the
>      pointer is set before the key is published, thus preventing a window
>      of unrestrictedness.  Normally this argument will be NULL.
> 
>  (5) As a temporary affair, keyring_restrict_trusted_only() is added.  It
>      should be passed to keyring_alloc() as the extra argument instead of
>      setting KEY_FLAG_TRUSTED_ONLY on a keyring.  This will be replaced in
>      a later patch with functions that look in the appropriate places for
>      authoritative keys.
> 
> Signed-off-by: David Howells <dhowells@...hat.com>

Rephrase restrict_link documentation comment inline below.

Reviewed-by: Mimi Zohar <zohar@...ux.vnet.ibm.com>

> ---
> 
>  Documentation/security/keys.txt  |   14 ++++++++++
>  certs/blacklist.c                |    2 +
>  certs/system_keyring.c           |    8 +++---
>  fs/cifs/cifsacl.c                |    2 +
>  fs/nfs/nfs4idmap.c               |    2 +
>  include/linux/key.h              |   48 ++++++++++++++++++++++++++++-------
>  net/dns_resolver/dns_key.c       |    2 +
>  net/rxrpc/ar-key.c               |    4 +--
>  security/integrity/digsig.c      |    7 ++---
>  security/integrity/ima/ima_mok.c |    8 +++---
>  security/keys/key.c              |   43 ++++++++++++++++++++++++++-----
>  security/keys/keyring.c          |   52 +++++++++++++++++++++++++++++++++-----
>  security/keys/persistent.c       |    4 +--
>  security/keys/process_keys.c     |   16 +++++++-----
>  security/keys/request_key.c      |    4 +--
>  security/keys/request_key_auth.c |    2 +
>  16 files changed, 165 insertions(+), 53 deletions(-)
> 
> diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
> index 8c183873b2b7..3e2e958f2091 100644
> --- a/Documentation/security/keys.txt
> +++ b/Documentation/security/keys.txt
> @@ -999,6 +999,10 @@ payload contents" for more information.
>  	struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
>  				  const struct cred *cred,
>  				  key_perm_t perm,
> +				  int (*restrict_link)(struct key *,
> +						       const struct key_type *,
> +						       unsigned long,
> +						       const union key_payload *),
>  				  unsigned long flags,
>  				  struct key *dest);
> 
> @@ -1010,6 +1014,16 @@ payload contents" for more information.
>      KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
>      towards the user's quota).  Error ENOMEM can also be returned.
> 
> +    If restrict_link not NULL, it should point to a function will be called to
> +    vet all attempts to link keys into the keyring, though this can be
> +    overridden by passing KEY_ALLOC_BYPASS_RESTRICTION to
> +    key_create_or_update().

Please fix the first part of the sentence.   Maybe add an example of
when it is appropriate to bypass the restriction - (eg. loading the
builtin keys).

> +
> +    When called, the restriction function will be passed the keyring being
> +    added to, the key flags value and the type and payload of the key being
> +    added.  Note that when a new key is being created, this is called between
> +    payload preparsing and actual key creation.
> +
> 
>  (*) To check the validity of a key, this function can be called:
> 
> diff --git a/certs/blacklist.c b/certs/blacklist.c
> index 5f54baae3a32..7f769479c17b 100644
> --- a/certs/blacklist.c
> +++ b/certs/blacklist.c
> @@ -148,7 +148,7 @@ static int __init blacklist_init(void)
>  			      KEY_USR_SEARCH,
>  			      KEY_ALLOC_NOT_IN_QUOTA |
>  			      KEY_FLAG_KEEP,
> -			      NULL);
> +			      NULL, NULL);
>  	if (IS_ERR(blacklist_keyring))
>  		panic("Can't allocate system blacklist keyring\n");
> 
> diff --git a/certs/system_keyring.c b/certs/system_keyring.c
> index dc18869ff680..417d65882870 100644
> --- a/certs/system_keyring.c
> +++ b/certs/system_keyring.c
> @@ -36,11 +36,10 @@ static __init int system_trusted_keyring_init(void)
>  			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
>  			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
> -			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +			      KEY_ALLOC_NOT_IN_QUOTA,
> +			      keyring_restrict_trusted_only, NULL);
>  	if (IS_ERR(system_trusted_keyring))
>  		panic("Can't allocate system trusted keyring\n");
> -
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
>  	return 0;
>  }
> 
> @@ -85,7 +84,8 @@ static __init int load_system_certificate_list(void)
>  					   KEY_USR_VIEW | KEY_USR_READ),
>  					   KEY_ALLOC_NOT_IN_QUOTA |
>  					   KEY_ALLOC_TRUSTED |
> -					   KEY_ALLOC_BUILT_IN);
> +					   KEY_ALLOC_BUILT_IN |
> +					   KEY_ALLOC_BYPASS_RESTRICTION);
>  		if (IS_ERR(key)) {
>  			pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
>  			       PTR_ERR(key));
> diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
> index 3f93125916bf..71e8a56e9479 100644
> --- a/fs/cifs/cifsacl.c
> +++ b/fs/cifs/cifsacl.c
> @@ -360,7 +360,7 @@ init_cifs_idmap(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
> index 5ba22c6b0ffa..c444285bb1b1 100644
> --- a/fs/nfs/nfs4idmap.c
> +++ b/fs/nfs/nfs4idmap.c
> @@ -201,7 +201,7 @@ int nfs_idmap_init(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/include/linux/key.h b/include/linux/key.h
> index 5f5b1129dc92..c331b8bed035 100644
> --- a/include/linux/key.h
> +++ b/include/linux/key.h
> @@ -174,10 +174,9 @@ struct key {
>  #define KEY_FLAG_ROOT_CAN_CLEAR	6	/* set if key can be cleared by root without permission */
>  #define KEY_FLAG_INVALIDATED	7	/* set if key has been invalidated */
>  #define KEY_FLAG_TRUSTED	8	/* set if key is trusted */
> -#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 */
> +#define KEY_FLAG_BUILTIN	9	/* set if key is built in to the kernel */
> +#define KEY_FLAG_ROOT_CAN_INVAL	10	/* set if key can be invalidated by root without permission */
> +#define KEY_FLAG_KEEP		11	/* 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
> @@ -205,6 +204,21 @@ struct key {
>  		};
>  		int reject_error;
>  	};
> +
> +	/* This is set on a keyring to restrict the addition of a link to a key
> +	 * to it.  If this method isn't provided then it is assumed that the
> +	 * keyring is open to any addition.  It is ignored for non-keyring
> +	 * keys.
> +	 *
> +	 * This is intended for use with rings of trusted keys whereby addition
> +	 * to the keyring needs to be controlled.  KEY_ALLOC_BYPASS_RESTRICTION
> +	 * overrides this, allowing the kernel to add extra keys without
> +	 * restriction.
> +	 */
> +	int (*restrict_link)(struct key *keyring,
> +			     const struct key_type *type,
> +			     unsigned long flags,
> +			     const union key_payload *payload);
>  };
> 
>  extern struct key *key_alloc(struct key_type *type,
> @@ -212,14 +226,19 @@ extern struct key *key_alloc(struct key_type *type,
>  			     kuid_t uid, kgid_t gid,
>  			     const struct cred *cred,
>  			     key_perm_t perm,
> -			     unsigned long flags);
> +			     unsigned long flags,
> +			     int (*restrict_link)(struct key *,
> +						  const struct key_type *,
> +						  unsigned long,
> +						  const union key_payload *));
> 
> 
> -#define KEY_ALLOC_IN_QUOTA	0x0000	/* add to quota, reject if would overrun */
> -#define KEY_ALLOC_QUOTA_OVERRUN	0x0001	/* add to quota, permit even if overrun */
> -#define KEY_ALLOC_NOT_IN_QUOTA	0x0002	/* not in quota */
> -#define KEY_ALLOC_TRUSTED	0x0004	/* Key should be flagged as trusted */
> -#define KEY_ALLOC_BUILT_IN	0x0008	/* Key is built into kernel */
> +#define KEY_ALLOC_IN_QUOTA		0x0000	/* add to quota, reject if would overrun */
> +#define KEY_ALLOC_QUOTA_OVERRUN		0x0001	/* add to quota, permit even if overrun */
> +#define KEY_ALLOC_NOT_IN_QUOTA		0x0002	/* not in quota */
> +#define KEY_ALLOC_TRUSTED		0x0004	/* Key should be flagged as trusted */
> +#define KEY_ALLOC_BUILT_IN		0x0008	/* Key is built into kernel */
> +#define KEY_ALLOC_BYPASS_RESTRICTION	0x0010	/* Override the check on restricted keyrings */
> 
>  extern void key_revoke(struct key *key);
>  extern void key_invalidate(struct key *key);
> @@ -288,8 +307,17 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
>  				 const struct cred *cred,
>  				 key_perm_t perm,
>  				 unsigned long flags,
> +				 int (*restrict_link)(struct key *,
> +						      const struct key_type *,
> +						      unsigned long,
> +						      const union key_payload *),
>  				 struct key *dest);
> 
> +extern int keyring_restrict_trusted_only(struct key *keyring,
> +					 const struct key_type *type,
> +					 unsigned long,
> +					 const union key_payload *payload);
> +
>  extern int keyring_clear(struct key *keyring);
> 
>  extern key_ref_t keyring_search(key_ref_t keyring,
> diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
> index c79b85eb4d4c..8737412c7b27 100644
> --- a/net/dns_resolver/dns_key.c
> +++ b/net/dns_resolver/dns_key.c
> @@ -281,7 +281,7 @@ static int __init init_dns_resolver(void)
>  				GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
>  		goto failed_put_cred;
> diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
> index 3f6571651d32..b8e87a16c544 100644
> --- a/net/rxrpc/ar-key.c
> +++ b/net/rxrpc/ar-key.c
> @@ -965,7 +965,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
> 
>  	key = key_alloc(&key_type_rxrpc, "x",
>  			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
> -			KEY_ALLOC_NOT_IN_QUOTA);
> +			KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(key)) {
>  		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
>  		return -ENOMEM;
> @@ -1012,7 +1012,7 @@ struct key *rxrpc_get_null_key(const char *keyname)
> 
>  	key = key_alloc(&key_type_rxrpc, keyname,
>  			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
> -			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
> +			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(key))
>  		return key;
> 
> diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
> index 8ef15118cc78..659566c2200b 100644
> --- a/security/integrity/digsig.c
> +++ b/security/integrity/digsig.c
> @@ -83,10 +83,9 @@ int __init integrity_init_keyring(const unsigned int id)
>  				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				     KEY_USR_VIEW | KEY_USR_READ |
>  				     KEY_USR_WRITE | KEY_USR_SEARCH),
> -				    KEY_ALLOC_NOT_IN_QUOTA, NULL);
> -	if (!IS_ERR(keyring[id]))
> -		set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
> -	else {
> +				    KEY_ALLOC_NOT_IN_QUOTA,
> +				    NULL, NULL);
> +	if (IS_ERR(keyring[id])) {
>  		err = PTR_ERR(keyring[id]);
>  		pr_info("Can't allocate %s keyring (%d)\n",
>  			keyring_name[id], err);
> diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
> index 676885e4320e..ef91248cb934 100644
> --- a/security/integrity/ima/ima_mok.c
> +++ b/security/integrity/ima/ima_mok.c
> @@ -35,20 +35,20 @@ __init int ima_mok_init(void)
>  			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  			      KEY_USR_VIEW | KEY_USR_READ |
>  			      KEY_USR_WRITE | KEY_USR_SEARCH,
> -			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +			      KEY_ALLOC_NOT_IN_QUOTA,
> +			      keyring_restrict_trusted_only, NULL);
> 
>  	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
>  				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
>  				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				KEY_USR_VIEW | KEY_USR_READ |
>  				KEY_USR_WRITE | KEY_USR_SEARCH,
> -				KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +				KEY_ALLOC_NOT_IN_QUOTA,
> +				keyring_restrict_trusted_only, NULL);
> 
>  	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
>  		panic("Can't allocate IMA MOK or blacklist keyrings.");
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
> 
> -	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
>  	set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
>  	return 0;
>  }
> diff --git a/security/keys/key.c b/security/keys/key.c
> index 48dbfa543bcb..23b271b1834d 100644
> --- a/security/keys/key.c
> +++ b/security/keys/key.c
> @@ -201,6 +201,7 @@ serial_exists:
>   * @cred: The credentials specifying UID namespace.
>   * @perm: The permissions mask of the new key.
>   * @flags: Flags specifying quota properties.
> + * @restrict_link: Optional link restriction method for new keyrings.
>   *
>   * Allocate a key of the specified type with the attributes given.  The key is
>   * returned in an uninstantiated state and the caller needs to instantiate the
> @@ -223,7 +224,11 @@ serial_exists:
>   */
>  struct key *key_alloc(struct key_type *type, const char *desc,
>  		      kuid_t uid, kgid_t gid, const struct cred *cred,
> -		      key_perm_t perm, unsigned long flags)
> +		      key_perm_t perm, unsigned long flags,
> +		      int (*restrict_link)(struct key *,
> +					   const struct key_type *,
> +					   unsigned long,
> +					   const union key_payload *))
>  {
>  	struct key_user *user = NULL;
>  	struct key *key;
> @@ -291,6 +296,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
>  	key->uid = uid;
>  	key->gid = gid;
>  	key->perm = perm;
> +	key->restrict_link = restrict_link;
> 
>  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
>  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
> @@ -495,6 +501,12 @@ int key_instantiate_and_link(struct key *key,
>  	}
> 
>  	if (keyring) {
> +		if (keyring->restrict_link) {
> +			ret = keyring->restrict_link(keyring, key->type,
> +						     key->flags, &prep.payload);
> +			if (ret < 0)
> +				goto error;
> +		}
>  		ret = __key_link_begin(keyring, &key->index_key, &edit);
>  		if (ret < 0)
>  			goto error;
> @@ -550,8 +562,12 @@ int key_reject_and_link(struct key *key,
>  	awaken = 0;
>  	ret = -EBUSY;
> 
> -	if (keyring)
> +	if (keyring) {
> +		if (keyring->restrict_link)
> +			return -EPERM;
> +
>  		link_ret = __key_link_begin(keyring, &key->index_key, &edit);
> +	}
> 
>  	mutex_lock(&key_construction_mutex);
> 
> @@ -792,6 +808,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  	struct key *keyring, *key = NULL;
>  	key_ref_t key_ref;
>  	int ret;
> +	int (*restrict_link)(struct key *,
> +			     const struct key_type *,
> +			     unsigned long,
> +			     const union key_payload *) = NULL;
> 
>  	/* look up the key type to see if it's one of the registered kernel
>  	 * types */
> @@ -810,6 +830,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
> 
>  	key_check(keyring);
> 
> +	key_ref = ERR_PTR(-EPERM);
> +	if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
> +		restrict_link = keyring->restrict_link;
> +
>  	key_ref = ERR_PTR(-ENOTDIR);
>  	if (keyring->type != &key_type_keyring)
>  		goto error_put_type;
> @@ -834,10 +858,15 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
>  	}
>  	index_key.desc_len = strlen(index_key.description);
> 
> -	key_ref = ERR_PTR(-EPERM);
> -	if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
> -		goto error_free_prep;
> -	flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
> +	if (restrict_link) {
> +		unsigned long kflags = prep.trusted ? KEY_FLAG_TRUSTED : 0;
> +		ret = restrict_link(keyring,
> +				    index_key.type, kflags, &prep.payload);
> +		if (ret < 0) {
> +			key_ref = ERR_PTR(ret);
> +			goto error_free_prep;
> +		}
> +	}
> 
>  	ret = __key_link_begin(keyring, &index_key, &edit);
>  	if (ret < 0) {
> @@ -878,7 +907,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
> 
>  	/* allocate a new key */
>  	key = key_alloc(index_key.type, index_key.description,
> -			cred->fsuid, cred->fsgid, cred, perm, flags);
> +			cred->fsuid, cred->fsgid, cred, perm, flags, NULL);
>  	if (IS_ERR(key)) {
>  		key_ref = ERR_CAST(key);
>  		goto error_link_end;
> diff --git a/security/keys/keyring.c b/security/keys/keyring.c
> index f931ccfeefb0..ea023ca6d217 100644
> --- a/security/keys/keyring.c
> +++ b/security/keys/keyring.c
> @@ -491,13 +491,18 @@ static long keyring_read(const struct key *keyring,
>   */
>  struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
>  			  const struct cred *cred, key_perm_t perm,
> -			  unsigned long flags, struct key *dest)
> +			  unsigned long flags,
> +			  int (*restrict_link)(struct key *,
> +					       const struct key_type *,
> +					       unsigned long,
> +					       const union key_payload *),
> +			  struct key *dest)
>  {
>  	struct key *keyring;
>  	int ret;
> 
>  	keyring = key_alloc(&key_type_keyring, description,
> -			    uid, gid, cred, perm, flags);
> +			    uid, gid, cred, perm, flags, restrict_link);
>  	if (!IS_ERR(keyring)) {
>  		ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
>  		if (ret < 0) {
> @@ -510,6 +515,30 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
>  }
>  EXPORT_SYMBOL(keyring_alloc);
> 
> +/**
> + * keyring_restrict_trusted_only - Restrict additions to a keyring to trusted keys only
> + * @keyring: The keyring being added to.
> + * @type: The type of key being added.
> + * @flags: The key flags.
> + * @payload: The payload of the key intended to be added.
> + *
> + * Reject the addition of any links to a keyring that point to keys that aren't
> + * marked as being trusted.  It can be overridden by passing
> + * KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when adding a key
> + * to a keyring.
> + *
> + * This is meant to be passed as the restrict_link parameter to
> + * keyring_alloc().
> + */
> +int keyring_restrict_trusted_only(struct key *keyring,
> +				  const struct key_type *type,
> +				  unsigned long flags,
> +				  const union key_payload *payload)
> +{
> +	
> +	return flags & KEY_FLAG_TRUSTED ? 0 : -EPERM;
> +}
> +
>  /*
>   * By default, we keys found by getting an exact match on their descriptions.
>   */
> @@ -1191,6 +1220,17 @@ void __key_link_end(struct key *keyring,
>  	up_write(&keyring->sem);
>  }
> 
> +/*
> + * Check addition of keys to restricted keyrings.
> + */
> +static int __key_link_check_restriction(struct key *keyring, struct key *key)
> +{
> +	if (!keyring->restrict_link)
> +		return 0;
> +	return keyring->restrict_link(keyring,
> +				      key->type, key->flags, &key->payload);
> +}
> +
>  /**
>   * key_link - Link a key to a keyring
>   * @keyring: The keyring to make the link in.
> @@ -1221,14 +1261,12 @@ int key_link(struct key *keyring, struct key *key)
>  	key_check(keyring);
>  	key_check(key);
> 
> -	if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
> -	    !test_bit(KEY_FLAG_TRUSTED, &key->flags))
> -		return -EPERM;
> -
>  	ret = __key_link_begin(keyring, &key->index_key, &edit);
>  	if (ret == 0) {
>  		kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
> -		ret = __key_link_check_live_key(keyring, key);
> +		ret = __key_link_check_restriction(keyring, key);
> +		if (ret == 0)
> +			ret = __key_link_check_live_key(keyring, key);
>  		if (ret == 0)
>  			__key_link(key, &edit);
>  		__key_link_end(keyring, &key->index_key, edit);
> diff --git a/security/keys/persistent.c b/security/keys/persistent.c
> index c9fae5ea89fe..2ef45b319dd9 100644
> --- a/security/keys/persistent.c
> +++ b/security/keys/persistent.c
> @@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns)
>  					current_cred(),
>  					((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  					 KEY_USR_VIEW | KEY_USR_READ),
> -					KEY_ALLOC_NOT_IN_QUOTA, NULL);
> +					KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
>  	if (IS_ERR(reg))
>  		return PTR_ERR(reg);
> 
> @@ -60,7 +60,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
>  				   uid, INVALID_GID, current_cred(),
>  				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
>  				    KEY_USR_VIEW | KEY_USR_READ),
> -				   KEY_ALLOC_NOT_IN_QUOTA,
> +				   KEY_ALLOC_NOT_IN_QUOTA, NULL,
>  				   ns->persistent_keyring_register);
>  	if (IS_ERR(persistent))
>  		return ERR_CAST(persistent);
> diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
> index a3f85d2a00bb..9bb6bb5fd845 100644
> --- a/security/keys/process_keys.c
> +++ b/security/keys/process_keys.c
> @@ -76,7 +76,8 @@ int install_user_keyrings(void)
>  		if (IS_ERR(uid_keyring)) {
>  			uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
>  						    cred, user_keyring_perm,
> -						    KEY_ALLOC_IN_QUOTA, NULL);
> +						    KEY_ALLOC_IN_QUOTA,
> +						    NULL, NULL);
>  			if (IS_ERR(uid_keyring)) {
>  				ret = PTR_ERR(uid_keyring);
>  				goto error;
> @@ -92,7 +93,8 @@ int install_user_keyrings(void)
>  			session_keyring =
>  				keyring_alloc(buf, user->uid, INVALID_GID,
>  					      cred, user_keyring_perm,
> -					      KEY_ALLOC_IN_QUOTA, NULL);
> +					      KEY_ALLOC_IN_QUOTA,
> +					      NULL, NULL);
>  			if (IS_ERR(session_keyring)) {
>  				ret = PTR_ERR(session_keyring);
>  				goto error_release;
> @@ -134,7 +136,8 @@ int install_thread_keyring_to_cred(struct cred *new)
> 
>  	keyring = keyring_alloc("_tid", new->uid, new->gid, new,
>  				KEY_POS_ALL | KEY_USR_VIEW,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN,
> +				NULL, NULL);
>  	if (IS_ERR(keyring))
>  		return PTR_ERR(keyring);
> 
> @@ -180,7 +183,8 @@ int install_process_keyring_to_cred(struct cred *new)
> 
>  	keyring = keyring_alloc("_pid", new->uid, new->gid, new,
>  				KEY_POS_ALL | KEY_USR_VIEW,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN,
> +				NULL, NULL);
>  	if (IS_ERR(keyring))
>  		return PTR_ERR(keyring);
> 
> @@ -231,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
> 
>  		keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
>  					KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
> -					flags, NULL);
> +					flags, NULL, NULL);
>  		if (IS_ERR(keyring))
>  			return PTR_ERR(keyring);
>  	} else {
> @@ -785,7 +789,7 @@ long join_session_keyring(const char *name)
>  		keyring = keyring_alloc(
>  			name, old->uid, old->gid, old,
>  			KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
> -			KEY_ALLOC_IN_QUOTA, NULL);
> +			KEY_ALLOC_IN_QUOTA, NULL, NULL);
>  		if (IS_ERR(keyring)) {
>  			ret = PTR_ERR(keyring);
>  			goto error2;
> diff --git a/security/keys/request_key.c b/security/keys/request_key.c
> index c7a117c9a8f3..a29e3554751e 100644
> --- a/security/keys/request_key.c
> +++ b/security/keys/request_key.c
> @@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons,
>  	cred = get_current_cred();
>  	keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
>  				KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
> -				KEY_ALLOC_QUOTA_OVERRUN, NULL);
> +				KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
>  	put_cred(cred);
>  	if (IS_ERR(keyring)) {
>  		ret = PTR_ERR(keyring);
> @@ -355,7 +355,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
> 
>  	key = key_alloc(ctx->index_key.type, ctx->index_key.description,
>  			ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
> -			perm, flags);
> +			perm, flags, NULL);
>  	if (IS_ERR(key))
>  		goto alloc_failed;
> 
> diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
> index 4f0f112fe276..9db8b4a82787 100644
> --- a/security/keys/request_key_auth.c
> +++ b/security/keys/request_key_auth.c
> @@ -202,7 +202,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
>  	authkey = key_alloc(&key_type_request_key_auth, desc,
>  			    cred->fsuid, cred->fsgid, cred,
>  			    KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
> -			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
> +			    KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL);
>  	if (IS_ERR(authkey)) {
>  		ret = PTR_ERR(authkey);
>  		goto error_alloc;
> 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ