diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /security/keys/keyring.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 214 |
1 files changed, 80 insertions, 134 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 6ece7f2e570..30e242f7bd0 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,15 +25,6 @@ | |||
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 | |||
37 | #define KEY_LINK_FIXQUOTA 1UL | 28 | #define KEY_LINK_FIXQUOTA 1UL |
38 | 29 | ||
39 | /* | 30 | /* |
@@ -66,7 +57,7 @@ static inline unsigned keyring_hash(const char *desc) | |||
66 | * operations. | 57 | * operations. |
67 | */ | 58 | */ |
68 | static int keyring_instantiate(struct key *keyring, | 59 | static int keyring_instantiate(struct key *keyring, |
69 | struct key_preparsed_payload *prep); | 60 | const void *data, size_t datalen); |
70 | static int keyring_match(const struct key *keyring, const void *criterion); | 61 | static int keyring_match(const struct key *keyring, const void *criterion); |
71 | static void keyring_revoke(struct key *keyring); | 62 | static void keyring_revoke(struct key *keyring); |
72 | static void keyring_destroy(struct key *keyring); | 63 | static void keyring_destroy(struct key *keyring); |
@@ -121,12 +112,12 @@ static void keyring_publish_name(struct key *keyring) | |||
121 | * Returns 0 on success, -EINVAL if given any data. | 112 | * Returns 0 on success, -EINVAL if given any data. |
122 | */ | 113 | */ |
123 | static int keyring_instantiate(struct key *keyring, | 114 | static int keyring_instantiate(struct key *keyring, |
124 | struct key_preparsed_payload *prep) | 115 | const void *data, size_t datalen) |
125 | { | 116 | { |
126 | int ret; | 117 | int ret; |
127 | 118 | ||
128 | ret = -EINVAL; | 119 | ret = -EINVAL; |
129 | if (prep->datalen == 0) { | 120 | if (datalen == 0) { |
130 | /* make the keyring available by name if it has one */ | 121 | /* make the keyring available by name if it has one */ |
131 | keyring_publish_name(keyring); | 122 | keyring_publish_name(keyring); |
132 | ret = 0; | 123 | ret = 0; |
@@ -147,11 +138,6 @@ static int keyring_match(const struct key *keyring, const void *description) | |||
147 | /* | 138 | /* |
148 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one | 139 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
149 | * and dispose of its data. | 140 | * 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. | ||
155 | */ | 141 | */ |
156 | static void keyring_destroy(struct key *keyring) | 142 | static void keyring_destroy(struct key *keyring) |
157 | { | 143 | { |
@@ -168,10 +154,11 @@ static void keyring_destroy(struct key *keyring) | |||
168 | write_unlock(&keyring_name_lock); | 154 | write_unlock(&keyring_name_lock); |
169 | } | 155 | } |
170 | 156 | ||
171 | klist = rcu_access_pointer(keyring->payload.subscriptions); | 157 | klist = rcu_dereference_check(keyring->payload.subscriptions, |
158 | atomic_read(&keyring->usage) == 0); | ||
172 | if (klist) { | 159 | if (klist) { |
173 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 160 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
174 | key_put(rcu_access_pointer(klist->keys[loop])); | 161 | key_put(klist->keys[loop]); |
175 | kfree(klist); | 162 | kfree(klist); |
176 | } | 163 | } |
177 | } | 164 | } |
@@ -227,8 +214,7 @@ static long keyring_read(const struct key *keyring, | |||
227 | ret = -EFAULT; | 214 | ret = -EFAULT; |
228 | 215 | ||
229 | for (loop = 0; loop < klist->nkeys; loop++) { | 216 | for (loop = 0; loop < klist->nkeys; loop++) { |
230 | key = rcu_deref_link_locked(klist, loop, | 217 | key = klist->keys[loop]; |
231 | keyring); | ||
232 | 218 | ||
233 | tmp = sizeof(key_serial_t); | 219 | tmp = sizeof(key_serial_t); |
234 | if (tmp > buflen) | 220 | if (tmp > buflen) |
@@ -256,15 +242,18 @@ error: | |||
256 | /* | 242 | /* |
257 | * Allocate a keyring and link into the destination keyring. | 243 | * Allocate a keyring and link into the destination keyring. |
258 | */ | 244 | */ |
259 | struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | 245 | struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid, |
260 | const struct cred *cred, key_perm_t perm, | 246 | const struct cred *cred, unsigned long flags, |
261 | unsigned long flags, struct key *dest) | 247 | struct key *dest) |
262 | { | 248 | { |
263 | struct key *keyring; | 249 | struct key *keyring; |
264 | int ret; | 250 | int ret; |
265 | 251 | ||
266 | keyring = key_alloc(&key_type_keyring, description, | 252 | keyring = key_alloc(&key_type_keyring, description, |
267 | uid, gid, cred, perm, flags); | 253 | uid, gid, cred, |
254 | (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
255 | flags); | ||
256 | |||
268 | if (!IS_ERR(keyring)) { | 257 | if (!IS_ERR(keyring)) { |
269 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); | 258 | ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL); |
270 | if (ret < 0) { | 259 | if (ret < 0) { |
@@ -275,7 +264,6 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, | |||
275 | 264 | ||
276 | return keyring; | 265 | return keyring; |
277 | } | 266 | } |
278 | EXPORT_SYMBOL(keyring_alloc); | ||
279 | 267 | ||
280 | /** | 268 | /** |
281 | * keyring_search_aux - Search a keyring tree for a key matching some criteria | 269 | * keyring_search_aux - Search a keyring tree for a key matching some criteria |
@@ -321,8 +309,6 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
321 | bool no_state_check) | 309 | bool no_state_check) |
322 | { | 310 | { |
323 | struct { | 311 | struct { |
324 | /* Need a separate keylist pointer for RCU purposes */ | ||
325 | struct key *keyring; | ||
326 | struct keyring_list *keylist; | 312 | struct keyring_list *keylist; |
327 | int kix; | 313 | int kix; |
328 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 314 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
@@ -333,7 +319,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
333 | struct key *keyring, *key; | 319 | struct key *keyring, *key; |
334 | key_ref_t key_ref; | 320 | key_ref_t key_ref; |
335 | long err; | 321 | long err; |
336 | int sp, nkeys, kix; | 322 | int sp, kix; |
337 | 323 | ||
338 | keyring = key_ref_to_ptr(keyring_ref); | 324 | keyring = key_ref_to_ptr(keyring_ref); |
339 | possessed = is_key_possessed(keyring_ref); | 325 | possessed = is_key_possessed(keyring_ref); |
@@ -380,17 +366,13 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
380 | /* otherwise, the top keyring must not be revoked, expired, or | 366 | /* otherwise, the top keyring must not be revoked, expired, or |
381 | * negatively instantiated if we are to search it */ | 367 | * negatively instantiated if we are to search it */ |
382 | key_ref = ERR_PTR(-EAGAIN); | 368 | key_ref = ERR_PTR(-EAGAIN); |
383 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | 369 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || |
384 | (1 << KEY_FLAG_REVOKED) | | ||
385 | (1 << KEY_FLAG_NEGATIVE)) || | ||
386 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 370 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
387 | goto error_2; | 371 | goto error_2; |
388 | 372 | ||
389 | /* start processing a new keyring */ | 373 | /* start processing a new keyring */ |
390 | descend: | 374 | descend: |
391 | kflags = keyring->flags; | 375 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
392 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | ||
393 | (1 << KEY_FLAG_REVOKED))) | ||
394 | goto not_this_keyring; | 376 | goto not_this_keyring; |
395 | 377 | ||
396 | keylist = rcu_dereference(keyring->payload.subscriptions); | 378 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -398,20 +380,17 @@ descend: | |||
398 | goto not_this_keyring; | 380 | goto not_this_keyring; |
399 | 381 | ||
400 | /* iterate through the keys in this keyring first */ | 382 | /* iterate through the keys in this keyring first */ |
401 | nkeys = keylist->nkeys; | 383 | for (kix = 0; kix < keylist->nkeys; kix++) { |
402 | smp_rmb(); | 384 | key = keylist->keys[kix]; |
403 | for (kix = 0; kix < nkeys; kix++) { | ||
404 | key = rcu_dereference(keylist->keys[kix]); | ||
405 | kflags = key->flags; | 385 | kflags = key->flags; |
406 | 386 | ||
407 | /* ignore keys not of this type */ | 387 | /* ignore keys not of this type */ |
408 | if (key->type != type) | 388 | if (key->type != type) |
409 | continue; | 389 | continue; |
410 | 390 | ||
411 | /* skip invalidated, revoked and expired keys */ | 391 | /* skip revoked keys and expired keys */ |
412 | if (!no_state_check) { | 392 | if (!no_state_check) { |
413 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | 393 | if (kflags & (1 << KEY_FLAG_REVOKED)) |
414 | (1 << KEY_FLAG_REVOKED))) | ||
415 | continue; | 394 | continue; |
416 | 395 | ||
417 | if (key->expiry && now.tv_sec >= key->expiry) | 396 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -442,10 +421,8 @@ descend: | |||
442 | /* search through the keyrings nested in this one */ | 421 | /* search through the keyrings nested in this one */ |
443 | kix = 0; | 422 | kix = 0; |
444 | ascend: | 423 | ascend: |
445 | nkeys = keylist->nkeys; | 424 | for (; kix < keylist->nkeys; kix++) { |
446 | smp_rmb(); | 425 | key = keylist->keys[kix]; |
447 | for (; kix < nkeys; kix++) { | ||
448 | key = rcu_dereference(keylist->keys[kix]); | ||
449 | if (key->type != &key_type_keyring) | 426 | if (key->type != &key_type_keyring) |
450 | continue; | 427 | continue; |
451 | 428 | ||
@@ -460,7 +437,6 @@ ascend: | |||
460 | continue; | 437 | continue; |
461 | 438 | ||
462 | /* stack the current position */ | 439 | /* stack the current position */ |
463 | stack[sp].keyring = keyring; | ||
464 | stack[sp].keylist = keylist; | 440 | stack[sp].keylist = keylist; |
465 | stack[sp].kix = kix; | 441 | stack[sp].kix = kix; |
466 | sp++; | 442 | sp++; |
@@ -476,7 +452,6 @@ not_this_keyring: | |||
476 | if (sp > 0) { | 452 | if (sp > 0) { |
477 | /* resume the processing of a keyring higher up in the tree */ | 453 | /* resume the processing of a keyring higher up in the tree */ |
478 | sp--; | 454 | sp--; |
479 | keyring = stack[sp].keyring; | ||
480 | keylist = stack[sp].keylist; | 455 | keylist = stack[sp].keylist; |
481 | kix = stack[sp].kix + 1; | 456 | kix = stack[sp].kix + 1; |
482 | goto ascend; | 457 | goto ascend; |
@@ -488,10 +463,6 @@ not_this_keyring: | |||
488 | /* we found a viable match */ | 463 | /* we found a viable match */ |
489 | found: | 464 | found: |
490 | atomic_inc(&key->usage); | 465 | atomic_inc(&key->usage); |
491 | key->last_used_at = now.tv_sec; | ||
492 | keyring->last_used_at = now.tv_sec; | ||
493 | while (sp > 0) | ||
494 | stack[--sp].keyring->last_used_at = now.tv_sec; | ||
495 | key_check(key); | 466 | key_check(key); |
496 | key_ref = make_key_ref(key, possessed); | 467 | key_ref = make_key_ref(key, possessed); |
497 | error_2: | 468 | error_2: |
@@ -544,7 +515,7 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
544 | struct keyring_list *klist; | 515 | struct keyring_list *klist; |
545 | unsigned long possessed; | 516 | unsigned long possessed; |
546 | struct key *keyring, *key; | 517 | struct key *keyring, *key; |
547 | int nkeys, loop; | 518 | int loop; |
548 | 519 | ||
549 | keyring = key_ref_to_ptr(keyring_ref); | 520 | keyring = key_ref_to_ptr(keyring_ref); |
550 | possessed = is_key_possessed(keyring_ref); | 521 | possessed = is_key_possessed(keyring_ref); |
@@ -553,17 +524,15 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
553 | 524 | ||
554 | klist = rcu_dereference(keyring->payload.subscriptions); | 525 | klist = rcu_dereference(keyring->payload.subscriptions); |
555 | if (klist) { | 526 | if (klist) { |
556 | nkeys = klist->nkeys; | 527 | for (loop = 0; loop < klist->nkeys; loop++) { |
557 | smp_rmb(); | 528 | key = klist->keys[loop]; |
558 | for (loop = 0; loop < nkeys ; loop++) { | 529 | |
559 | key = rcu_dereference(klist->keys[loop]); | ||
560 | if (key->type == ktype && | 530 | if (key->type == ktype && |
561 | (!key->type->match || | 531 | (!key->type->match || |
562 | key->type->match(key, description)) && | 532 | key->type->match(key, description)) && |
563 | key_permission(make_key_ref(key, possessed), | 533 | key_permission(make_key_ref(key, possessed), |
564 | perm) == 0 && | 534 | perm) == 0 && |
565 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | | 535 | !test_bit(KEY_FLAG_REVOKED, &key->flags) |
566 | (1 << KEY_FLAG_REVOKED))) | ||
567 | ) | 536 | ) |
568 | goto found; | 537 | goto found; |
569 | } | 538 | } |
@@ -574,8 +543,6 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
574 | 543 | ||
575 | found: | 544 | found: |
576 | atomic_inc(&key->usage); | 545 | atomic_inc(&key->usage); |
577 | keyring->last_used_at = key->last_used_at = | ||
578 | current_kernel_time().tv_sec; | ||
579 | rcu_read_unlock(); | 546 | rcu_read_unlock(); |
580 | return make_key_ref(key, possessed); | 547 | return make_key_ref(key, possessed); |
581 | } | 548 | } |
@@ -610,7 +577,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
610 | &keyring_name_hash[bucket], | 577 | &keyring_name_hash[bucket], |
611 | type_data.link | 578 | type_data.link |
612 | ) { | 579 | ) { |
613 | if (!kuid_has_mapping(current_user_ns(), keyring->user->uid)) | 580 | if (keyring->user->user_ns != current_user_ns()) |
614 | continue; | 581 | continue; |
615 | 582 | ||
616 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 583 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
@@ -629,7 +596,6 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
629 | * (ie. it has a zero usage count) */ | 596 | * (ie. it has a zero usage count) */ |
630 | if (!atomic_inc_not_zero(&keyring->usage)) | 597 | if (!atomic_inc_not_zero(&keyring->usage)) |
631 | continue; | 598 | continue; |
632 | keyring->last_used_at = current_kernel_time().tv_sec; | ||
633 | goto out; | 599 | goto out; |
634 | } | 600 | } |
635 | } | 601 | } |
@@ -656,7 +622,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
656 | 622 | ||
657 | struct keyring_list *keylist; | 623 | struct keyring_list *keylist; |
658 | struct key *subtree, *key; | 624 | struct key *subtree, *key; |
659 | int sp, nkeys, kix, ret; | 625 | int sp, kix, ret; |
660 | 626 | ||
661 | rcu_read_lock(); | 627 | rcu_read_lock(); |
662 | 628 | ||
@@ -679,10 +645,8 @@ descend: | |||
679 | 645 | ||
680 | ascend: | 646 | ascend: |
681 | /* iterate through the remaining keys in this keyring */ | 647 | /* iterate through the remaining keys in this keyring */ |
682 | nkeys = keylist->nkeys; | 648 | for (; kix < keylist->nkeys; kix++) { |
683 | smp_rmb(); | 649 | key = keylist->keys[kix]; |
684 | for (; kix < nkeys; kix++) { | ||
685 | key = rcu_dereference(keylist->keys[kix]); | ||
686 | 650 | ||
687 | if (key == A) | 651 | if (key == A) |
688 | goto cycle_detected; | 652 | goto cycle_detected; |
@@ -739,7 +703,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
739 | container_of(rcu, struct keyring_list, rcu); | 703 | container_of(rcu, struct keyring_list, rcu); |
740 | 704 | ||
741 | if (klist->delkey != USHRT_MAX) | 705 | if (klist->delkey != USHRT_MAX) |
742 | key_put(rcu_access_pointer(klist->keys[klist->delkey])); | 706 | key_put(klist->keys[klist->delkey]); |
743 | kfree(klist); | 707 | kfree(klist); |
744 | } | 708 | } |
745 | 709 | ||
@@ -749,14 +713,12 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
749 | int __key_link_begin(struct key *keyring, const struct key_type *type, | 713 | int __key_link_begin(struct key *keyring, const struct key_type *type, |
750 | const char *description, unsigned long *_prealloc) | 714 | const char *description, unsigned long *_prealloc) |
751 | __acquires(&keyring->sem) | 715 | __acquires(&keyring->sem) |
752 | __acquires(&keyring_serialise_link_sem) | ||
753 | { | 716 | { |
754 | struct keyring_list *klist, *nklist; | 717 | struct keyring_list *klist, *nklist; |
755 | unsigned long prealloc; | 718 | unsigned long prealloc; |
756 | unsigned max; | 719 | unsigned max; |
757 | time_t lowest_lru; | ||
758 | size_t size; | 720 | size_t size; |
759 | int loop, lru, ret; | 721 | int loop, ret; |
760 | 722 | ||
761 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); | 723 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
762 | 724 | ||
@@ -777,39 +739,31 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
777 | klist = rcu_dereference_locked_keyring(keyring); | 739 | klist = rcu_dereference_locked_keyring(keyring); |
778 | 740 | ||
779 | /* see if there's a matching key we can displace */ | 741 | /* see if there's a matching key we can displace */ |
780 | lru = -1; | ||
781 | if (klist && klist->nkeys > 0) { | 742 | if (klist && klist->nkeys > 0) { |
782 | lowest_lru = TIME_T_MAX; | ||
783 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 743 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
784 | struct key *key = rcu_deref_link_locked(klist, loop, | 744 | if (klist->keys[loop]->type == type && |
785 | keyring); | 745 | strcmp(klist->keys[loop]->description, |
786 | if (key->type == type && | 746 | description) == 0 |
787 | strcmp(key->description, description) == 0) { | 747 | ) { |
788 | /* Found a match - we'll replace the link with | 748 | /* found a match - we'll replace this one with |
789 | * one to the new key. We record the slot | 749 | * the new key */ |
790 | * position. | 750 | size = sizeof(struct key *) * klist->maxkeys; |
791 | */ | 751 | size += sizeof(*klist); |
792 | klist->delkey = loop; | 752 | BUG_ON(size > PAGE_SIZE); |
793 | prealloc = 0; | 753 | |
754 | ret = -ENOMEM; | ||
755 | nklist = kmemdup(klist, size, GFP_KERNEL); | ||
756 | if (!nklist) | ||
757 | goto error_sem; | ||
758 | |||
759 | /* note replacement slot */ | ||
760 | klist->delkey = nklist->delkey = loop; | ||
761 | prealloc = (unsigned long)nklist; | ||
794 | goto done; | 762 | goto done; |
795 | } | 763 | } |
796 | if (key->last_used_at < lowest_lru) { | ||
797 | lowest_lru = key->last_used_at; | ||
798 | lru = loop; | ||
799 | } | ||
800 | } | 764 | } |
801 | } | 765 | } |
802 | 766 | ||
803 | /* If the keyring is full then do an LRU discard */ | ||
804 | if (klist && | ||
805 | klist->nkeys == klist->maxkeys && | ||
806 | klist->maxkeys >= MAX_KEYRING_LINKS) { | ||
807 | kdebug("LRU discard %d\n", lru); | ||
808 | klist->delkey = lru; | ||
809 | prealloc = 0; | ||
810 | goto done; | ||
811 | } | ||
812 | |||
813 | /* check that we aren't going to overrun the user's quota */ | 767 | /* check that we aren't going to overrun the user's quota */ |
814 | ret = key_payload_reserve(keyring, | 768 | ret = key_payload_reserve(keyring, |
815 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 769 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -818,19 +772,20 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
818 | 772 | ||
819 | if (klist && klist->nkeys < klist->maxkeys) { | 773 | if (klist && klist->nkeys < klist->maxkeys) { |
820 | /* there's sufficient slack space to append directly */ | 774 | /* there's sufficient slack space to append directly */ |
821 | klist->delkey = klist->nkeys; | 775 | nklist = NULL; |
822 | prealloc = KEY_LINK_FIXQUOTA; | 776 | prealloc = KEY_LINK_FIXQUOTA; |
823 | } else { | 777 | } else { |
824 | /* grow the key list */ | 778 | /* grow the key list */ |
825 | max = 4; | 779 | max = 4; |
826 | if (klist) { | 780 | if (klist) |
827 | max += klist->maxkeys; | 781 | max += klist->maxkeys; |
828 | if (max > MAX_KEYRING_LINKS) | ||
829 | max = MAX_KEYRING_LINKS; | ||
830 | BUG_ON(max <= klist->maxkeys); | ||
831 | } | ||
832 | 782 | ||
783 | ret = -ENFILE; | ||
784 | if (max > USHRT_MAX - 1) | ||
785 | goto error_quota; | ||
833 | size = sizeof(*klist) + sizeof(struct key *) * max; | 786 | size = sizeof(*klist) + sizeof(struct key *) * max; |
787 | if (size > PAGE_SIZE) | ||
788 | goto error_quota; | ||
834 | 789 | ||
835 | ret = -ENOMEM; | 790 | ret = -ENOMEM; |
836 | nklist = kmalloc(size, GFP_KERNEL); | 791 | nklist = kmalloc(size, GFP_KERNEL); |
@@ -850,10 +805,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
850 | } | 805 | } |
851 | 806 | ||
852 | /* add the key into the new space */ | 807 | /* add the key into the new space */ |
853 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); | 808 | nklist->keys[nklist->delkey] = NULL; |
854 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
855 | } | 809 | } |
856 | 810 | ||
811 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
857 | done: | 812 | done: |
858 | *_prealloc = prealloc; | 813 | *_prealloc = prealloc; |
859 | kleave(" = 0"); | 814 | kleave(" = 0"); |
@@ -899,26 +854,24 @@ void __key_link(struct key *keyring, struct key *key, | |||
899 | unsigned long *_prealloc) | 854 | unsigned long *_prealloc) |
900 | { | 855 | { |
901 | struct keyring_list *klist, *nklist; | 856 | struct keyring_list *klist, *nklist; |
902 | struct key *discard; | ||
903 | 857 | ||
904 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | 858 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
905 | *_prealloc = 0; | 859 | *_prealloc = 0; |
906 | 860 | ||
907 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); | 861 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); |
908 | 862 | ||
909 | klist = rcu_dereference_locked_keyring(keyring); | 863 | klist = rcu_dereference_protected(keyring->payload.subscriptions, |
864 | rwsem_is_locked(&keyring->sem)); | ||
910 | 865 | ||
911 | atomic_inc(&key->usage); | 866 | atomic_inc(&key->usage); |
912 | keyring->last_used_at = key->last_used_at = | ||
913 | current_kernel_time().tv_sec; | ||
914 | 867 | ||
915 | /* there's a matching key we can displace or an empty slot in a newly | 868 | /* there's a matching key we can displace or an empty slot in a newly |
916 | * allocated list we can fill */ | 869 | * allocated list we can fill */ |
917 | if (nklist) { | 870 | if (nklist) { |
918 | kdebug("reissue %hu/%hu/%hu", | 871 | kdebug("replace %hu/%hu/%hu", |
919 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | 872 | nklist->delkey, nklist->nkeys, nklist->maxkeys); |
920 | 873 | ||
921 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); | 874 | nklist->keys[nklist->delkey] = key; |
922 | 875 | ||
923 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | 876 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
924 | 877 | ||
@@ -929,23 +882,9 @@ void __key_link(struct key *keyring, struct key *key, | |||
929 | klist->delkey, klist->nkeys, klist->maxkeys); | 882 | klist->delkey, klist->nkeys, klist->maxkeys); |
930 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | 883 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
931 | } | 884 | } |
932 | } else if (klist->delkey < klist->nkeys) { | ||
933 | kdebug("replace %hu/%hu/%hu", | ||
934 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
935 | |||
936 | discard = rcu_dereference_protected( | ||
937 | klist->keys[klist->delkey], | ||
938 | rwsem_is_locked(&keyring->sem)); | ||
939 | rcu_assign_pointer(klist->keys[klist->delkey], key); | ||
940 | /* The garbage collector will take care of RCU | ||
941 | * synchronisation */ | ||
942 | key_put(discard); | ||
943 | } else { | 885 | } else { |
944 | /* there's sufficient slack space to append directly */ | 886 | /* there's sufficient slack space to append directly */ |
945 | kdebug("append %hu/%hu/%hu", | 887 | klist->keys[klist->nkeys] = key; |
946 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
947 | |||
948 | RCU_INIT_POINTER(klist->keys[klist->delkey], key); | ||
949 | smp_wmb(); | 888 | smp_wmb(); |
950 | klist->nkeys++; | 889 | klist->nkeys++; |
951 | } | 890 | } |
@@ -959,7 +898,6 @@ void __key_link(struct key *keyring, struct key *key, | |||
959 | void __key_link_end(struct key *keyring, struct key_type *type, | 898 | void __key_link_end(struct key *keyring, struct key_type *type, |
960 | unsigned long prealloc) | 899 | unsigned long prealloc) |
961 | __releases(&keyring->sem) | 900 | __releases(&keyring->sem) |
962 | __releases(&keyring_serialise_link_sem) | ||
963 | { | 901 | { |
964 | BUG_ON(type == NULL); | 902 | BUG_ON(type == NULL); |
965 | BUG_ON(type->name == NULL); | 903 | BUG_ON(type->name == NULL); |
@@ -1053,7 +991,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
1053 | if (klist) { | 991 | if (klist) { |
1054 | /* search the keyring for the key */ | 992 | /* search the keyring for the key */ |
1055 | for (loop = 0; loop < klist->nkeys; loop++) | 993 | for (loop = 0; loop < klist->nkeys; loop++) |
1056 | if (rcu_access_pointer(klist->keys[loop]) == key) | 994 | if (klist->keys[loop] == key) |
1057 | goto key_is_present; | 995 | goto key_is_present; |
1058 | } | 996 | } |
1059 | 997 | ||
@@ -1116,7 +1054,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | |||
1116 | klist = container_of(rcu, struct keyring_list, rcu); | 1054 | klist = container_of(rcu, struct keyring_list, rcu); |
1117 | 1055 | ||
1118 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1056 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1119 | key_put(rcu_access_pointer(klist->keys[loop])); | 1057 | key_put(klist->keys[loop]); |
1120 | 1058 | ||
1121 | kfree(klist); | 1059 | kfree(klist); |
1122 | } | 1060 | } |
@@ -1183,6 +1121,15 @@ static void keyring_revoke(struct key *keyring) | |||
1183 | } | 1121 | } |
1184 | 1122 | ||
1185 | /* | 1123 | /* |
1124 | * Determine whether a key is dead. | ||
1125 | */ | ||
1126 | static bool key_is_dead(struct key *key, time_t limit) | ||
1127 | { | ||
1128 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1129 | (key->expiry > 0 && key->expiry <= limit); | ||
1130 | } | ||
1131 | |||
1132 | /* | ||
1186 | * Collect garbage from the contents of a keyring, replacing the old list with | 1133 | * Collect garbage from the contents of a keyring, replacing the old list with |
1187 | * a new one with the pointers all shuffled down. | 1134 | * a new one with the pointers all shuffled down. |
1188 | * | 1135 | * |
@@ -1207,8 +1154,7 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1207 | /* work out how many subscriptions we're keeping */ | 1154 | /* work out how many subscriptions we're keeping */ |
1208 | keep = 0; | 1155 | keep = 0; |
1209 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1156 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1210 | if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), | 1157 | if (!key_is_dead(klist->keys[loop], limit)) |
1211 | limit)) | ||
1212 | keep++; | 1158 | keep++; |
1213 | 1159 | ||
1214 | if (keep == klist->nkeys) | 1160 | if (keep == klist->nkeys) |
@@ -1229,11 +1175,11 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1229 | */ | 1175 | */ |
1230 | keep = 0; | 1176 | keep = 0; |
1231 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 1177 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
1232 | key = rcu_deref_link_locked(klist, loop, keyring); | 1178 | key = klist->keys[loop]; |
1233 | if (!key_is_dead(key, limit)) { | 1179 | if (!key_is_dead(key, limit)) { |
1234 | if (keep >= max) | 1180 | if (keep >= max) |
1235 | goto discard_new; | 1181 | goto discard_new; |
1236 | RCU_INIT_POINTER(new->keys[keep++], key_get(key)); | 1182 | new->keys[keep++] = key_get(key); |
1237 | } | 1183 | } |
1238 | } | 1184 | } |
1239 | new->nkeys = keep; | 1185 | new->nkeys = keep; |