Skip to content

Commit

Permalink
KEYS: Preparse match data
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Vivek Goyal <[email protected]>
  • Loading branch information
dhowells committed Sep 16, 2014
1 parent 53d91c5 commit 4629195
Show file tree
Hide file tree
Showing 11 changed files with 129 additions and 51 deletions.
31 changes: 30 additions & 1 deletion crypto/asymmetric_keys/asymmetric_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion include/keys/user-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 28 additions & 3 deletions include/linux/key-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
5 changes: 3 additions & 2 deletions net/dns_resolver/dns_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
8 changes: 3 additions & 5 deletions security/keys/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down
49 changes: 30 additions & 19 deletions security/keys/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
{
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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down
8 changes: 4 additions & 4 deletions security/keys/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 7 additions & 6 deletions security/keys/process_keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
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;
}

/*
Expand All @@ -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;
Expand Down Expand Up @@ -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.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);
Expand Down
21 changes: 16 additions & 5 deletions security/keys/request_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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) {
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions security/keys/request_key_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions security/keys/user_defined.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 4629195

Please sign in to comment.