Commit 46291959 authored by David Howells's avatar David Howells

KEYS: Preparse match data

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: default avatarDavid Howells <dhowells@redhat.com>
Acked-by: default avatarVivek Goyal <vgoyal@redhat.com>
parent 53d91c5c
...@@ -59,9 +59,11 @@ EXPORT_SYMBOL_GPL(asymmetric_keyid_match); ...@@ -59,9 +59,11 @@ EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
* "id:<id>" - request a key matching the ID * "id:<id>" - request a key matching the ID
* "<subtype>:<id>" - request a key of a subtype * "<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 struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *description = match_data->raw_data;
const char *spec = description; const char *spec = description;
const char *id; const char *id;
ptrdiff_t speclen; ptrdiff_t speclen;
...@@ -93,6 +95,31 @@ static int asymmetric_key_match(const struct key *key, const void *description) ...@@ -93,6 +95,31 @@ static int asymmetric_key_match(const struct key *key, const void *description)
return 0; 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 * Describe the asymmetric key
*/ */
...@@ -196,7 +223,9 @@ struct key_type key_type_asymmetric = { ...@@ -196,7 +223,9 @@ struct key_type key_type_asymmetric = {
.preparse = asymmetric_key_preparse, .preparse = asymmetric_key_preparse,
.free_preparse = asymmetric_key_free_preparse, .free_preparse = asymmetric_key_free_preparse,
.instantiate = generic_key_instantiate, .instantiate = generic_key_instantiate,
.match_preparse = asymmetric_key_match_preparse,
.match = asymmetric_key_match, .match = asymmetric_key_match,
.match_free = asymmetric_key_match_free,
.destroy = asymmetric_key_destroy, .destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe, .describe = asymmetric_key_describe,
.def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE, .def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
......
...@@ -36,11 +36,13 @@ extern struct key_type key_type_user; ...@@ -36,11 +36,13 @@ extern struct key_type key_type_user;
extern struct key_type key_type_logon; extern struct key_type key_type_logon;
struct key_preparsed_payload; struct key_preparsed_payload;
struct key_match_data;
extern int user_preparse(struct key_preparsed_payload *prep); extern int user_preparse(struct key_preparsed_payload *prep);
extern void user_free_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_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_revoke(struct key *key);
extern void user_destroy(struct key *key); extern void user_destroy(struct key *key);
extern void user_describe(const struct key *user, struct seq_file *m); extern void user_describe(const struct key *user, struct seq_file *m);
......
...@@ -52,6 +52,22 @@ struct key_preparsed_payload { ...@@ -52,6 +52,22 @@ struct key_preparsed_payload {
typedef int (*request_key_actor_t)(struct key_construction *key, typedef int (*request_key_actor_t)(struct key_construction *key,
const char *op, void *aux); 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 * kernel managed key type definition
*/ */
...@@ -67,8 +83,6 @@ struct key_type { ...@@ -67,8 +83,6 @@ struct key_type {
/* Default key search algorithm. */ /* Default key search algorithm. */
unsigned def_lookup_type; 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 */ /* vet a description */
int (*vet_description)(const char *description); int (*vet_description)(const char *description);
...@@ -96,8 +110,19 @@ struct key_type { ...@@ -96,8 +110,19 @@ struct key_type {
*/ */
int (*update)(struct key *key, struct key_preparsed_payload *prep); 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 */ /* 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) /* clear some of the data from a key on revokation (optional)
* - the key's semaphore will be write-locked by the caller * - the key's semaphore will be write-locked by the caller
......
...@@ -177,10 +177,11 @@ static void dns_resolver_free_preparse(struct key_preparsed_payload *prep) ...@@ -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. * should end with a period). The domain name is case-independent.
*/ */
static int 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; 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); kenter("%s,%s", src, dsp);
......
...@@ -107,13 +107,10 @@ extern int iterate_over_keyring(const struct key *keyring, ...@@ -107,13 +107,10 @@ extern int iterate_over_keyring(const struct key *keyring,
int (*func)(const struct key *key, void *data), int (*func)(const struct key *key, void *data),
void *data); void *data);
typedef int (*key_match_func_t)(const struct key *, const void *);
struct keyring_search_context { struct keyring_search_context {
struct keyring_index_key index_key; struct keyring_index_key index_key;
const struct cred *cred; const struct cred *cred;
key_match_func_t match; struct key_match_data match_data;
const void *match_data;
unsigned flags; unsigned flags;
#define KEYRING_SEARCH_LOOKUP_TYPE 0x0001 /* [as type->def_lookup_type] */ #define KEYRING_SEARCH_LOOKUP_TYPE 0x0001 /* [as type->def_lookup_type] */
#define KEYRING_SEARCH_NO_STATE_CHECK 0x0002 /* Skip state checks */ #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, ...@@ -152,7 +149,8 @@ extern struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring, struct key *dest_keyring,
unsigned long flags); 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, extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
key_perm_t perm); key_perm_t perm);
#define KEY_LOOKUP_CREATE 0x01 #define KEY_LOOKUP_CREATE 0x01
......
...@@ -545,7 +545,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) ...@@ -545,7 +545,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
} }
/* keys that don't match */ /* keys that don't match */
if (!ctx->match(key, ctx->match_data)) { if (!ctx->match_data.cmp(key, &ctx->match_data)) {
kleave(" = 0 [!match]"); kleave(" = 0 [!match]");
return 0; return 0;
} }
...@@ -585,8 +585,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) ...@@ -585,8 +585,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
*/ */
static int search_keyring(struct key *keyring, struct keyring_search_context *ctx) static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
{ {
if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) == if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
KEYRING_SEARCH_LOOKUP_DIRECT) {
const void *object; const void *object;
object = assoc_array_find(&keyring->keys, object = assoc_array_find(&keyring->keys,
...@@ -627,7 +626,7 @@ static bool search_nested_keyrings(struct key *keyring, ...@@ -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 /* Check to see if this top-level keyring is what we are looking for
* and whether it is valid or not. * 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)) { keyring_compare_object(keyring, &ctx->index_key)) {
ctx->skipped_ret = 2; ctx->skipped_ret = 2;
ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK; ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
...@@ -885,16 +884,28 @@ key_ref_t keyring_search(key_ref_t keyring, ...@@ -885,16 +884,28 @@ key_ref_t keyring_search(key_ref_t keyring,
.index_key.type = type, .index_key.type = type,
.index_key.description = description, .index_key.description = description,
.cred = current_cred(), .cred = current_cred(),
.match = type->match, .match_data.cmp = type->match,
.match_data = description, .match_data.raw_data = description,
.flags = (type->def_lookup_type | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
KEYRING_SEARCH_DO_STATE_CHECK), .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 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); EXPORT_SYMBOL(keyring_search);
...@@ -1014,7 +1025,7 @@ static int keyring_detect_cycle_iterator(const void *object, ...@@ -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 /* We might get a keyring with matching index-key that is nonetheless a
* different keyring. */ * different keyring. */
if (key != ctx->match_data) if (key != ctx->match_data.raw_data)
return 0; return 0;
ctx->result = ERR_PTR(-EDEADLK); ctx->result = ERR_PTR(-EDEADLK);
...@@ -1031,14 +1042,14 @@ static int keyring_detect_cycle_iterator(const void *object, ...@@ -1031,14 +1042,14 @@ static int keyring_detect_cycle_iterator(const void *object,
static int keyring_detect_cycle(struct key *A, struct key *B) static int keyring_detect_cycle(struct key *A, struct key *B)
{ {
struct keyring_search_context ctx = { struct keyring_search_context ctx = {
.index_key = A->index_key, .index_key = A->index_key,
.match_data = A, .match_data.raw_data = A,
.iterator = keyring_detect_cycle_iterator, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.flags = (KEYRING_SEARCH_LOOKUP_DIRECT | .iterator = keyring_detect_cycle_iterator,
KEYRING_SEARCH_NO_STATE_CHECK | .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
KEYRING_SEARCH_NO_UPDATE_TIME | KEYRING_SEARCH_NO_UPDATE_TIME |
KEYRING_SEARCH_NO_CHECK_PERM | KEYRING_SEARCH_NO_CHECK_PERM |
KEYRING_SEARCH_DETECT_TOO_DEEP), KEYRING_SEARCH_DETECT_TOO_DEEP),
}; };
rcu_read_lock(); rcu_read_lock();
......
...@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -194,10 +194,10 @@ static int proc_keys_show(struct seq_file *m, void *v)
.index_key.type = key->type, .index_key.type = key->type,
.index_key.description = key->description, .index_key.description = key->description,
.cred = current_cred(), .cred = current_cred(),
.match = lookup_user_key_possessed, .match_data.cmp = lookup_user_key_possessed,
.match_data = key, .match_data.raw_data = key,
.flags = (KEYRING_SEARCH_NO_STATE_CHECK | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
KEYRING_SEARCH_LOOKUP_DIRECT), .flags = KEYRING_SEARCH_NO_STATE_CHECK,
}; };
key_ref = make_key_ref(key, 0); key_ref = make_key_ref(key, 0);
......
...@@ -489,9 +489,10 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx) ...@@ -489,9 +489,10 @@ key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
/* /*
* See if the key we're looking at is the target key. * 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, ...@@ -516,9 +517,9 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_perm_t perm) key_perm_t perm)
{ {
struct keyring_search_context ctx = { struct keyring_search_context ctx = {
.match = lookup_user_key_possessed, .match_data.cmp = lookup_user_key_possessed,
.flags = (KEYRING_SEARCH_NO_STATE_CHECK | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
KEYRING_SEARCH_LOOKUP_DIRECT), .flags = KEYRING_SEARCH_NO_STATE_CHECK,
}; };
struct request_key_auth *rka; struct request_key_auth *rka;
struct key *key; struct key *key;
...@@ -673,7 +674,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -673,7 +674,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ctx.index_key.type = key->type; ctx.index_key.type = key->type;
ctx.index_key.description = key->description; ctx.index_key.description = key->description;
ctx.index_key.desc_len = strlen(key->description); ctx.index_key.desc_len = strlen(key->description);
ctx.match_data = key; ctx.match_data.raw_data = key;
kdebug("check possessed"); kdebug("check possessed");
skey_ref = search_process_keyrings(&ctx); skey_ref = search_process_keyrings(&ctx);
kdebug("possessed=%p", skey_ref); kdebug("possessed=%p", skey_ref);
......
...@@ -531,9 +531,9 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -531,9 +531,9 @@ struct key *request_key_and_link(struct key_type *type,
.index_key.type = type, .index_key.type = type,
.index_key.description = description, .index_key.description = description,
.cred = current_cred(), .cred = current_cred(),
.match = type->match, .match_data.cmp = type->match,
.match_data = description, .match_data.raw_data = description,
.flags = KEYRING_SEARCH_LOOKUP_DIRECT, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
}; };
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
...@@ -543,6 +543,14 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -543,6 +543,14 @@ struct key *request_key_and_link(struct key_type *type,
ctx.index_key.type->name, ctx.index_key.description, ctx.index_key.type->name, ctx.index_key.description,
callout_info, callout_len, aux, dest_keyring, flags); 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 */ /* search all the process keyrings for a key */
key_ref = search_process_keyrings(&ctx); key_ref = search_process_keyrings(&ctx);
...@@ -555,7 +563,7 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -555,7 +563,7 @@ struct key *request_key_and_link(struct key_type *type,
if (ret < 0) { if (ret < 0) {
key_put(key); key_put(key);
key = ERR_PTR(ret); key = ERR_PTR(ret);
goto error; goto error_free;
} }
} }
} else if (PTR_ERR(key_ref) != -EAGAIN) { } else if (PTR_ERR(key_ref) != -EAGAIN) {
...@@ -565,12 +573,15 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -565,12 +573,15 @@ struct key *request_key_and_link(struct key_type *type,
* should consult userspace if we can */ * should consult userspace if we can */
key = ERR_PTR(-ENOKEY); key = ERR_PTR(-ENOKEY);
if (!callout_info) if (!callout_info)
goto error; goto error_free;
key = construct_key_and_link(&ctx, callout_info, callout_len, key = construct_key_and_link(&ctx, callout_info, callout_len,
aux, dest_keyring, flags); aux, dest_keyring, flags);
} }
error_free:
if (type->match_free)
type->match_free(&ctx.match_data);
error: error:
kleave(" = %p", key); kleave(" = %p", key);
return key; return key;
......
...@@ -246,9 +246,9 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) ...@@ -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.type = &key_type_request_key_auth,
.index_key.description = description, .index_key.description = description,
.cred = current_cred(), .cred = current_cred(),
.match = user_match, .match_data.cmp = user_match,
.match_data = description, .match_data.raw_data = description,
.flags = KEYRING_SEARCH_LOOKUP_DIRECT, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
}; };
struct key *authkey; struct key *authkey;
key_ref_t authkey_ref; key_ref_t authkey_ref;
......
...@@ -141,9 +141,9 @@ EXPORT_SYMBOL_GPL(user_update); ...@@ -141,9 +141,9 @@ EXPORT_SYMBOL_GPL(user_update);
/* /*
* match users on their name * 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); EXPORT_SYMBOL_GPL(user_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment