KEYS: Preparse match data
authorDavid Howells <dhowells@redhat.com>
Tue, 16 Sep 2014 16:36:02 +0000 (17:36 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 16 Sep 2014 16:36:02 +0000 (17:36 +0100)
Preparse the match data.  This provides several advantages:

 (1) The preparser can reject invalid criteria up front.

 (2) The preparser can convert the criteria to binary data if necessary (the
     asymmetric key type really wants to do binary comparison of the key IDs).

 (3) The preparser can set the type of search to be performed.  This means
     that it's not then a one-off setting in the key type.

 (4) The preparser can set an appropriate comparator function.

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
crypto/asymmetric_keys/asymmetric_type.c
include/keys/user-type.h
include/linux/key-type.h
net/dns_resolver/dns_key.c
security/keys/internal.h
security/keys/keyring.c
security/keys/proc.c
security/keys/process_keys.c
security/keys/request_key.c
security/keys/request_key_auth.c
security/keys/user_defined.c

index eb8cd46961a5aa5a6a7470c6d17008d1745bbdf6..f666b4e8d25690544d07967f95ee18b935a0bbde 100644 (file)
@@ -59,9 +59,11 @@ EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
  *     "id:<id>"       - request a key matching the ID
  *     "<subtype>:<id>" - request a key of a subtype
  */
-static int asymmetric_key_match(const struct key *key, const void *description)
+static int asymmetric_key_match(const struct key *key,
+                               const struct key_match_data *match_data)
 {
        const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+       const char *description = match_data->raw_data;
        const char *spec = description;
        const char *id;
        ptrdiff_t speclen;
@@ -93,6 +95,31 @@ static int asymmetric_key_match(const struct key *key, const void *description)
        return 0;
 }
 
+/*
+ * Preparse the match criterion.  If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
+ *
+ *     "id:<id>" - request a key by any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
+ */
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
+{
+       match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+       return 0;
+}
+
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+}
+
 /*
  * Describe the asymmetric key
  */
@@ -196,7 +223,9 @@ struct key_type key_type_asymmetric = {
        .preparse       = asymmetric_key_preparse,
        .free_preparse  = asymmetric_key_free_preparse,
        .instantiate    = generic_key_instantiate,
+       .match_preparse = asymmetric_key_match_preparse,
        .match          = asymmetric_key_match,
+       .match_free     = asymmetric_key_match_free,
        .destroy        = asymmetric_key_destroy,
        .describe       = asymmetric_key_describe,
        .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
index 3ab1873a4bfab05571bdbc60a60c8a31df5dfde5..66d92af30e7c0e5c32edbd308ebbb3f49c04b6df 100644 (file)
@@ -36,11 +36,13 @@ extern struct key_type key_type_user;
 extern struct key_type key_type_logon;
 
 struct key_preparsed_payload;
+struct key_match_data;
 
 extern int user_preparse(struct key_preparsed_payload *prep);
 extern void user_free_preparse(struct key_preparsed_payload *prep);
 extern int user_update(struct key *key, struct key_preparsed_payload *prep);
-extern int user_match(const struct key *key, const void *criterion);
+extern int user_match(const struct key *key,
+                     const struct key_match_data *match_data);
 extern void user_revoke(struct key *key);
 extern void user_destroy(struct key *key);
 extern void user_describe(const struct key *user, struct seq_file *m);
index 44792ee649de2513b8f5dba53d29758cacef2f24..8aba688a451a08a5f5fd6bba16870c6522cd3995 100644 (file)
@@ -52,6 +52,22 @@ struct key_preparsed_payload {
 typedef int (*request_key_actor_t)(struct key_construction *key,
                                   const char *op, void *aux);
 
+/*
+ * Preparsed matching criterion.
+ */
+struct key_match_data {
+       /* Comparison function, defaults to type->match, but can be replaced by
+        * type->match_preparse(). */
+       int (*cmp)(const struct key *key,
+                  const struct key_match_data *match_data);
+
+       const void      *raw_data;      /* Raw match data */
+       void            *preparsed;     /* For ->match_preparse() to stash stuff */
+       unsigned        lookup_type;    /* Type of lookup for this search. */
+#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
+#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
+};
+
 /*
  * kernel managed key type definition
  */
@@ -67,8 +83,6 @@ struct key_type {
 
        /* Default key search algorithm. */
        unsigned def_lookup_type;
-#define KEYRING_SEARCH_LOOKUP_DIRECT   0x0000  /* Direct lookup by description. */
-#define KEYRING_SEARCH_LOOKUP_ITERATE  0x0001  /* Iterative search. */
 
        /* vet a description */
        int (*vet_description)(const char *description);
@@ -96,8 +110,19 @@ struct key_type {
         */
        int (*update)(struct key *key, struct key_preparsed_payload *prep);
 
+       /* Preparse the data supplied to ->match() (optional).  The
+        * data to be preparsed can be found in match_data->raw_data.
+        * The lookup type can also be set by this function.
+        */
+       int (*match_preparse)(struct key_match_data *match_data);
+
        /* match a key against a description */
-       int (*match)(const struct key *key, const void *desc);
+       int (*match)(const struct key *key,
+                    const struct key_match_data *match_data);
+
+       /* Free preparsed match data (optional).  This should be supplied it
+        * ->match_preparse() is supplied. */
+       void (*match_free)(struct key_match_data *match_data);
 
        /* clear some of the data from a key on revokation (optional)
         * - the key's semaphore will be write-locked by the caller
index f380b2c581781433f2091fec38c7ad77f46f1fae..92df6e508ae7d094601282700d98eedea2b8877f 100644 (file)
@@ -177,10 +177,11 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
  * should end with a period).  The domain name is case-independent.
  */
 static int
-dns_resolver_match(const struct key *key, const void *description)
+dns_resolver_match(const struct key *key,
+                  const struct key_match_data *match_data)
 {
        int slen, dlen, ret = 0;
-       const char *src = key->description, *dsp = description;
+       const char *src = key->description, *dsp = match_data->raw_data;
 
        kenter("%s,%s", src, dsp);
 
index 5f20da01fd8d317f835375de9654f42c1a1b4e8b..805e60b0b87ebe8a90e934cd0aaa52efd24a1a1e 100644 (file)
@@ -107,13 +107,10 @@ extern int iterate_over_keyring(const struct key *keyring,
                                int (*func)(const struct key *key, void *data),
                                void *data);
 
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
 struct keyring_search_context {
        struct keyring_index_key index_key;
        const struct cred       *cred;
-       key_match_func_t        match;
-       const void              *match_data;
+       struct key_match_data   match_data;
        unsigned                flags;
 #define KEYRING_SEARCH_LOOKUP_TYPE     0x0001  /* [as type->def_lookup_type] */
 #define KEYRING_SEARCH_NO_STATE_CHECK  0x0002  /* Skip state checks */
@@ -152,7 +149,8 @@ extern struct key *request_key_and_link(struct key_type *type,
                                        struct key *dest_keyring,
                                        unsigned long flags);
 
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern int lookup_user_key_possessed(const struct key *key,
+                                    const struct key_match_data *match_data);
 extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
                                 key_perm_t perm);
 #define KEY_LOOKUP_CREATE      0x01
index 8314a7d2104df95ead666466213819504a31d5c2..10f0a5f2d3620ce775a529b6090cb61667360ec6 100644 (file)
@@ -545,7 +545,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
        }
 
        /* keys that don't match */
-       if (!ctx->match(key, ctx->match_data)) {
+       if (!ctx->match_data.cmp(key, &ctx->match_data)) {
                kleave(" = 0 [!match]");
                return 0;
        }
@@ -585,8 +585,7 @@ skipped:
  */
 static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
 {
-       if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
-           KEYRING_SEARCH_LOOKUP_DIRECT) {
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
                const void *object;
 
                object = assoc_array_find(&keyring->keys,
@@ -627,7 +626,7 @@ static bool search_nested_keyrings(struct key *keyring,
        /* Check to see if this top-level keyring is what we are looking for
         * and whether it is valid or not.
         */
-       if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+       if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
            keyring_compare_object(keyring, &ctx->index_key)) {
                ctx->skipped_ret = 2;
                ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
@@ -885,16 +884,28 @@ key_ref_t keyring_search(key_ref_t keyring,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = (type->def_lookup_type |
-                                          KEYRING_SEARCH_DO_STATE_CHECK),
+               .match_data.cmp         = type->match,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_DO_STATE_CHECK,
        };
+       key_ref_t key;
+       int ret;
 
-       if (!ctx.match)
+       if (!ctx.match_data.cmp)
                return ERR_PTR(-ENOKEY);
 
-       return keyring_search_aux(keyring, &ctx);
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+       }
+
+       key = keyring_search_aux(keyring, &ctx);
+
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
+       return key;
 }
 EXPORT_SYMBOL(keyring_search);
 
@@ -1014,7 +1025,7 @@ static int keyring_detect_cycle_iterator(const void *object,
 
        /* We might get a keyring with matching index-key that is nonetheless a
         * different keyring. */
-       if (key != ctx->match_data)
+       if (key != ctx->match_data.raw_data)
                return 0;
 
        ctx->result = ERR_PTR(-EDEADLK);
@@ -1031,14 +1042,14 @@ static int keyring_detect_cycle_iterator(const void *object,
 static int keyring_detect_cycle(struct key *A, struct key *B)
 {
        struct keyring_search_context ctx = {
-               .index_key      = A->index_key,
-               .match_data     = A,
-               .iterator       = keyring_detect_cycle_iterator,
-               .flags          = (KEYRING_SEARCH_LOOKUP_DIRECT |
-                                  KEYRING_SEARCH_NO_STATE_CHECK |
-                                  KEYRING_SEARCH_NO_UPDATE_TIME |
-                                  KEYRING_SEARCH_NO_CHECK_PERM |
-                                  KEYRING_SEARCH_DETECT_TOO_DEEP),
+               .index_key              = A->index_key,
+               .match_data.raw_data    = A,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .iterator               = keyring_detect_cycle_iterator,
+               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
+                                          KEYRING_SEARCH_NO_UPDATE_TIME |
+                                          KEYRING_SEARCH_NO_CHECK_PERM |
+                                          KEYRING_SEARCH_DETECT_TOO_DEEP),
        };
 
        rcu_read_lock();
index d3f6f2fd21db84bc197ed82b14808b6bc9bc4e87..972eeb336b8145b0529001c38f64a53e2e8f8c5a 100644 (file)
@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
                .index_key.type         = key->type,
                .index_key.description  = key->description,
                .cred                   = current_cred(),
-               .match                  = lookup_user_key_possessed,
-               .match_data             = key,
-               .flags                  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.raw_data    = key,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
 
        key_ref = make_key_ref(key, 0);
index 0cf8a130a267ca58fbc5599787c93b9913cfc576..08bd533d014fd87a31f5e3570c5e8b646b75252d 100644 (file)
@@ -489,9 +489,10 @@ found:
 /*
  * See if the key we're looking at is the target key.
  */
-int lookup_user_key_possessed(const struct key *key, const void *target)
+int lookup_user_key_possessed(const struct key *key,
+                             const struct key_match_data *match_data)
 {
-       return key == target;
+       return key == match_data->raw_data;
 }
 
 /*
@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
                          key_perm_t perm)
 {
        struct keyring_search_context ctx = {
-               .match  = lookup_user_key_possessed,
-               .flags  = (KEYRING_SEARCH_NO_STATE_CHECK |
-                          KEYRING_SEARCH_LOOKUP_DIRECT),
+               .match_data.cmp         = lookup_user_key_possessed,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .flags                  = KEYRING_SEARCH_NO_STATE_CHECK,
        };
        struct request_key_auth *rka;
        struct key *key;
@@ -673,7 +674,7 @@ try_again:
                ctx.index_key.type              = key->type;
                ctx.index_key.description       = key->description;
                ctx.index_key.desc_len          = strlen(key->description);
-               ctx.match_data                  = key;
+               ctx.match_data.raw_data         = key;
                kdebug("check possessed");
                skey_ref = search_process_keyrings(&ctx);
                kdebug("possessed=%p", skey_ref);
index 381411941cc1abbc48a699b1c2c38042f1a05711..408523e5e2e2eef5ccb421ed33d4986d15dcad84 100644 (file)
@@ -531,9 +531,9 @@ struct key *request_key_and_link(struct key_type *type,
                .index_key.type         = type,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = type->match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = type->match,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *key;
        key_ref_t key_ref;
@@ -543,6 +543,14 @@ struct key *request_key_and_link(struct key_type *type,
               ctx.index_key.type->name, ctx.index_key.description,
               callout_info, callout_len, aux, dest_keyring, flags);
 
+       if (type->match_preparse) {
+               ret = type->match_preparse(&ctx.match_data);
+               if (ret < 0) {
+                       key = ERR_PTR(ret);
+                       goto error;
+               }
+       }
+
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(&ctx);
 
@@ -555,7 +563,7 @@ struct key *request_key_and_link(struct key_type *type,
                        if (ret < 0) {
                                key_put(key);
                                key = ERR_PTR(ret);
-                               goto error;
+                               goto error_free;
                        }
                }
        } else if (PTR_ERR(key_ref) != -EAGAIN) {
@@ -565,12 +573,15 @@ struct key *request_key_and_link(struct key_type *type,
                 * should consult userspace if we can */
                key = ERR_PTR(-ENOKEY);
                if (!callout_info)
-                       goto error;
+                       goto error_free;
 
                key = construct_key_and_link(&ctx, callout_info, callout_len,
                                             aux, dest_keyring, flags);
        }
 
+error_free:
+       if (type->match_free)
+               type->match_free(&ctx.match_data);
 error:
        kleave(" = %p", key);
        return key;
index 739e7455d388192a9e505679c4ac0782a09921c5..9ae02819cc064f3c68ef505b4a2ca75c7b762264 100644 (file)
@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
                .index_key.type         = &key_type_request_key_auth,
                .index_key.description  = description,
                .cred                   = current_cred(),
-               .match                  = user_match,
-               .match_data             = description,
-               .flags                  = KEYRING_SEARCH_LOOKUP_DIRECT,
+               .match_data.cmp         = user_match,
+               .match_data.raw_data    = description,
+               .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
        };
        struct key *authkey;
        key_ref_t authkey_ref;
index eee340011f2bd54d7b12f3f28a25ec3f8396b5fd..ec8a56063b021278215e83352be0f3220ee7b10b 100644 (file)
@@ -141,9 +141,9 @@ EXPORT_SYMBOL_GPL(user_update);
 /*
  * match users on their name
  */
-int user_match(const struct key *key, const void *description)
+int user_match(const struct key *key, const struct key_match_data *match_data)
 {
-       return strcmp(key->description, description) == 0;
+       return strcmp(key->description, match_data->raw_data) == 0;
 }
 
 EXPORT_SYMBOL_GPL(user_match);