diff options
Diffstat (limited to 'security/keys/request_key.c')
-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, | |||
302 | const struct cred *cred = current_cred(); | 302 | const struct cred *cred = current_cred(); |
303 | struct key *key; | 303 | struct key *key; |
304 | key_ref_t key_ref; | 304 | key_ref_t key_ref; |
305 | int ret; | ||
305 | 306 | ||
306 | kenter("%s,%s,,,", type->name, description); | 307 | kenter("%s,%s,,,", type->name, description); |
307 | 308 | ||
@@ -337,14 +338,23 @@ static int construct_alloc_key(struct key_type *type, | |||
337 | kleave(" = 0 [%d]", key_serial(key)); | 338 | kleave(" = 0 [%d]", key_serial(key)); |
338 | return 0; | 339 | return 0; |
339 | 340 | ||
341 | /* the key is now present - we tell the caller that we found it by | ||
342 | * returning -EINPROGRESS */ | ||
340 | key_already_present: | 343 | key_already_present: |
341 | mutex_unlock(&key_construction_mutex); | 344 | mutex_unlock(&key_construction_mutex); |
345 | ret = 0; | ||
342 | if (dest_keyring) { | 346 | if (dest_keyring) { |
343 | __key_link(dest_keyring, key_ref_to_ptr(key_ref)); | 347 | ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref)); |
344 | up_write(&dest_keyring->sem); | 348 | up_write(&dest_keyring->sem); |
345 | } | 349 | } |
346 | mutex_unlock(&user->cons_lock); | 350 | mutex_unlock(&user->cons_lock); |
347 | key_put(key); | 351 | key_put(key); |
352 | if (ret < 0) { | ||
353 | key_ref_put(key_ref); | ||
354 | *_key = NULL; | ||
355 | kleave(" = %d [link]", ret); | ||
356 | return ret; | ||
357 | } | ||
348 | *_key = key = key_ref_to_ptr(key_ref); | 358 | *_key = key = key_ref_to_ptr(key_ref); |
349 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); | 359 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); |
350 | return -EINPROGRESS; | 360 | return -EINPROGRESS; |
@@ -390,6 +400,10 @@ static struct key *construct_key_and_link(struct key_type *type, | |||
390 | kdebug("cons failed"); | 400 | kdebug("cons failed"); |
391 | goto construction_failed; | 401 | goto construction_failed; |
392 | } | 402 | } |
403 | } else if (ret == -EINPROGRESS) { | ||
404 | ret = 0; | ||
405 | } else { | ||
406 | key = ERR_PTR(ret); | ||
393 | } | 407 | } |
394 | 408 | ||
395 | key_put(dest_keyring); | 409 | key_put(dest_keyring); |
@@ -422,6 +436,7 @@ struct key *request_key_and_link(struct key_type *type, | |||
422 | const struct cred *cred = current_cred(); | 436 | const struct cred *cred = current_cred(); |
423 | struct key *key; | 437 | struct key *key; |
424 | key_ref_t key_ref; | 438 | key_ref_t key_ref; |
439 | int ret; | ||
425 | 440 | ||
426 | kenter("%s,%s,%p,%zu,%p,%p,%lx", | 441 | kenter("%s,%s,%p,%zu,%p,%p,%lx", |
427 | type->name, description, callout_info, callout_len, aux, | 442 | type->name, description, callout_info, callout_len, aux, |
@@ -435,8 +450,13 @@ struct key *request_key_and_link(struct key_type *type, | |||
435 | key = key_ref_to_ptr(key_ref); | 450 | key = key_ref_to_ptr(key_ref); |
436 | if (dest_keyring) { | 451 | if (dest_keyring) { |
437 | construct_get_dest_keyring(&dest_keyring); | 452 | construct_get_dest_keyring(&dest_keyring); |
438 | key_link(dest_keyring, key); | 453 | ret = key_link(dest_keyring, key); |
439 | key_put(dest_keyring); | 454 | key_put(dest_keyring); |
455 | if (ret < 0) { | ||
456 | key_put(key); | ||
457 | key = ERR_PTR(ret); | ||
458 | goto error; | ||
459 | } | ||
440 | } | 460 | } |
441 | } else if (PTR_ERR(key_ref) != -EAGAIN) { | 461 | } else if (PTR_ERR(key_ref) != -EAGAIN) { |
442 | key = ERR_CAST(key_ref); | 462 | key = ERR_CAST(key_ref); |