diff options
author | David Howells <dhowells@redhat.com> | 2010-04-30 14:32:39 +0100 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-05-06 22:25:02 +1000 |
commit | f70e2e06196ad4c1c762037da2f75354f6c16b81 (patch) | |
tree | 9632a1e655efb684c87f8c7be6d091fbb1a430e7 /security/keys/request_key.c | |
parent | 043b4d40f53131c5f72eca2a46555fe35328a930 (diff) |
KEYS: Do preallocation for __key_link()
Do preallocation for __key_link() so that the various callers in request_key.c
can deal with any errors from this source before attempting to construct a key.
This allows them to assume that the actual linkage step is guaranteed to be
successful.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r-- | security/keys/request_key.c | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index ac49c8aacbf0..f656e9c069e3 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -299,6 +299,7 @@ static int construct_alloc_key(struct key_type *type, struct key_user *user, struct key **_key) { + struct keyring_list *prealloc; const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; @@ -306,6 +307,7 @@ static int construct_alloc_key(struct key_type *type, kenter("%s,%s,,,", type->name, description); + *_key = NULL; mutex_lock(&user->cons_lock); key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, @@ -315,8 +317,12 @@ static int construct_alloc_key(struct key_type *type, set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); - if (dest_keyring) - down_write(&dest_keyring->sem); + if (dest_keyring) { + ret = __key_link_begin(dest_keyring, type, description, + &prealloc); + if (ret < 0) + goto link_prealloc_failed; + } /* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we @@ -328,11 +334,11 @@ static int construct_alloc_key(struct key_type *type, goto key_already_present; if (dest_keyring) - __key_link(dest_keyring, key); + __key_link(dest_keyring, key, &prealloc); mutex_unlock(&key_construction_mutex); if (dest_keyring) - up_write(&dest_keyring->sem); + __key_link_end(dest_keyring, type, prealloc); mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); @@ -341,27 +347,36 @@ static int construct_alloc_key(struct key_type *type, /* the key is now present - we tell the caller that we found it by * returning -EINPROGRESS */ key_already_present: + key_put(key); mutex_unlock(&key_construction_mutex); - ret = 0; + key = key_ref_to_ptr(key_ref); if (dest_keyring) { - ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref)); - up_write(&dest_keyring->sem); + ret = __key_link_check_live_key(dest_keyring, key); + if (ret == 0) + __key_link(dest_keyring, key, &prealloc); + __key_link_end(dest_keyring, type, prealloc); + if (ret < 0) + goto link_check_failed; } mutex_unlock(&user->cons_lock); - key_put(key); - if (ret < 0) { - key_ref_put(key_ref); - *_key = NULL; - kleave(" = %d [link]", ret); - return ret; - } - *_key = key = key_ref_to_ptr(key_ref); + *_key = key; kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; +link_check_failed: + mutex_unlock(&user->cons_lock); + key_put(key); + kleave(" = %d [linkcheck]", ret); + return ret; + +link_prealloc_failed: + up_write(&dest_keyring->sem); + mutex_unlock(&user->cons_lock); + kleave(" = %d [prelink]", ret); + return ret; + alloc_failed: mutex_unlock(&user->cons_lock); - *_key = NULL; kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); } |