diff options
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 ac49c8aacbf..f656e9c069e 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, | |||
299 | struct key_user *user, | 299 | struct key_user *user, |
300 | struct key **_key) | 300 | struct key **_key) |
301 | { | 301 | { |
302 | struct keyring_list *prealloc; | ||
302 | const struct cred *cred = current_cred(); | 303 | const struct cred *cred = current_cred(); |
303 | struct key *key; | 304 | struct key *key; |
304 | key_ref_t key_ref; | 305 | key_ref_t key_ref; |
@@ -306,6 +307,7 @@ static int construct_alloc_key(struct key_type *type, | |||
306 | 307 | ||
307 | kenter("%s,%s,,,", type->name, description); | 308 | kenter("%s,%s,,,", type->name, description); |
308 | 309 | ||
310 | *_key = NULL; | ||
309 | mutex_lock(&user->cons_lock); | 311 | mutex_lock(&user->cons_lock); |
310 | 312 | ||
311 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, | 313 | key = key_alloc(type, description, cred->fsuid, cred->fsgid, cred, |
@@ -315,8 +317,12 @@ static int construct_alloc_key(struct key_type *type, | |||
315 | 317 | ||
316 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); | 318 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
317 | 319 | ||
318 | if (dest_keyring) | 320 | if (dest_keyring) { |
319 | down_write(&dest_keyring->sem); | 321 | ret = __key_link_begin(dest_keyring, type, description, |
322 | &prealloc); | ||
323 | if (ret < 0) | ||
324 | goto link_prealloc_failed; | ||
325 | } | ||
320 | 326 | ||
321 | /* attach the key to the destination keyring under lock, but we do need | 327 | /* attach the key to the destination keyring under lock, but we do need |
322 | * to do another check just in case someone beat us to it whilst we | 328 | * 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, | |||
328 | goto key_already_present; | 334 | goto key_already_present; |
329 | 335 | ||
330 | if (dest_keyring) | 336 | if (dest_keyring) |
331 | __key_link(dest_keyring, key); | 337 | __key_link(dest_keyring, key, &prealloc); |
332 | 338 | ||
333 | mutex_unlock(&key_construction_mutex); | 339 | mutex_unlock(&key_construction_mutex); |
334 | if (dest_keyring) | 340 | if (dest_keyring) |
335 | up_write(&dest_keyring->sem); | 341 | __key_link_end(dest_keyring, type, prealloc); |
336 | mutex_unlock(&user->cons_lock); | 342 | mutex_unlock(&user->cons_lock); |
337 | *_key = key; | 343 | *_key = key; |
338 | kleave(" = 0 [%d]", key_serial(key)); | 344 | kleave(" = 0 [%d]", key_serial(key)); |
@@ -341,27 +347,36 @@ static int construct_alloc_key(struct key_type *type, | |||
341 | /* the key is now present - we tell the caller that we found it by | 347 | /* the key is now present - we tell the caller that we found it by |
342 | * returning -EINPROGRESS */ | 348 | * returning -EINPROGRESS */ |
343 | key_already_present: | 349 | key_already_present: |
350 | key_put(key); | ||
344 | mutex_unlock(&key_construction_mutex); | 351 | mutex_unlock(&key_construction_mutex); |
345 | ret = 0; | 352 | key = key_ref_to_ptr(key_ref); |
346 | if (dest_keyring) { | 353 | if (dest_keyring) { |
347 | ret = __key_link(dest_keyring, key_ref_to_ptr(key_ref)); | 354 | ret = __key_link_check_live_key(dest_keyring, key); |
348 | up_write(&dest_keyring->sem); | 355 | if (ret == 0) |
356 | __key_link(dest_keyring, key, &prealloc); | ||
357 | __key_link_end(dest_keyring, type, prealloc); | ||
358 | if (ret < 0) | ||
359 | goto link_check_failed; | ||
349 | } | 360 | } |
350 | mutex_unlock(&user->cons_lock); | 361 | mutex_unlock(&user->cons_lock); |
351 | key_put(key); | 362 | *_key = key; |
352 | if (ret < 0) { | ||
353 | key_ref_put(key_ref); | ||
354 | *_key = NULL; | ||
355 | kleave(" = %d [link]", ret); | ||
356 | return ret; | ||
357 | } | ||
358 | *_key = key = key_ref_to_ptr(key_ref); | ||
359 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); | 363 | kleave(" = -EINPROGRESS [%d]", key_serial(key)); |
360 | return -EINPROGRESS; | 364 | return -EINPROGRESS; |
361 | 365 | ||
366 | link_check_failed: | ||
367 | mutex_unlock(&user->cons_lock); | ||
368 | key_put(key); | ||
369 | kleave(" = %d [linkcheck]", ret); | ||
370 | return ret; | ||
371 | |||
372 | link_prealloc_failed: | ||
373 | up_write(&dest_keyring->sem); | ||
374 | mutex_unlock(&user->cons_lock); | ||
375 | kleave(" = %d [prelink]", ret); | ||
376 | return ret; | ||
377 | |||
362 | alloc_failed: | 378 | alloc_failed: |
363 | mutex_unlock(&user->cons_lock); | 379 | mutex_unlock(&user->cons_lock); |
364 | *_key = NULL; | ||
365 | kleave(" = %ld", PTR_ERR(key)); | 380 | kleave(" = %ld", PTR_ERR(key)); |
366 | return PTR_ERR(key); | 381 | return PTR_ERR(key); |
367 | } | 382 | } |