Commit 4bdf0bc3 authored by David Howells's avatar David Howells

KEYS: Introduce a search context structure

Search functions pass around a bunch of arguments, each of which gets copied
with each call.  Introduce a search context structure to hold these.

Whilst we're at it, create a search flag that indicates whether the search
should be directly to the description or whether it should iterate through all
keys looking for a non-description match.

This will be useful when keyrings use a generic data struct with generic
routines to manage their content as the search terms can just be passed
through to the iterator callback function.

Also, for future use, the data to be supplied to the match function is
separated from the description pointer in the search context.  This makes it
clear which is being supplied.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 16feef43
...@@ -63,6 +63,11 @@ struct key_type { ...@@ -63,6 +63,11 @@ struct key_type {
*/ */
size_t def_datalen; size_t def_datalen;
/* 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 */ /* vet a description */
int (*vet_description)(const char *description); int (*vet_description)(const char *description);
......
...@@ -107,23 +107,31 @@ extern struct key *keyring_search_instkey(struct key *keyring, ...@@ -107,23 +107,31 @@ extern struct key *keyring_search_instkey(struct key *keyring,
typedef int (*key_match_func_t)(const struct key *, const void *); 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;
unsigned flags;
#define KEYRING_SEARCH_LOOKUP_TYPE 0x0001 /* [as type->def_lookup_type] */
#define KEYRING_SEARCH_NO_STATE_CHECK 0x0002 /* Skip state checks */
#define KEYRING_SEARCH_DO_STATE_CHECK 0x0004 /* Override NO_STATE_CHECK */
#define KEYRING_SEARCH_NO_UPDATE_TIME 0x0008 /* Don't update times */
#define KEYRING_SEARCH_NO_CHECK_PERM 0x0010 /* Don't check permissions */
#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0020 /* Give an error on excessive depth */
/* Internal stuff */
int skipped_ret;
bool possessed;
key_ref_t result;
struct timespec now;
};
extern key_ref_t keyring_search_aux(key_ref_t keyring_ref, extern key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred, struct keyring_search_context *ctx);
struct key_type *type,
const void *description, extern key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx);
key_match_func_t match, extern key_ref_t search_process_keyrings(struct keyring_search_context *ctx);
bool no_state_check);
extern key_ref_t search_my_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred);
extern key_ref_t search_process_keyrings(struct key_type *type,
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred);
extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check); extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
......
...@@ -280,11 +280,7 @@ EXPORT_SYMBOL(keyring_alloc); ...@@ -280,11 +280,7 @@ EXPORT_SYMBOL(keyring_alloc);
/** /**
* keyring_search_aux - Search a keyring tree for a key matching some criteria * keyring_search_aux - Search a keyring tree for a key matching some criteria
* @keyring_ref: A pointer to the keyring with possession indicator. * @keyring_ref: A pointer to the keyring with possession indicator.
* @cred: The credentials to use for permissions checks. * @ctx: The keyring search context.
* @type: The type of key to search for.
* @description: Parameter for @match.
* @match: Function to rule on whether or not a key is the one required.
* @no_state_check: Don't check if a matching key is bad
* *
* Search the supplied keyring tree for a key that matches the criteria given. * Search the supplied keyring tree for a key that matches the criteria given.
* The root keyring and any linked keyrings must grant Search permission to the * The root keyring and any linked keyrings must grant Search permission to the
...@@ -314,11 +310,7 @@ EXPORT_SYMBOL(keyring_alloc); ...@@ -314,11 +310,7 @@ EXPORT_SYMBOL(keyring_alloc);
* @keyring_ref is propagated to the returned key reference. * @keyring_ref is propagated to the returned key reference.
*/ */
key_ref_t keyring_search_aux(key_ref_t keyring_ref, key_ref_t keyring_search_aux(key_ref_t keyring_ref,
const struct cred *cred, struct keyring_search_context *ctx)
struct key_type *type,
const void *description,
key_match_func_t match,
bool no_state_check)
{ {
struct { struct {
/* Need a separate keylist pointer for RCU purposes */ /* Need a separate keylist pointer for RCU purposes */
...@@ -328,20 +320,18 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -328,20 +320,18 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
} stack[KEYRING_SEARCH_MAX_DEPTH]; } stack[KEYRING_SEARCH_MAX_DEPTH];
struct keyring_list *keylist; struct keyring_list *keylist;
struct timespec now;
unsigned long kflags; unsigned long kflags;
struct key *keyring, *key; struct key *keyring, *key;
key_ref_t key_ref; key_ref_t key_ref;
bool possessed;
long err; long err;
int sp, nkeys, kix; int sp, nkeys, kix;
keyring = key_ref_to_ptr(keyring_ref); keyring = key_ref_to_ptr(keyring_ref);
possessed = is_key_possessed(keyring_ref); ctx->possessed = is_key_possessed(keyring_ref);
key_check(keyring); key_check(keyring);
/* top keyring must have search permission to begin the search */ /* top keyring must have search permission to begin the search */
err = key_task_permission(keyring_ref, cred, KEY_SEARCH); err = key_task_permission(keyring_ref, ctx->cred, KEY_SEARCH);
if (err < 0) { if (err < 0) {
key_ref = ERR_PTR(err); key_ref = ERR_PTR(err);
goto error; goto error;
...@@ -353,7 +343,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -353,7 +343,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
rcu_read_lock(); rcu_read_lock();
now = current_kernel_time(); ctx->now = current_kernel_time();
err = -EAGAIN; err = -EAGAIN;
sp = 0; sp = 0;
...@@ -361,16 +351,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -361,16 +351,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
* are looking for */ * are looking for */
key_ref = ERR_PTR(-EAGAIN); key_ref = ERR_PTR(-EAGAIN);
kflags = keyring->flags; kflags = keyring->flags;
if (keyring->type == type && match(keyring, description)) { if (keyring->type == ctx->index_key.type &&
ctx->match(keyring, ctx->match_data)) {
key = keyring; key = keyring;
if (no_state_check) if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)
goto found; goto found;
/* check it isn't negative and hasn't expired or been /* check it isn't negative and hasn't expired or been
* revoked */ * revoked */
if (kflags & (1 << KEY_FLAG_REVOKED)) if (kflags & (1 << KEY_FLAG_REVOKED))
goto error_2; goto error_2;
if (key->expiry && now.tv_sec >= key->expiry) if (key->expiry && ctx->now.tv_sec >= key->expiry)
goto error_2; goto error_2;
key_ref = ERR_PTR(key->type_data.reject_error); key_ref = ERR_PTR(key->type_data.reject_error);
if (kflags & (1 << KEY_FLAG_NEGATIVE)) if (kflags & (1 << KEY_FLAG_NEGATIVE))
...@@ -384,7 +375,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -384,7 +375,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
if (kflags & ((1 << KEY_FLAG_INVALIDATED) | if (kflags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_REVOKED) |
(1 << KEY_FLAG_NEGATIVE)) || (1 << KEY_FLAG_NEGATIVE)) ||
(keyring->expiry && now.tv_sec >= keyring->expiry)) (keyring->expiry && ctx->now.tv_sec >= keyring->expiry))
goto error_2; goto error_2;
/* start processing a new keyring */ /* start processing a new keyring */
...@@ -406,29 +397,29 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -406,29 +397,29 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
kflags = key->flags; kflags = key->flags;
/* ignore keys not of this type */ /* ignore keys not of this type */
if (key->type != type) if (key->type != ctx->index_key.type)
continue; continue;
/* skip invalidated, revoked and expired keys */ /* skip invalidated, revoked and expired keys */
if (!no_state_check) { if (!(ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)) {
if (kflags & ((1 << KEY_FLAG_INVALIDATED) | if (kflags & ((1 << KEY_FLAG_INVALIDATED) |
(1 << KEY_FLAG_REVOKED))) (1 << KEY_FLAG_REVOKED)))
continue; continue;
if (key->expiry && now.tv_sec >= key->expiry) if (key->expiry && ctx->now.tv_sec >= key->expiry)
continue; continue;
} }
/* keys that don't match */ /* keys that don't match */
if (!match(key, description)) if (!ctx->match(key, ctx->match_data))
continue; continue;
/* key must have search permissions */ /* key must have search permissions */
if (key_task_permission(make_key_ref(key, possessed), if (key_task_permission(make_key_ref(key, ctx->possessed),
cred, KEY_SEARCH) < 0) ctx->cred, KEY_SEARCH) < 0)
continue; continue;
if (no_state_check) if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)
goto found; goto found;
/* we set a different error code if we pass a negative key */ /* we set a different error code if we pass a negative key */
...@@ -456,8 +447,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -456,8 +447,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
if (sp >= KEYRING_SEARCH_MAX_DEPTH) if (sp >= KEYRING_SEARCH_MAX_DEPTH)
continue; continue;
if (key_task_permission(make_key_ref(key, possessed), if (key_task_permission(make_key_ref(key, ctx->possessed),
cred, KEY_SEARCH) < 0) ctx->cred, KEY_SEARCH) < 0)
continue; continue;
/* stack the current position */ /* stack the current position */
...@@ -489,12 +480,12 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, ...@@ -489,12 +480,12 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref,
/* we found a viable match */ /* we found a viable match */
found: found:
atomic_inc(&key->usage); atomic_inc(&key->usage);
key->last_used_at = now.tv_sec; key->last_used_at = ctx->now.tv_sec;
keyring->last_used_at = now.tv_sec; keyring->last_used_at = ctx->now.tv_sec;
while (sp > 0) while (sp > 0)
stack[--sp].keyring->last_used_at = now.tv_sec; stack[--sp].keyring->last_used_at = ctx->now.tv_sec;
key_check(key); key_check(key);
key_ref = make_key_ref(key, possessed); key_ref = make_key_ref(key, ctx->possessed);
error_2: error_2:
rcu_read_unlock(); rcu_read_unlock();
error: error:
...@@ -514,11 +505,20 @@ key_ref_t keyring_search(key_ref_t keyring, ...@@ -514,11 +505,20 @@ key_ref_t keyring_search(key_ref_t keyring,
struct key_type *type, struct key_type *type,
const char *description) const char *description)
{ {
if (!type->match) struct keyring_search_context ctx = {
.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),
};
if (!ctx.match)
return ERR_PTR(-ENOKEY); return ERR_PTR(-ENOKEY);
return keyring_search_aux(keyring, current->cred, return keyring_search_aux(keyring, &ctx);
type, description, type->match, false);
} }
EXPORT_SYMBOL(keyring_search); EXPORT_SYMBOL(keyring_search);
......
...@@ -182,7 +182,6 @@ static void proc_keys_stop(struct seq_file *p, void *v) ...@@ -182,7 +182,6 @@ static void proc_keys_stop(struct seq_file *p, void *v)
static int proc_keys_show(struct seq_file *m, void *v) static int proc_keys_show(struct seq_file *m, void *v)
{ {
const struct cred *cred = current_cred();
struct rb_node *_p = v; struct rb_node *_p = v;
struct key *key = rb_entry(_p, struct key, serial_node); struct key *key = rb_entry(_p, struct key, serial_node);
struct timespec now; struct timespec now;
...@@ -191,15 +190,23 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -191,15 +190,23 @@ static int proc_keys_show(struct seq_file *m, void *v)
char xbuf[12]; char xbuf[12];
int rc; int rc;
struct keyring_search_context ctx = {
.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),
};
key_ref = make_key_ref(key, 0); key_ref = make_key_ref(key, 0);
/* determine if the key is possessed by this process (a test we can /* determine if the key is possessed by this process (a test we can
* skip if the key does not indicate the possessor can view it * skip if the key does not indicate the possessor can view it
*/ */
if (key->perm & KEY_POS_VIEW) { if (key->perm & KEY_POS_VIEW) {
skey_ref = search_my_process_keyrings(key->type, key, skey_ref = search_my_process_keyrings(&ctx);
lookup_user_key_possessed,
true, cred);
if (!IS_ERR(skey_ref)) { if (!IS_ERR(skey_ref)) {
key_ref_put(skey_ref); key_ref_put(skey_ref);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
...@@ -211,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v) ...@@ -211,7 +218,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
* - the caller holds a spinlock, and thus the RCU read lock, making our * - the caller holds a spinlock, and thus the RCU read lock, making our
* access to __current_cred() safe * access to __current_cred() safe
*/ */
rc = key_task_permission(key_ref, cred, KEY_VIEW); rc = key_task_permission(key_ref, ctx.cred, KEY_VIEW);
if (rc < 0) if (rc < 0)
return 0; return 0;
......
...@@ -319,11 +319,7 @@ void key_fsgid_changed(struct task_struct *tsk) ...@@ -319,11 +319,7 @@ void key_fsgid_changed(struct task_struct *tsk)
* In the case of a successful return, the possession attribute is set on the * In the case of a successful return, the possession attribute is set on the
* returned key reference. * returned key reference.
*/ */
key_ref_t search_my_process_keyrings(struct key_type *type, key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred)
{ {
key_ref_t key_ref, ret, err; key_ref_t key_ref, ret, err;
...@@ -339,10 +335,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -339,10 +335,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
err = ERR_PTR(-EAGAIN); err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */ /* search the thread keyring first */
if (cred->thread_keyring) { if (ctx->cred->thread_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->thread_keyring, 1), make_key_ref(ctx->cred->thread_keyring, 1), ctx);
cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
...@@ -358,10 +353,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -358,10 +353,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
} }
/* search the process keyring second */ /* search the process keyring second */
if (cred->process_keyring) { if (ctx->cred->process_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->process_keyring, 1), make_key_ref(ctx->cred->process_keyring, 1), ctx);
cred, type, description, match, no_state_check);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
...@@ -379,11 +373,11 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -379,11 +373,11 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
} }
/* search the session keyring */ /* search the session keyring */
if (cred->session_keyring) { if (ctx->cred->session_keyring) {
rcu_read_lock(); rcu_read_lock();
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(rcu_dereference(cred->session_keyring), 1), make_key_ref(rcu_dereference(ctx->cred->session_keyring), 1),
cred, type, description, match, no_state_check); ctx);
rcu_read_unlock(); rcu_read_unlock();
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
...@@ -402,10 +396,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -402,10 +396,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
} }
} }
/* or search the user-session keyring */ /* or search the user-session keyring */
else if (cred->user->session_keyring) { else if (ctx->cred->user->session_keyring) {
key_ref = keyring_search_aux( key_ref = keyring_search_aux(
make_key_ref(cred->user->session_keyring, 1), make_key_ref(ctx->cred->user->session_keyring, 1),
cred, type, description, match, no_state_check); ctx);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
...@@ -437,19 +431,14 @@ key_ref_t search_my_process_keyrings(struct key_type *type, ...@@ -437,19 +431,14 @@ key_ref_t search_my_process_keyrings(struct key_type *type,
* *
* Return same as search_my_process_keyrings(). * Return same as search_my_process_keyrings().
*/ */
key_ref_t search_process_keyrings(struct key_type *type, key_ref_t search_process_keyrings(struct keyring_search_context *ctx)
const void *description,
key_match_func_t match,
bool no_state_check,
const struct cred *cred)
{ {
struct request_key_auth *rka; struct request_key_auth *rka;
key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; key_ref_t key_ref, ret = ERR_PTR(-EACCES), err;
might_sleep(); might_sleep();
key_ref = search_my_process_keyrings(type, description, match, key_ref = search_my_process_keyrings(ctx);
no_state_check, cred);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto found; goto found;
err = key_ref; err = key_ref;
...@@ -458,19 +447,21 @@ key_ref_t search_process_keyrings(struct key_type *type, ...@@ -458,19 +447,21 @@ key_ref_t search_process_keyrings(struct key_type *type,
* search the keyrings of the process mentioned there * search the keyrings of the process mentioned there
* - we don't permit access to request_key auth keys via this method * - we don't permit access to request_key auth keys via this method
*/ */
if (cred->request_key_auth && if (ctx->cred->request_key_auth &&
cred == current_cred() && ctx->cred == current_cred() &&
type != &key_type_request_key_auth ctx->index_key.type != &key_type_request_key_auth
) { ) {
const struct cred *cred = ctx->cred;
/* defend against the auth key being revoked */ /* defend against the auth key being revoked */
down_read(&cred->request_key_auth->sem); down_read(&cred->request_key_auth->sem);
if (key_validate(cred->request_key_auth) == 0) { if (key_validate(ctx->cred->request_key_auth) == 0) {
rka = cred->request_key_auth->payload.data; rka = ctx->cred->request_key_auth->payload.data;
key_ref = search_process_keyrings(type, description, ctx->cred = rka->cred;
match, no_state_check, key_ref = search_process_keyrings(ctx);
rka->cred); ctx->cred = cred;
up_read(&cred->request_key_auth->sem); up_read(&cred->request_key_auth->sem);
...@@ -524,19 +515,23 @@ int lookup_user_key_possessed(const struct key *key, const void *target) ...@@ -524,19 +515,23 @@ int lookup_user_key_possessed(const struct key *key, const void *target)
key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, 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 = {
.match = lookup_user_key_possessed,
.flags = (KEYRING_SEARCH_NO_STATE_CHECK |
KEYRING_SEARCH_LOOKUP_DIRECT),
};
struct request_key_auth *rka; struct request_key_auth *rka;
const struct cred *cred;
struct key *key; struct key *key;
key_ref_t key_ref, skey_ref; key_ref_t key_ref, skey_ref;
int ret; int ret;
try_again: try_again:
cred = get_current_cred(); ctx.cred = get_current_cred();
key_ref = ERR_PTR(-ENOKEY); key_ref = ERR_PTR(-ENOKEY);
switch (id) { switch (id) {
case KEY_SPEC_THREAD_KEYRING: case KEY_SPEC_THREAD_KEYRING:
if (!cred->thread_keyring) { if (!ctx.cred->thread_keyring) {
if (!(lflags & KEY_LOOKUP_CREATE)) if (!(lflags & KEY_LOOKUP_CREATE))
goto error; goto error;
...@@ -548,13 +543,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -548,13 +543,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
goto reget_creds; goto reget_creds;
} }
key = cred->thread_keyring; key = ctx.cred->thread_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_PROCESS_KEYRING: case KEY_SPEC_PROCESS_KEYRING:
if (!cred->process_keyring) { if (!ctx.cred->process_keyring) {
if (!(lflags & KEY_LOOKUP_CREATE)) if (!(lflags & KEY_LOOKUP_CREATE))
goto error; goto error;
...@@ -566,13 +561,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -566,13 +561,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
goto reget_creds; goto reget_creds;
} }
key = cred->process_keyring; key = ctx.cred->process_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_SESSION_KEYRING: case KEY_SPEC_SESSION_KEYRING:
if (!cred->session_keyring) { if (!ctx.cred->session_keyring) {
/* always install a session keyring upon access if one /* always install a session keyring upon access if one
* doesn't exist yet */ * doesn't exist yet */
ret = install_user_keyrings(); ret = install_user_keyrings();
...@@ -582,13 +577,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -582,13 +577,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
ret = join_session_keyring(NULL); ret = join_session_keyring(NULL);
else else
ret = install_session_keyring( ret = install_session_keyring(
cred->user->session_keyring); ctx.cred->user->session_keyring);
if (ret < 0) if (ret < 0)
goto error; goto error;
goto reget_creds; goto reget_creds;
} else if (cred->session_keyring == } else if (ctx.cred->session_keyring ==
cred->user->session_keyring && ctx.cred->user->session_keyring &&
lflags & KEY_LOOKUP_CREATE) { lflags & KEY_LOOKUP_CREATE) {
ret = join_session_keyring(NULL); ret = join_session_keyring(NULL);
if (ret < 0) if (ret < 0)
...@@ -597,32 +592,32 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -597,32 +592,32 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
} }
rcu_read_lock(); rcu_read_lock();
key = rcu_dereference(cred->session_keyring); key = rcu_dereference(ctx.cred->session_keyring);
atomic_inc(&key->usage); atomic_inc(&key->usage);
rcu_read_unlock(); rcu_read_unlock();
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_USER_KEYRING: case KEY_SPEC_USER_KEYRING:
if (!cred->user->uid_keyring) { if (!ctx.cred->user->uid_keyring) {
ret = install_user_keyrings(); ret = install_user_keyrings();
if (ret < 0) if (ret < 0)
goto error; goto error;
} }
key = cred->user->uid_keyring; key = ctx.cred->user->uid_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
case KEY_SPEC_USER_SESSION_KEYRING: case KEY_SPEC_USER_SESSION_KEYRING:
if (!cred->user->session_keyring) { if (!ctx.cred->user->session_keyring) {
ret = install_user_keyrings(); ret = install_user_keyrings();
if (ret < 0) if (ret < 0)
goto error; goto error;
} }
key = cred->user->session_keyring; key = ctx.cred->user->session_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
break; break;
...@@ -633,7 +628,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -633,7 +628,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
goto error; goto error;
case KEY_SPEC_REQKEY_AUTH_KEY: case KEY_SPEC_REQKEY_AUTH_KEY:
key = cred->request_key_auth; key = ctx.cred->request_key_auth;
if (!key) if (!key)
goto error; goto error;
...@@ -642,20 +637,20 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -642,20 +637,20 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
break; break;
case KEY_SPEC_REQUESTOR_KEYRING: case KEY_SPEC_REQUESTOR_KEYRING:
if (!cred->request_key_auth) if (!ctx.cred->request_key_auth)
goto error; goto error;
down_read(&cred->request_key_auth->sem); down_read(&ctx.cred->request_key_auth->sem);
if (test_bit(KEY_FLAG_REVOKED, if (test_bit(KEY_FLAG_REVOKED,
&cred->request_key_auth->flags)) { &ctx.cred->request_key_auth->flags)) {
key_ref = ERR_PTR(-EKEYREVOKED); key_ref = ERR_PTR(-EKEYREVOKED);
key = NULL; key = NULL;
} else { } else {
rka = cred->request_key_auth->payload.data; rka = ctx.cred->request_key_auth->payload.data;
key = rka->dest_keyring; key = rka->dest_keyring;
atomic_inc(&key->usage); atomic_inc(&key->usage);
} }
up_read(&cred->request_key_auth->sem); up_read(&ctx.cred->request_key_auth->sem);
if (!key) if (!key)
goto error; goto error;
key_ref = make_key_ref(key, 1); key_ref = make_key_ref(key, 1);
...@@ -675,9 +670,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -675,9 +670,13 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
key_ref = make_key_ref(key, 0); key_ref = make_key_ref(key, 0);
/* check to see if we possess the key */ /* check to see if we possess the key */
skey_ref = search_process_keyrings(key->type, key, ctx.index_key.type = key->type;
lookup_user_key_possessed, ctx.index_key.description = key->description;
true, cred); ctx.index_key.desc_len = strlen(key->description);
ctx.match_data = key;
kdebug("check possessed");
skey_ref = search_process_keyrings(&ctx);
kdebug("possessed=%p", skey_ref);
if (!IS_ERR(skey_ref)) { if (!IS_ERR(skey_ref)) {
key_put(key); key_put(key);
...@@ -717,14 +716,14 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -717,14 +716,14 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
goto invalid_key; goto invalid_key;
/* check the permissions */ /* check the permissions */
ret = key_task_permission(key_ref, cred, perm); ret = key_task_permission(key_ref, ctx.cred, perm);
if (ret < 0) if (ret < 0)
goto invalid_key; goto invalid_key;
key->last_used_at = current_kernel_time().tv_sec; key->last_used_at = current_kernel_time().tv_sec;
error: error:
put_cred(cred); put_cred(ctx.cred);
return key_ref; return key_ref;
invalid_key: invalid_key:
...@@ -735,7 +734,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, ...@@ -735,7 +734,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags,
/* if we attempted to install a keyring, then it may have caused new /* if we attempted to install a keyring, then it may have caused new
* creds to be installed */ * creds to be installed */
reget_creds: reget_creds:
put_cred(cred); put_cred(ctx.cred);
goto try_again; goto try_again;
} }
......
...@@ -345,38 +345,34 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) ...@@ -345,38 +345,34 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
* May return a key that's already under construction instead if there was a * May return a key that's already under construction instead if there was a
* race between two thread calling request_key(). * race between two thread calling request_key().
*/ */
static int construct_alloc_key(struct key_type *type, static int construct_alloc_key(struct keyring_search_context *ctx,
const char *description,
struct key *dest_keyring, struct key *dest_keyring,
unsigned long flags, unsigned long flags,
struct key_user *user, struct key_user *user,
struct key **_key) struct key **_key)
{ {
const struct keyring_index_key index_key = {
.type = type,
.description = description,
.desc_len = strlen(description),
};
const struct cred *cred = current_cred();
unsigned long prealloc; unsigned long prealloc;
struct key *key; struct key *key;
key_perm_t perm; key_perm_t perm;
key_ref_t key_ref; key_ref_t key_ref;
int ret; int ret;
kenter("%s,%s,,,", type->name, description); kenter("%s,%s,,,",
ctx->index_key.type->name, ctx->index_key.description);
*_key = NULL; *_key = NULL;
mutex_lock(&user->cons_lock); mutex_lock(&user->cons_lock);
perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
perm |= KEY_USR_VIEW; perm |= KEY_USR_VIEW;
if (type->read) if (ctx->index_key.type->read)
perm |= KEY_POS_READ; perm |= KEY_POS_READ;
if (type == &key_type_keyring || type->update) if (ctx->index_key.type == &key_type_keyring ||
ctx->index_key.type->update)
perm |= KEY_POS_WRITE; perm |= KEY_POS_WRITE;
key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, key = key_alloc(ctx->index_key.type, ctx->index_key.description,
ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
perm, flags); perm, flags);
if (IS_ERR(key)) if (IS_ERR(key))
goto alloc_failed; goto alloc_failed;
...@@ -384,7 +380,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -384,7 +380,7 @@ static int construct_alloc_key(struct key_type *type,
set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
if (dest_keyring) { if (dest_keyring) {
ret = __key_link_begin(dest_keyring, &index_key, &prealloc); ret = __key_link_begin(dest_keyring, &ctx->index_key, &prealloc);
if (ret < 0) if (ret < 0)
goto link_prealloc_failed; goto link_prealloc_failed;
} }
...@@ -394,8 +390,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -394,8 +390,7 @@ static int construct_alloc_key(struct key_type *type,
* waited for locks */ * waited for locks */
mutex_lock(&key_construction_mutex); mutex_lock(&key_construction_mutex);
key_ref = search_process_keyrings(type, description, type->match, key_ref = search_process_keyrings(ctx);
false, cred);
if (!IS_ERR(key_ref)) if (!IS_ERR(key_ref))
goto key_already_present; goto key_already_present;
...@@ -404,7 +399,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -404,7 +399,7 @@ static int construct_alloc_key(struct key_type *type,
mutex_unlock(&key_construction_mutex); mutex_unlock(&key_construction_mutex);
if (dest_keyring) if (dest_keyring)
__key_link_end(dest_keyring, &index_key, prealloc); __key_link_end(dest_keyring, &ctx->index_key, prealloc);
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
*_key = key; *_key = key;
kleave(" = 0 [%d]", key_serial(key)); kleave(" = 0 [%d]", key_serial(key));
...@@ -420,7 +415,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -420,7 +415,7 @@ static int construct_alloc_key(struct key_type *type,
ret = __key_link_check_live_key(dest_keyring, key); ret = __key_link_check_live_key(dest_keyring, key);
if (ret == 0) if (ret == 0)
__key_link(dest_keyring, key, &prealloc); __key_link(dest_keyring, key, &prealloc);
__key_link_end(dest_keyring, &index_key, prealloc); __key_link_end(dest_keyring, &ctx->index_key, prealloc);
if (ret < 0) if (ret < 0)
goto link_check_failed; goto link_check_failed;
} }
...@@ -449,8 +444,7 @@ static int construct_alloc_key(struct key_type *type, ...@@ -449,8 +444,7 @@ static int construct_alloc_key(struct key_type *type,
/* /*
* Commence key construction. * Commence key construction.
*/ */
static struct key *construct_key_and_link(struct key_type *type, static struct key *construct_key_and_link(struct keyring_search_context *ctx,
const char *description,
const char *callout_info, const char *callout_info,
size_t callout_len, size_t callout_len,
void *aux, void *aux,
...@@ -469,8 +463,7 @@ static struct key *construct_key_and_link(struct key_type *type, ...@@ -469,8 +463,7 @@ static struct key *construct_key_and_link(struct key_type *type,
construct_get_dest_keyring(&dest_keyring); construct_get_dest_keyring(&dest_keyring);
ret = construct_alloc_key(type, description, dest_keyring, flags, user, ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key);
&key);
key_user_put(user); key_user_put(user);
if (ret == 0) { if (ret == 0) {
...@@ -534,18 +527,24 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -534,18 +527,24 @@ struct key *request_key_and_link(struct key_type *type,
struct key *dest_keyring, struct key *dest_keyring,
unsigned long flags) unsigned long flags)
{ {
const struct cred *cred = current_cred(); struct keyring_search_context ctx = {
.index_key.type = type,
.index_key.description = description,
.cred = current_cred(),
.match = type->match,
.match_data = description,
.flags = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
int ret; int ret;
kenter("%s,%s,%p,%zu,%p,%p,%lx", kenter("%s,%s,%p,%zu,%p,%p,%lx",
type->name, description, callout_info, callout_len, aux, ctx.index_key.type->name, ctx.index_key.description,
dest_keyring, flags); callout_info, callout_len, aux, dest_keyring, flags);
/* search all the process keyrings for a key */ /* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match, key_ref = search_process_keyrings(&ctx);
false, cred);
if (!IS_ERR(key_ref)) { if (!IS_ERR(key_ref)) {
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
...@@ -568,9 +567,8 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -568,9 +567,8 @@ struct key *request_key_and_link(struct key_type *type,
if (!callout_info) if (!callout_info)
goto error; goto error;
key = construct_key_and_link(type, description, callout_info, key = construct_key_and_link(&ctx, callout_info, callout_len,
callout_len, aux, dest_keyring, aux, dest_keyring, flags);
flags);
} }
error: error:
......
...@@ -239,15 +239,17 @@ static int key_get_instantiation_authkey_match(const struct key *key, ...@@ -239,15 +239,17 @@ static int key_get_instantiation_authkey_match(const struct key *key,
*/ */
struct key *key_get_instantiation_authkey(key_serial_t target_id) struct key *key_get_instantiation_authkey(key_serial_t target_id)
{ {
const struct cred *cred = current_cred(); struct keyring_search_context ctx = {
.index_key.type = &key_type_request_key_auth,
.cred = current_cred(),
.match = key_get_instantiation_authkey_match,
.match_data = (void *)(unsigned long)target_id,
.flags = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *authkey; struct key *authkey;
key_ref_t authkey_ref; key_ref_t authkey_ref;
authkey_ref = search_process_keyrings( authkey_ref = search_process_keyrings(&ctx);
&key_type_request_key_auth,
(void *) (unsigned long) target_id,
key_get_instantiation_authkey_match,
false, cred);
if (IS_ERR(authkey_ref)) { if (IS_ERR(authkey_ref)) {
authkey = ERR_CAST(authkey_ref); authkey = ERR_CAST(authkey_ref);
......
...@@ -25,14 +25,15 @@ static int logon_vet_description(const char *desc); ...@@ -25,14 +25,15 @@ static int logon_vet_description(const char *desc);
* arbitrary blob of data as the payload * arbitrary blob of data as the payload
*/ */
struct key_type key_type_user = { struct key_type key_type_user = {
.name = "user", .name = "user",
.instantiate = user_instantiate, .def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.update = user_update, .instantiate = user_instantiate,
.match = user_match, .update = user_update,
.revoke = user_revoke, .match = user_match,
.destroy = user_destroy, .revoke = user_revoke,
.describe = user_describe, .destroy = user_destroy,
.read = user_read, .describe = user_describe,
.read = user_read,
}; };
EXPORT_SYMBOL_GPL(key_type_user); EXPORT_SYMBOL_GPL(key_type_user);
...@@ -45,6 +46,7 @@ EXPORT_SYMBOL_GPL(key_type_user); ...@@ -45,6 +46,7 @@ EXPORT_SYMBOL_GPL(key_type_user);
*/ */
struct key_type key_type_logon = { struct key_type key_type_logon = {
.name = "logon", .name = "logon",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.instantiate = user_instantiate, .instantiate = user_instantiate,
.update = user_update, .update = user_update,
.match = user_match, .match = 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