Commit df593ee2 authored by David Howells's avatar David Howells

keys: Hoist locking out of __key_link_begin()

Hoist the locking of out of __key_link_begin() and into its callers.  This
is necessary to allow the upcoming key_move() operation to correctly order
taking of the source keyring semaphore, the destination keyring semaphore
and the keyring serialisation lock.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent eb0f68cb
...@@ -93,6 +93,8 @@ extern wait_queue_head_t request_key_conswq; ...@@ -93,6 +93,8 @@ extern wait_queue_head_t request_key_conswq;
extern struct key_type *key_type_lookup(const char *type); extern struct key_type *key_type_lookup(const char *type);
extern void key_type_put(struct key_type *ktype); extern void key_type_put(struct key_type *ktype);
extern int __key_link_lock(struct key *keyring,
const struct keyring_index_key *index_key);
extern int __key_link_begin(struct key *keyring, extern int __key_link_begin(struct key *keyring,
const struct keyring_index_key *index_key, const struct keyring_index_key *index_key,
struct assoc_array_edit **_edit); struct assoc_array_edit **_edit);
......
...@@ -500,7 +500,7 @@ int key_instantiate_and_link(struct key *key, ...@@ -500,7 +500,7 @@ int key_instantiate_and_link(struct key *key,
struct key *authkey) struct key *authkey)
{ {
struct key_preparsed_payload prep; struct key_preparsed_payload prep;
struct assoc_array_edit *edit; struct assoc_array_edit *edit = NULL;
int ret; int ret;
memset(&prep, 0, sizeof(prep)); memset(&prep, 0, sizeof(prep));
...@@ -515,10 +515,14 @@ int key_instantiate_and_link(struct key *key, ...@@ -515,10 +515,14 @@ int key_instantiate_and_link(struct key *key,
} }
if (keyring) { if (keyring) {
ret = __key_link_begin(keyring, &key->index_key, &edit); ret = __key_link_lock(keyring, &key->index_key);
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret < 0)
goto error_link_end;
if (keyring->restrict_link && keyring->restrict_link->check) { if (keyring->restrict_link && keyring->restrict_link->check) {
struct key_restriction *keyres = keyring->restrict_link; struct key_restriction *keyres = keyring->restrict_link;
...@@ -570,7 +574,7 @@ int key_reject_and_link(struct key *key, ...@@ -570,7 +574,7 @@ int key_reject_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct assoc_array_edit *edit; struct assoc_array_edit *edit = NULL;
int ret, awaken, link_ret = 0; int ret, awaken, link_ret = 0;
key_check(key); key_check(key);
...@@ -583,7 +587,12 @@ int key_reject_and_link(struct key *key, ...@@ -583,7 +587,12 @@ int key_reject_and_link(struct key *key,
if (keyring->restrict_link) if (keyring->restrict_link)
return -EPERM; return -EPERM;
link_ret = __key_link_begin(keyring, &key->index_key, &edit); link_ret = __key_link_lock(keyring, &key->index_key);
if (link_ret == 0) {
link_ret = __key_link_begin(keyring, &key->index_key, &edit);
if (link_ret < 0)
__key_link_end(keyring, &key->index_key, edit);
}
} }
mutex_lock(&key_construction_mutex); mutex_lock(&key_construction_mutex);
...@@ -810,7 +819,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -810,7 +819,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
.description = description, .description = description,
}; };
struct key_preparsed_payload prep; struct key_preparsed_payload prep;
struct assoc_array_edit *edit; struct assoc_array_edit *edit = NULL;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
key_ref_t key_ref; key_ref_t key_ref;
...@@ -860,12 +869,18 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -860,12 +869,18 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
} }
index_key.desc_len = strlen(index_key.description); index_key.desc_len = strlen(index_key.description);
ret = __key_link_begin(keyring, &index_key, &edit); ret = __key_link_lock(keyring, &index_key);
if (ret < 0) { if (ret < 0) {
key_ref = ERR_PTR(ret); key_ref = ERR_PTR(ret);
goto error_free_prep; goto error_free_prep;
} }
ret = __key_link_begin(keyring, &index_key, &edit);
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error_link_end;
}
if (restrict_link && restrict_link->check) { if (restrict_link && restrict_link->check) {
ret = restrict_link->check(keyring, index_key.type, ret = restrict_link->check(keyring, index_key.type,
&prep.payload, restrict_link->key); &prep.payload, restrict_link->key);
......
...@@ -1199,14 +1199,34 @@ static int keyring_detect_cycle(struct key *A, struct key *B) ...@@ -1199,14 +1199,34 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
return PTR_ERR(ctx.result) == -EAGAIN ? 0 : PTR_ERR(ctx.result); return PTR_ERR(ctx.result) == -EAGAIN ? 0 : PTR_ERR(ctx.result);
} }
/*
* Lock keyring for link.
*/
int __key_link_lock(struct key *keyring,
const struct keyring_index_key *index_key)
__acquires(&keyring->sem)
__acquires(&keyring_serialise_link_lock)
{
if (keyring->type != &key_type_keyring)
return -ENOTDIR;
down_write(&keyring->sem);
/* Serialise link/link calls to prevent parallel calls causing a cycle
* when linking two keyring in opposite orders.
*/
if (index_key->type == &key_type_keyring)
mutex_lock(&keyring_serialise_link_lock);
return 0;
}
/* /*
* Preallocate memory so that a key can be linked into to a keyring. * Preallocate memory so that a key can be linked into to a keyring.
*/ */
int __key_link_begin(struct key *keyring, int __key_link_begin(struct key *keyring,
const struct keyring_index_key *index_key, const struct keyring_index_key *index_key,
struct assoc_array_edit **_edit) struct assoc_array_edit **_edit)
__acquires(&keyring->sem)
__acquires(&keyring_serialise_link_lock)
{ {
struct assoc_array_edit *edit; struct assoc_array_edit *edit;
int ret; int ret;
...@@ -1215,20 +1235,13 @@ int __key_link_begin(struct key *keyring, ...@@ -1215,20 +1235,13 @@ int __key_link_begin(struct key *keyring,
keyring->serial, index_key->type->name, index_key->description); keyring->serial, index_key->type->name, index_key->description);
BUG_ON(index_key->desc_len == 0); BUG_ON(index_key->desc_len == 0);
BUG_ON(*_edit != NULL);
if (keyring->type != &key_type_keyring) *_edit = NULL;
return -ENOTDIR;
down_write(&keyring->sem);
ret = -EKEYREVOKED; ret = -EKEYREVOKED;
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
goto error_krsem; goto error;
/* serialise link/link calls to prevent parallel calls causing a cycle
* when linking two keyring in opposite orders */
if (index_key->type == &key_type_keyring)
mutex_lock(&keyring_serialise_link_lock);
/* Create an edit script that will insert/replace the key in the /* Create an edit script that will insert/replace the key in the
* keyring tree. * keyring tree.
...@@ -1239,7 +1252,7 @@ int __key_link_begin(struct key *keyring, ...@@ -1239,7 +1252,7 @@ int __key_link_begin(struct key *keyring,
NULL); NULL);
if (IS_ERR(edit)) { if (IS_ERR(edit)) {
ret = PTR_ERR(edit); ret = PTR_ERR(edit);
goto error_sem; goto error;
} }
/* If we're not replacing a link in-place then we're going to need some /* If we're not replacing a link in-place then we're going to need some
...@@ -1258,11 +1271,7 @@ int __key_link_begin(struct key *keyring, ...@@ -1258,11 +1271,7 @@ int __key_link_begin(struct key *keyring,
error_cancel: error_cancel:
assoc_array_cancel_edit(edit); assoc_array_cancel_edit(edit);
error_sem: error:
if (index_key->type == &key_type_keyring)
mutex_unlock(&keyring_serialise_link_lock);
error_krsem:
up_write(&keyring->sem);
kleave(" = %d", ret); kleave(" = %d", ret);
return ret; return ret;
} }
...@@ -1312,9 +1321,6 @@ void __key_link_end(struct key *keyring, ...@@ -1312,9 +1321,6 @@ void __key_link_end(struct key *keyring,
BUG_ON(index_key->type == NULL); BUG_ON(index_key->type == NULL);
kenter("%d,%s,", keyring->serial, index_key->type->name); kenter("%d,%s,", keyring->serial, index_key->type->name);
if (index_key->type == &key_type_keyring)
mutex_unlock(&keyring_serialise_link_lock);
if (edit) { if (edit) {
if (!edit->dead_leaf) { if (!edit->dead_leaf) {
key_payload_reserve(keyring, key_payload_reserve(keyring,
...@@ -1323,6 +1329,9 @@ void __key_link_end(struct key *keyring, ...@@ -1323,6 +1329,9 @@ void __key_link_end(struct key *keyring,
assoc_array_cancel_edit(edit); assoc_array_cancel_edit(edit);
} }
up_write(&keyring->sem); up_write(&keyring->sem);
if (index_key->type == &key_type_keyring)
mutex_unlock(&keyring_serialise_link_lock);
} }
/* /*
...@@ -1358,7 +1367,7 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key) ...@@ -1358,7 +1367,7 @@ static int __key_link_check_restriction(struct key *keyring, struct key *key)
*/ */
int key_link(struct key *keyring, struct key *key) int key_link(struct key *keyring, struct key *key)
{ {
struct assoc_array_edit *edit; struct assoc_array_edit *edit = NULL;
int ret; int ret;
kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage)); kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
...@@ -1366,17 +1375,24 @@ int key_link(struct key *keyring, struct key *key) ...@@ -1366,17 +1375,24 @@ int key_link(struct key *keyring, struct key *key)
key_check(keyring); key_check(keyring);
key_check(key); key_check(key);
ret = __key_link_lock(keyring, &key->index_key);
if (ret < 0)
goto error;
ret = __key_link_begin(keyring, &key->index_key, &edit); ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) { if (ret < 0)
kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage)); goto error_end;
ret = __key_link_check_restriction(keyring, key);
if (ret == 0) kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
ret = __key_link_check_live_key(keyring, key); ret = __key_link_check_restriction(keyring, key);
if (ret == 0) if (ret == 0)
__key_link(key, &edit); ret = __key_link_check_live_key(keyring, key);
__key_link_end(keyring, &key->index_key, edit); if (ret == 0)
} __key_link(key, &edit);
error_end:
__key_link_end(keyring, &key->index_key, edit);
error:
kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage)); kleave(" = %d {%d,%d}", ret, keyring->serial, refcount_read(&keyring->usage));
return ret; return ret;
} }
......
...@@ -343,7 +343,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -343,7 +343,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
struct key_user *user, struct key_user *user,
struct key **_key) struct key **_key)
{ {
struct assoc_array_edit *edit; struct assoc_array_edit *edit = NULL;
struct key *key; struct key *key;
key_perm_t perm; key_perm_t perm;
key_ref_t key_ref; key_ref_t key_ref;
...@@ -372,6 +372,9 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -372,6 +372,9 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
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_lock(dest_keyring, &ctx->index_key);
if (ret < 0)
goto link_lock_failed;
ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit); ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit);
if (ret < 0) if (ret < 0)
goto link_prealloc_failed; goto link_prealloc_failed;
...@@ -423,6 +426,8 @@ static int construct_alloc_key(struct keyring_search_context *ctx, ...@@ -423,6 +426,8 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
return ret; return ret;
link_prealloc_failed: link_prealloc_failed:
__key_link_end(dest_keyring, &ctx->index_key, edit);
link_lock_failed:
mutex_unlock(&user->cons_lock); mutex_unlock(&user->cons_lock);
key_put(key); key_put(key);
kleave(" = %d [prelink]", ret); kleave(" = %d [prelink]", ret);
......
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