diff options
author | David Howells <dhowells@redhat.com> | 2010-04-30 14:32:34 +0100 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-05-06 10:56:55 +1000 |
commit | 2b9e4688fad8867b6e918610f396af3ab9246898 (patch) | |
tree | c0146493e6ea4dff7b51259de1d7e83729a26c94 | |
parent | 553d603c8fce8cf727eb26e4bf6b9549cd4623f1 (diff) |
KEYS: Better handling of errors from construct_alloc_key()
Errors from construct_alloc_key() shouldn't just be ignored in the way they are
by construct_key_and_link(). The only error that can be ignored so is
EINPROGRESS as that is used to indicate that we've found a key and don't need
to construct one.
We don't, however, handle ENOMEM, EDQUOT or EACCES to indicate allocation
failures of one sort or another.
Reported-by: Vegard Nossum <vegard.nossum@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r-- | security/keys/request_key.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index d737cea5347c..1bc38587adc4 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -302,6 +302,7 @@ static int construct_alloc_key(struct key_type *type, const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; + int ret; kenter("%s,%s,,,", type->name, description); @@ -337,14 +338,23 @@ static int construct_alloc_key(struct key_type *type, kleave(" = 0 [%d]", key_serial(key)); return 0; + /* the key is now present - we tell the caller that we found it by + * returning -EINPROGRESS */ key_already_present: mutex_unlock(&key_construction_mutex); + ret = 0; if (dest_keyring) { - __key_link(dest_keyring, key_ref_to_ptr(key_ref)); + ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref)); up_write(&dest_keyring->sem); } 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); kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; @@ -390,6 +400,10 @@ static struct key *construct_key_and_link(struct key_type *type, kdebug("cons failed"); goto construction_failed; } + } else if (ret == -EINPROGRESS) { + ret = 0; + } else { + key = ERR_PTR(ret); } key_put(dest_keyring); @@ -422,6 +436,7 @@ struct key *request_key_and_link(struct key_type *type, const struct cred *cred = current_cred(); struct key *key; key_ref_t key_ref; + int ret; kenter("%s,%s,%p,%zu,%p,%p,%lx", type->name, description, callout_info, callout_len, aux, @@ -435,8 +450,13 @@ struct key *request_key_and_link(struct key_type *type, key = key_ref_to_ptr(key_ref); if (dest_keyring) { construct_get_dest_keyring(&dest_keyring); - key_link(dest_keyring, key); + ret = key_link(dest_keyring, key); key_put(dest_keyring); + if (ret < 0) { + key_put(key); + key = ERR_PTR(ret); + goto error; + } } } else if (PTR_ERR(key_ref) != -EAGAIN) { key = ERR_CAST(key_ref); |