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 <[email protected]>

Rephrase restrict_link documentation comment inline below.

Reviewed-by: Mimi Zohar <[email protected]>

> ---
> 
>  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;
> 


Reply via email to