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: David Howells <dhowells@redhat.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int __key_link_begin(struct key *keyring,
|
||||
const struct keyring_index_key *index_key,
|
||||
struct assoc_array_edit **_edit)
|
||||
__acquires(&keyring->sem)
|
||||
__acquires(&keyring_serialise_link_lock)
|
||||
{
|
||||
struct assoc_array_edit *edit;
|
||||
int ret;
|
||||
@@ -1215,20 +1235,13 @@ int __key_link_begin(struct key *keyring,
|
||||
keyring->serial, index_key->type->name, index_key->description);
|
||||
|
||||
BUG_ON(index_key->desc_len == 0);
|
||||
BUG_ON(*_edit != NULL);
|
||||
|
||||
if (keyring->type != &key_type_keyring)
|
||||
return -ENOTDIR;
|
||||
|
||||
down_write(&keyring->sem);
|
||||
*_edit = NULL;
|
||||
|
||||
ret = -EKEYREVOKED;
|
||||
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
|
||||
goto error_krsem;
|
||||
|
||||
/* 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);
|
||||
goto error;
|
||||
|
||||
/* Create an edit script that will insert/replace the key in the
|
||||
* keyring tree.
|
||||
@@ -1239,7 +1252,7 @@ int __key_link_begin(struct key *keyring,
|
||||
NULL);
|
||||
if (IS_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
|
||||
@@ -1258,11 +1271,7 @@ int __key_link_begin(struct key *keyring,
|
||||
|
||||
error_cancel:
|
||||
assoc_array_cancel_edit(edit);
|
||||
error_sem:
|
||||
if (index_key->type == &key_type_keyring)
|
||||
mutex_unlock(&keyring_serialise_link_lock);
|
||||
error_krsem:
|
||||
up_write(&keyring->sem);
|
||||
error:
|
||||
kleave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -1312,9 +1321,6 @@ void __key_link_end(struct key *keyring,
|
||||
BUG_ON(index_key->type == NULL);
|
||||
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->dead_leaf) {
|
||||
key_payload_reserve(keyring,
|
||||
@@ -1323,6 +1329,9 @@ void __key_link_end(struct key *keyring,
|
||||
assoc_array_cancel_edit(edit);
|
||||
}
|
||||
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)
|
||||
*/
|
||||
int key_link(struct key *keyring, struct key *key)
|
||||
{
|
||||
struct assoc_array_edit *edit;
|
||||
struct assoc_array_edit *edit = NULL;
|
||||
int ret;
|
||||
|
||||
kenter("{%d,%d}", keyring->serial, refcount_read(&keyring->usage));
|
||||
@@ -1366,17 +1375,24 @@ int key_link(struct key *keyring, struct key *key)
|
||||
key_check(keyring);
|
||||
key_check(key);
|
||||
|
||||
ret = __key_link_begin(keyring, &key->index_key, &edit);
|
||||
if (ret == 0) {
|
||||
kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
|
||||
ret = __key_link_check_restriction(keyring, key);
|
||||
if (ret == 0)
|
||||
ret = __key_link_check_live_key(keyring, key);
|
||||
if (ret == 0)
|
||||
__key_link(key, &edit);
|
||||
__key_link_end(keyring, &key->index_key, edit);
|
||||
}
|
||||
ret = __key_link_lock(keyring, &key->index_key);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = __key_link_begin(keyring, &key->index_key, &edit);
|
||||
if (ret < 0)
|
||||
goto error_end;
|
||||
|
||||
kdebug("begun {%d,%d}", keyring->serial, refcount_read(&keyring->usage));
|
||||
ret = __key_link_check_restriction(keyring, key);
|
||||
if (ret == 0)
|
||||
ret = __key_link_check_live_key(keyring, key);
|
||||
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));
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user