diff options
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 167 |
1 files changed, 107 insertions, 60 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d605f75292e4..7445875f6818 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,6 +25,15 @@ | |||
25 | (keyring)->payload.subscriptions, \ | 25 | (keyring)->payload.subscriptions, \ |
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | ||
28 | #define rcu_deref_link_locked(klist, index, keyring) \ | ||
29 | (rcu_dereference_protected( \ | ||
30 | (klist)->keys[index], \ | ||
31 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
32 | |||
33 | #define MAX_KEYRING_LINKS \ | ||
34 | min_t(size_t, USHRT_MAX - 1, \ | ||
35 | ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) | ||
36 | |||
28 | #define KEY_LINK_FIXQUOTA 1UL | 37 | #define KEY_LINK_FIXQUOTA 1UL |
29 | 38 | ||
30 | /* | 39 | /* |
@@ -138,6 +147,11 @@ static int keyring_match(const struct key *keyring, const void *description) | |||
138 | /* | 147 | /* |
139 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one | 148 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
140 | * and dispose of its data. | 149 | * and dispose of its data. |
150 | * | ||
151 | * The garbage collector detects the final key_put(), removes the keyring from | ||
152 | * the serial number tree and then does RCU synchronisation before coming here, | ||
153 | * so we shouldn't need to worry about code poking around here with the RCU | ||
154 | * readlock held by this time. | ||
141 | */ | 155 | */ |
142 | static void keyring_destroy(struct key *keyring) | 156 | static void keyring_destroy(struct key *keyring) |
143 | { | 157 | { |
@@ -154,11 +168,10 @@ static void keyring_destroy(struct key *keyring) | |||
154 | write_unlock(&keyring_name_lock); | 168 | write_unlock(&keyring_name_lock); |
155 | } | 169 | } |
156 | 170 | ||
157 | klist = rcu_dereference_check(keyring->payload.subscriptions, | 171 | klist = rcu_access_pointer(keyring->payload.subscriptions); |
158 | atomic_read(&keyring->usage) == 0); | ||
159 | if (klist) { | 172 | if (klist) { |
160 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 173 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
161 | key_put(klist->keys[loop]); | 174 | key_put(rcu_access_pointer(klist->keys[loop])); |
162 | kfree(klist); | 175 | kfree(klist); |
163 | } | 176 | } |
164 | } | 177 | } |
@@ -214,7 +227,8 @@ static long keyring_read(const struct key *keyring, | |||
214 | ret = -EFAULT; | 227 | ret = -EFAULT; |
215 | 228 | ||
216 | for (loop = 0; loop < klist->nkeys; loop++) { | 229 | for (loop = 0; loop < klist->nkeys; loop++) { |
217 | key = klist->keys[loop]; | 230 | key = rcu_deref_link_locked(klist, loop, |
231 | keyring); | ||
218 | 232 | ||
219 | tmp = sizeof(key_serial_t); | 233 | tmp = sizeof(key_serial_t); |
220 | if (tmp > buflen) | 234 | if (tmp > buflen) |
@@ -309,6 +323,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
309 | bool no_state_check) | 323 | bool no_state_check) |
310 | { | 324 | { |
311 | struct { | 325 | struct { |
326 | /* Need a separate keylist pointer for RCU purposes */ | ||
327 | struct key *keyring; | ||
312 | struct keyring_list *keylist; | 328 | struct keyring_list *keylist; |
313 | int kix; | 329 | int kix; |
314 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 330 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
@@ -366,13 +382,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
366 | /* otherwise, the top keyring must not be revoked, expired, or | 382 | /* otherwise, the top keyring must not be revoked, expired, or |
367 | * negatively instantiated if we are to search it */ | 383 | * negatively instantiated if we are to search it */ |
368 | key_ref = ERR_PTR(-EAGAIN); | 384 | key_ref = ERR_PTR(-EAGAIN); |
369 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || | 385 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
386 | (1 << KEY_FLAG_REVOKED) | | ||
387 | (1 << KEY_FLAG_NEGATIVE)) || | ||
370 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 388 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
371 | goto error_2; | 389 | goto error_2; |
372 | 390 | ||
373 | /* start processing a new keyring */ | 391 | /* start processing a new keyring */ |
374 | descend: | 392 | descend: |
375 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 393 | kflags = keyring->flags; |
394 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | ||
395 | (1 << KEY_FLAG_REVOKED))) | ||
376 | goto not_this_keyring; | 396 | goto not_this_keyring; |
377 | 397 | ||
378 | keylist = rcu_dereference(keyring->payload.subscriptions); | 398 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -383,16 +403,17 @@ descend: | |||
383 | nkeys = keylist->nkeys; | 403 | nkeys = keylist->nkeys; |
384 | smp_rmb(); | 404 | smp_rmb(); |
385 | for (kix = 0; kix < nkeys; kix++) { | 405 | for (kix = 0; kix < nkeys; kix++) { |
386 | key = keylist->keys[kix]; | 406 | key = rcu_dereference(keylist->keys[kix]); |
387 | kflags = key->flags; | 407 | kflags = key->flags; |
388 | 408 | ||
389 | /* ignore keys not of this type */ | 409 | /* ignore keys not of this type */ |
390 | if (key->type != type) | 410 | if (key->type != type) |
391 | continue; | 411 | continue; |
392 | 412 | ||
393 | /* skip revoked keys and expired keys */ | 413 | /* skip invalidated, revoked and expired keys */ |
394 | if (!no_state_check) { | 414 | if (!no_state_check) { |
395 | if (kflags & (1 << KEY_FLAG_REVOKED)) | 415 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
416 | (1 << KEY_FLAG_REVOKED))) | ||
396 | continue; | 417 | continue; |
397 | 418 | ||
398 | if (key->expiry && now.tv_sec >= key->expiry) | 419 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -426,7 +447,7 @@ ascend: | |||
426 | nkeys = keylist->nkeys; | 447 | nkeys = keylist->nkeys; |
427 | smp_rmb(); | 448 | smp_rmb(); |
428 | for (; kix < nkeys; kix++) { | 449 | for (; kix < nkeys; kix++) { |
429 | key = keylist->keys[kix]; | 450 | key = rcu_dereference(keylist->keys[kix]); |
430 | if (key->type != &key_type_keyring) | 451 | if (key->type != &key_type_keyring) |
431 | continue; | 452 | continue; |
432 | 453 | ||
@@ -441,6 +462,7 @@ ascend: | |||
441 | continue; | 462 | continue; |
442 | 463 | ||
443 | /* stack the current position */ | 464 | /* stack the current position */ |
465 | stack[sp].keyring = keyring; | ||
444 | stack[sp].keylist = keylist; | 466 | stack[sp].keylist = keylist; |
445 | stack[sp].kix = kix; | 467 | stack[sp].kix = kix; |
446 | sp++; | 468 | sp++; |
@@ -456,6 +478,7 @@ not_this_keyring: | |||
456 | if (sp > 0) { | 478 | if (sp > 0) { |
457 | /* resume the processing of a keyring higher up in the tree */ | 479 | /* resume the processing of a keyring higher up in the tree */ |
458 | sp--; | 480 | sp--; |
481 | keyring = stack[sp].keyring; | ||
459 | keylist = stack[sp].keylist; | 482 | keylist = stack[sp].keylist; |
460 | kix = stack[sp].kix + 1; | 483 | kix = stack[sp].kix + 1; |
461 | goto ascend; | 484 | goto ascend; |
@@ -467,6 +490,10 @@ not_this_keyring: | |||
467 | /* we found a viable match */ | 490 | /* we found a viable match */ |
468 | found: | 491 | found: |
469 | atomic_inc(&key->usage); | 492 | atomic_inc(&key->usage); |
493 | key->last_used_at = now.tv_sec; | ||
494 | keyring->last_used_at = now.tv_sec; | ||
495 | while (sp > 0) | ||
496 | stack[--sp].keyring->last_used_at = now.tv_sec; | ||
470 | key_check(key); | 497 | key_check(key); |
471 | key_ref = make_key_ref(key, possessed); | 498 | key_ref = make_key_ref(key, possessed); |
472 | error_2: | 499 | error_2: |
@@ -531,14 +558,14 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
531 | nkeys = klist->nkeys; | 558 | nkeys = klist->nkeys; |
532 | smp_rmb(); | 559 | smp_rmb(); |
533 | for (loop = 0; loop < nkeys ; loop++) { | 560 | for (loop = 0; loop < nkeys ; loop++) { |
534 | key = klist->keys[loop]; | 561 | key = rcu_dereference(klist->keys[loop]); |
535 | |||
536 | if (key->type == ktype && | 562 | if (key->type == ktype && |
537 | (!key->type->match || | 563 | (!key->type->match || |
538 | key->type->match(key, description)) && | 564 | key->type->match(key, description)) && |
539 | key_permission(make_key_ref(key, possessed), | 565 | key_permission(make_key_ref(key, possessed), |
540 | perm) == 0 && | 566 | perm) == 0 && |
541 | !test_bit(KEY_FLAG_REVOKED, &key->flags) | 567 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | |
568 | (1 << KEY_FLAG_REVOKED))) | ||
542 | ) | 569 | ) |
543 | goto found; | 570 | goto found; |
544 | } | 571 | } |
@@ -549,6 +576,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
549 | 576 | ||
550 | found: | 577 | found: |
551 | atomic_inc(&key->usage); | 578 | atomic_inc(&key->usage); |
579 | keyring->last_used_at = key->last_used_at = | ||
580 | current_kernel_time().tv_sec; | ||
552 | rcu_read_unlock(); | 581 | rcu_read_unlock(); |
553 | return make_key_ref(key, possessed); | 582 | return make_key_ref(key, possessed); |
554 | } | 583 | } |
@@ -602,6 +631,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
602 | * (ie. it has a zero usage count) */ | 631 | * (ie. it has a zero usage count) */ |
603 | if (!atomic_inc_not_zero(&keyring->usage)) | 632 | if (!atomic_inc_not_zero(&keyring->usage)) |
604 | continue; | 633 | continue; |
634 | keyring->last_used_at = current_kernel_time().tv_sec; | ||
605 | goto out; | 635 | goto out; |
606 | } | 636 | } |
607 | } | 637 | } |
@@ -654,7 +684,7 @@ ascend: | |||
654 | nkeys = keylist->nkeys; | 684 | nkeys = keylist->nkeys; |
655 | smp_rmb(); | 685 | smp_rmb(); |
656 | for (; kix < nkeys; kix++) { | 686 | for (; kix < nkeys; kix++) { |
657 | key = keylist->keys[kix]; | 687 | key = rcu_dereference(keylist->keys[kix]); |
658 | 688 | ||
659 | if (key == A) | 689 | if (key == A) |
660 | goto cycle_detected; | 690 | goto cycle_detected; |
@@ -711,7 +741,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
711 | container_of(rcu, struct keyring_list, rcu); | 741 | container_of(rcu, struct keyring_list, rcu); |
712 | 742 | ||
713 | if (klist->delkey != USHRT_MAX) | 743 | if (klist->delkey != USHRT_MAX) |
714 | key_put(klist->keys[klist->delkey]); | 744 | key_put(rcu_access_pointer(klist->keys[klist->delkey])); |
715 | kfree(klist); | 745 | kfree(klist); |
716 | } | 746 | } |
717 | 747 | ||
@@ -725,8 +755,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
725 | struct keyring_list *klist, *nklist; | 755 | struct keyring_list *klist, *nklist; |
726 | unsigned long prealloc; | 756 | unsigned long prealloc; |
727 | unsigned max; | 757 | unsigned max; |
758 | time_t lowest_lru; | ||
728 | size_t size; | 759 | size_t size; |
729 | int loop, ret; | 760 | int loop, lru, ret; |
730 | 761 | ||
731 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); | 762 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
732 | 763 | ||
@@ -747,31 +778,39 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
747 | klist = rcu_dereference_locked_keyring(keyring); | 778 | klist = rcu_dereference_locked_keyring(keyring); |
748 | 779 | ||
749 | /* see if there's a matching key we can displace */ | 780 | /* see if there's a matching key we can displace */ |
781 | lru = -1; | ||
750 | if (klist && klist->nkeys > 0) { | 782 | if (klist && klist->nkeys > 0) { |
783 | lowest_lru = TIME_T_MAX; | ||
751 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 784 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
752 | if (klist->keys[loop]->type == type && | 785 | struct key *key = rcu_deref_link_locked(klist, loop, |
753 | strcmp(klist->keys[loop]->description, | 786 | keyring); |
754 | description) == 0 | 787 | if (key->type == type && |
755 | ) { | 788 | strcmp(key->description, description) == 0) { |
756 | /* found a match - we'll replace this one with | 789 | /* Found a match - we'll replace the link with |
757 | * the new key */ | 790 | * one to the new key. We record the slot |
758 | size = sizeof(struct key *) * klist->maxkeys; | 791 | * position. |
759 | size += sizeof(*klist); | 792 | */ |
760 | BUG_ON(size > PAGE_SIZE); | 793 | klist->delkey = loop; |
761 | 794 | prealloc = 0; | |
762 | ret = -ENOMEM; | ||
763 | nklist = kmemdup(klist, size, GFP_KERNEL); | ||
764 | if (!nklist) | ||
765 | goto error_sem; | ||
766 | |||
767 | /* note replacement slot */ | ||
768 | klist->delkey = nklist->delkey = loop; | ||
769 | prealloc = (unsigned long)nklist; | ||
770 | goto done; | 795 | goto done; |
771 | } | 796 | } |
797 | if (key->last_used_at < lowest_lru) { | ||
798 | lowest_lru = key->last_used_at; | ||
799 | lru = loop; | ||
800 | } | ||
772 | } | 801 | } |
773 | } | 802 | } |
774 | 803 | ||
804 | /* If the keyring is full then do an LRU discard */ | ||
805 | if (klist && | ||
806 | klist->nkeys == klist->maxkeys && | ||
807 | klist->maxkeys >= MAX_KEYRING_LINKS) { | ||
808 | kdebug("LRU discard %d\n", lru); | ||
809 | klist->delkey = lru; | ||
810 | prealloc = 0; | ||
811 | goto done; | ||
812 | } | ||
813 | |||
775 | /* check that we aren't going to overrun the user's quota */ | 814 | /* check that we aren't going to overrun the user's quota */ |
776 | ret = key_payload_reserve(keyring, | 815 | ret = key_payload_reserve(keyring, |
777 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 816 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -780,20 +819,19 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
780 | 819 | ||
781 | if (klist && klist->nkeys < klist->maxkeys) { | 820 | if (klist && klist->nkeys < klist->maxkeys) { |
782 | /* there's sufficient slack space to append directly */ | 821 | /* there's sufficient slack space to append directly */ |
783 | nklist = NULL; | 822 | klist->delkey = klist->nkeys; |
784 | prealloc = KEY_LINK_FIXQUOTA; | 823 | prealloc = KEY_LINK_FIXQUOTA; |
785 | } else { | 824 | } else { |
786 | /* grow the key list */ | 825 | /* grow the key list */ |
787 | max = 4; | 826 | max = 4; |
788 | if (klist) | 827 | if (klist) { |
789 | max += klist->maxkeys; | 828 | max += klist->maxkeys; |
829 | if (max > MAX_KEYRING_LINKS) | ||
830 | max = MAX_KEYRING_LINKS; | ||
831 | BUG_ON(max <= klist->maxkeys); | ||
832 | } | ||
790 | 833 | ||
791 | ret = -ENFILE; | ||
792 | if (max > USHRT_MAX - 1) | ||
793 | goto error_quota; | ||
794 | size = sizeof(*klist) + sizeof(struct key *) * max; | 834 | size = sizeof(*klist) + sizeof(struct key *) * max; |
795 | if (size > PAGE_SIZE) | ||
796 | goto error_quota; | ||
797 | 835 | ||
798 | ret = -ENOMEM; | 836 | ret = -ENOMEM; |
799 | nklist = kmalloc(size, GFP_KERNEL); | 837 | nklist = kmalloc(size, GFP_KERNEL); |
@@ -813,10 +851,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
813 | } | 851 | } |
814 | 852 | ||
815 | /* add the key into the new space */ | 853 | /* add the key into the new space */ |
816 | nklist->keys[nklist->delkey] = NULL; | 854 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); |
855 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
817 | } | 856 | } |
818 | 857 | ||
819 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
820 | done: | 858 | done: |
821 | *_prealloc = prealloc; | 859 | *_prealloc = prealloc; |
822 | kleave(" = 0"); | 860 | kleave(" = 0"); |
@@ -862,6 +900,7 @@ void __key_link(struct key *keyring, struct key *key, | |||
862 | unsigned long *_prealloc) | 900 | unsigned long *_prealloc) |
863 | { | 901 | { |
864 | struct keyring_list *klist, *nklist; | 902 | struct keyring_list *klist, *nklist; |
903 | struct key *discard; | ||
865 | 904 | ||
866 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | 905 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
867 | *_prealloc = 0; | 906 | *_prealloc = 0; |
@@ -871,14 +910,16 @@ void __key_link(struct key *keyring, struct key *key, | |||
871 | klist = rcu_dereference_locked_keyring(keyring); | 910 | klist = rcu_dereference_locked_keyring(keyring); |
872 | 911 | ||
873 | atomic_inc(&key->usage); | 912 | atomic_inc(&key->usage); |
913 | keyring->last_used_at = key->last_used_at = | ||
914 | current_kernel_time().tv_sec; | ||
874 | 915 | ||
875 | /* there's a matching key we can displace or an empty slot in a newly | 916 | /* there's a matching key we can displace or an empty slot in a newly |
876 | * allocated list we can fill */ | 917 | * allocated list we can fill */ |
877 | if (nklist) { | 918 | if (nklist) { |
878 | kdebug("replace %hu/%hu/%hu", | 919 | kdebug("reissue %hu/%hu/%hu", |
879 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | 920 | nklist->delkey, nklist->nkeys, nklist->maxkeys); |
880 | 921 | ||
881 | nklist->keys[nklist->delkey] = key; | 922 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); |
882 | 923 | ||
883 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | 924 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
884 | 925 | ||
@@ -889,9 +930,23 @@ void __key_link(struct key *keyring, struct key *key, | |||
889 | klist->delkey, klist->nkeys, klist->maxkeys); | 930 | klist->delkey, klist->nkeys, klist->maxkeys); |
890 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | 931 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
891 | } | 932 | } |
933 | } else if (klist->delkey < klist->nkeys) { | ||
934 | kdebug("replace %hu/%hu/%hu", | ||
935 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
936 | |||
937 | discard = rcu_dereference_protected( | ||
938 | klist->keys[klist->delkey], | ||
939 | rwsem_is_locked(&keyring->sem)); | ||
940 | rcu_assign_pointer(klist->keys[klist->delkey], key); | ||
941 | /* The garbage collector will take care of RCU | ||
942 | * synchronisation */ | ||
943 | key_put(discard); | ||
892 | } else { | 944 | } else { |
893 | /* there's sufficient slack space to append directly */ | 945 | /* there's sufficient slack space to append directly */ |
894 | klist->keys[klist->nkeys] = key; | 946 | kdebug("append %hu/%hu/%hu", |
947 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
948 | |||
949 | RCU_INIT_POINTER(klist->keys[klist->delkey], key); | ||
895 | smp_wmb(); | 950 | smp_wmb(); |
896 | klist->nkeys++; | 951 | klist->nkeys++; |
897 | } | 952 | } |
@@ -998,7 +1053,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
998 | if (klist) { | 1053 | if (klist) { |
999 | /* search the keyring for the key */ | 1054 | /* search the keyring for the key */ |
1000 | for (loop = 0; loop < klist->nkeys; loop++) | 1055 | for (loop = 0; loop < klist->nkeys; loop++) |
1001 | if (klist->keys[loop] == key) | 1056 | if (rcu_access_pointer(klist->keys[loop]) == key) |
1002 | goto key_is_present; | 1057 | goto key_is_present; |
1003 | } | 1058 | } |
1004 | 1059 | ||
@@ -1061,7 +1116,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | |||
1061 | klist = container_of(rcu, struct keyring_list, rcu); | 1116 | klist = container_of(rcu, struct keyring_list, rcu); |
1062 | 1117 | ||
1063 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1118 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1064 | key_put(klist->keys[loop]); | 1119 | key_put(rcu_access_pointer(klist->keys[loop])); |
1065 | 1120 | ||
1066 | kfree(klist); | 1121 | kfree(klist); |
1067 | } | 1122 | } |
@@ -1128,15 +1183,6 @@ static void keyring_revoke(struct key *keyring) | |||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | /* | 1185 | /* |
1131 | * Determine whether a key is dead. | ||
1132 | */ | ||
1133 | static bool key_is_dead(struct key *key, time_t limit) | ||
1134 | { | ||
1135 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1136 | (key->expiry > 0 && key->expiry <= limit); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Collect garbage from the contents of a keyring, replacing the old list with | 1186 | * Collect garbage from the contents of a keyring, replacing the old list with |
1141 | * a new one with the pointers all shuffled down. | 1187 | * a new one with the pointers all shuffled down. |
1142 | * | 1188 | * |
@@ -1161,7 +1207,8 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1161 | /* work out how many subscriptions we're keeping */ | 1207 | /* work out how many subscriptions we're keeping */ |
1162 | keep = 0; | 1208 | keep = 0; |
1163 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1209 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1164 | if (!key_is_dead(klist->keys[loop], limit)) | 1210 | if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), |
1211 | limit)) | ||
1165 | keep++; | 1212 | keep++; |
1166 | 1213 | ||
1167 | if (keep == klist->nkeys) | 1214 | if (keep == klist->nkeys) |
@@ -1182,11 +1229,11 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1182 | */ | 1229 | */ |
1183 | keep = 0; | 1230 | keep = 0; |
1184 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 1231 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
1185 | key = klist->keys[loop]; | 1232 | key = rcu_deref_link_locked(klist, loop, keyring); |
1186 | if (!key_is_dead(key, limit)) { | 1233 | if (!key_is_dead(key, limit)) { |
1187 | if (keep >= max) | 1234 | if (keep >= max) |
1188 | goto discard_new; | 1235 | goto discard_new; |
1189 | new->keys[keep++] = key_get(key); | 1236 | RCU_INIT_POINTER(new->keys[keep++], key_get(key)); |
1190 | } | 1237 | } |
1191 | } | 1238 | } |
1192 | new->nkeys = keep; | 1239 | new->nkeys = keep; |