diff options
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 41 |
1 files changed, 30 insertions, 11 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index eb914a838840..83bf4b4afd49 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -402,6 +402,18 @@ int key_payload_reserve(struct key *key, size_t datalen) | |||
402 | EXPORT_SYMBOL(key_payload_reserve); | 402 | EXPORT_SYMBOL(key_payload_reserve); |
403 | 403 | ||
404 | /* | 404 | /* |
405 | * Change the key state to being instantiated. | ||
406 | */ | ||
407 | static void mark_key_instantiated(struct key *key, int reject_error) | ||
408 | { | ||
409 | /* Commit the payload before setting the state; barrier versus | ||
410 | * key_read_state(). | ||
411 | */ | ||
412 | smp_store_release(&key->state, | ||
413 | (reject_error < 0) ? reject_error : KEY_IS_POSITIVE); | ||
414 | } | ||
415 | |||
416 | /* | ||
405 | * Instantiate a key and link it into the target keyring atomically. Must be | 417 | * Instantiate a key and link it into the target keyring atomically. Must be |
406 | * called with the target keyring's semaphore writelocked. The target key's | 418 | * called with the target keyring's semaphore writelocked. The target key's |
407 | * semaphore need not be locked as instantiation is serialised by | 419 | * semaphore need not be locked as instantiation is serialised by |
@@ -424,14 +436,14 @@ static int __key_instantiate_and_link(struct key *key, | |||
424 | mutex_lock(&key_construction_mutex); | 436 | mutex_lock(&key_construction_mutex); |
425 | 437 | ||
426 | /* can't instantiate twice */ | 438 | /* can't instantiate twice */ |
427 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 439 | if (key->state == KEY_IS_UNINSTANTIATED) { |
428 | /* instantiate the key */ | 440 | /* instantiate the key */ |
429 | ret = key->type->instantiate(key, prep); | 441 | ret = key->type->instantiate(key, prep); |
430 | 442 | ||
431 | if (ret == 0) { | 443 | if (ret == 0) { |
432 | /* mark the key as being instantiated */ | 444 | /* mark the key as being instantiated */ |
433 | atomic_inc(&key->user->nikeys); | 445 | atomic_inc(&key->user->nikeys); |
434 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | 446 | mark_key_instantiated(key, 0); |
435 | 447 | ||
436 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) | 448 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
437 | awaken = 1; | 449 | awaken = 1; |
@@ -577,13 +589,10 @@ int key_reject_and_link(struct key *key, | |||
577 | mutex_lock(&key_construction_mutex); | 589 | mutex_lock(&key_construction_mutex); |
578 | 590 | ||
579 | /* can't instantiate twice */ | 591 | /* can't instantiate twice */ |
580 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 592 | if (key->state == KEY_IS_UNINSTANTIATED) { |
581 | /* mark the key as being negatively instantiated */ | 593 | /* mark the key as being negatively instantiated */ |
582 | atomic_inc(&key->user->nikeys); | 594 | atomic_inc(&key->user->nikeys); |
583 | key->reject_error = -error; | 595 | mark_key_instantiated(key, -error); |
584 | smp_wmb(); | ||
585 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
586 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | ||
587 | now = current_kernel_time(); | 596 | now = current_kernel_time(); |
588 | key->expiry = now.tv_sec + timeout; | 597 | key->expiry = now.tv_sec + timeout; |
589 | key_schedule_gc(key->expiry + key_gc_delay); | 598 | key_schedule_gc(key->expiry + key_gc_delay); |
@@ -752,8 +761,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref, | |||
752 | 761 | ||
753 | ret = key->type->update(key, prep); | 762 | ret = key->type->update(key, prep); |
754 | if (ret == 0) | 763 | if (ret == 0) |
755 | /* updating a negative key instantiates it */ | 764 | /* Updating a negative key positively instantiates it */ |
756 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | 765 | mark_key_instantiated(key, 0); |
757 | 766 | ||
758 | up_write(&key->sem); | 767 | up_write(&key->sem); |
759 | 768 | ||
@@ -936,6 +945,16 @@ error: | |||
936 | */ | 945 | */ |
937 | __key_link_end(keyring, &index_key, edit); | 946 | __key_link_end(keyring, &index_key, edit); |
938 | 947 | ||
948 | key = key_ref_to_ptr(key_ref); | ||
949 | if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) { | ||
950 | ret = wait_for_key_construction(key, true); | ||
951 | if (ret < 0) { | ||
952 | key_ref_put(key_ref); | ||
953 | key_ref = ERR_PTR(ret); | ||
954 | goto error_free_prep; | ||
955 | } | ||
956 | } | ||
957 | |||
939 | key_ref = __key_update(key_ref, &prep); | 958 | key_ref = __key_update(key_ref, &prep); |
940 | goto error_free_prep; | 959 | goto error_free_prep; |
941 | } | 960 | } |
@@ -986,8 +1005,8 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
986 | 1005 | ||
987 | ret = key->type->update(key, &prep); | 1006 | ret = key->type->update(key, &prep); |
988 | if (ret == 0) | 1007 | if (ret == 0) |
989 | /* updating a negative key instantiates it */ | 1008 | /* Updating a negative key positively instantiates it */ |
990 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | 1009 | mark_key_instantiated(key, 0); |
991 | 1010 | ||
992 | up_write(&key->sem); | 1011 | up_write(&key->sem); |
993 | 1012 | ||