diff options
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 245 |
1 files changed, 148 insertions, 97 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e2ab4f8e7481..c9a5de197487 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -132,10 +132,17 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); | 132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); |
133 | 133 | ||
134 | ret = 0; | 134 | ret = 0; |
135 | sklist = source->payload.subscriptions; | ||
136 | 135 | ||
137 | if (sklist && sklist->nkeys > 0) { | 136 | /* find out how many keys are currently linked */ |
137 | rcu_read_lock(); | ||
138 | sklist = rcu_dereference(source->payload.subscriptions); | ||
139 | max = 0; | ||
140 | if (sklist) | ||
138 | max = sklist->nkeys; | 141 | max = sklist->nkeys; |
142 | rcu_read_unlock(); | ||
143 | |||
144 | /* allocate a new payload and stuff load with key links */ | ||
145 | if (max > 0) { | ||
139 | BUG_ON(max > limit); | 146 | BUG_ON(max > limit); |
140 | 147 | ||
141 | max = (max + 3) & ~3; | 148 | max = (max + 3) & ~3; |
@@ -148,6 +155,10 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
148 | if (!klist) | 155 | if (!klist) |
149 | goto error; | 156 | goto error; |
150 | 157 | ||
158 | /* set links */ | ||
159 | rcu_read_lock(); | ||
160 | sklist = rcu_dereference(source->payload.subscriptions); | ||
161 | |||
151 | klist->maxkeys = max; | 162 | klist->maxkeys = max; |
152 | klist->nkeys = sklist->nkeys; | 163 | klist->nkeys = sklist->nkeys; |
153 | memcpy(klist->keys, | 164 | memcpy(klist->keys, |
@@ -157,7 +168,9 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
157 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 168 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
158 | atomic_inc(&klist->keys[loop]->usage); | 169 | atomic_inc(&klist->keys[loop]->usage); |
159 | 170 | ||
160 | keyring->payload.subscriptions = klist; | 171 | rcu_read_unlock(); |
172 | |||
173 | rcu_assign_pointer(keyring->payload.subscriptions, klist); | ||
161 | ret = 0; | 174 | ret = 0; |
162 | } | 175 | } |
163 | 176 | ||
@@ -192,7 +205,7 @@ static void keyring_destroy(struct key *keyring) | |||
192 | write_unlock(&keyring_name_lock); | 205 | write_unlock(&keyring_name_lock); |
193 | } | 206 | } |
194 | 207 | ||
195 | klist = keyring->payload.subscriptions; | 208 | klist = rcu_dereference(keyring->payload.subscriptions); |
196 | if (klist) { | 209 | if (klist) { |
197 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 210 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
198 | key_put(klist->keys[loop]); | 211 | key_put(klist->keys[loop]); |
@@ -216,17 +229,20 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) | |||
216 | seq_puts(m, "[anon]"); | 229 | seq_puts(m, "[anon]"); |
217 | } | 230 | } |
218 | 231 | ||
219 | klist = keyring->payload.subscriptions; | 232 | rcu_read_lock(); |
233 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
220 | if (klist) | 234 | if (klist) |
221 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); | 235 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); |
222 | else | 236 | else |
223 | seq_puts(m, ": empty"); | 237 | seq_puts(m, ": empty"); |
238 | rcu_read_unlock(); | ||
224 | 239 | ||
225 | } /* end keyring_describe() */ | 240 | } /* end keyring_describe() */ |
226 | 241 | ||
227 | /*****************************************************************************/ | 242 | /*****************************************************************************/ |
228 | /* | 243 | /* |
229 | * read a list of key IDs from the keyring's contents | 244 | * read a list of key IDs from the keyring's contents |
245 | * - the keyring's semaphore is read-locked | ||
230 | */ | 246 | */ |
231 | static long keyring_read(const struct key *keyring, | 247 | static long keyring_read(const struct key *keyring, |
232 | char __user *buffer, size_t buflen) | 248 | char __user *buffer, size_t buflen) |
@@ -237,7 +253,7 @@ static long keyring_read(const struct key *keyring, | |||
237 | int loop, ret; | 253 | int loop, ret; |
238 | 254 | ||
239 | ret = 0; | 255 | ret = 0; |
240 | klist = keyring->payload.subscriptions; | 256 | klist = rcu_dereference(keyring->payload.subscriptions); |
241 | 257 | ||
242 | if (klist) { | 258 | if (klist) { |
243 | /* calculate how much data we could return */ | 259 | /* calculate how much data we could return */ |
@@ -320,7 +336,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
320 | key_match_func_t match) | 336 | key_match_func_t match) |
321 | { | 337 | { |
322 | struct { | 338 | struct { |
323 | struct key *keyring; | 339 | struct keyring_list *keylist; |
324 | int kix; | 340 | int kix; |
325 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 341 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
326 | 342 | ||
@@ -328,10 +344,12 @@ struct key *keyring_search_aux(struct key *keyring, | |||
328 | struct timespec now; | 344 | struct timespec now; |
329 | struct key *key; | 345 | struct key *key; |
330 | long err; | 346 | long err; |
331 | int sp, psp, kix; | 347 | int sp, kix; |
332 | 348 | ||
333 | key_check(keyring); | 349 | key_check(keyring); |
334 | 350 | ||
351 | rcu_read_lock(); | ||
352 | |||
335 | /* top keyring must have search permission to begin the search */ | 353 | /* top keyring must have search permission to begin the search */ |
336 | key = ERR_PTR(-EACCES); | 354 | key = ERR_PTR(-EACCES); |
337 | if (!key_permission(keyring, KEY_SEARCH)) | 355 | if (!key_permission(keyring, KEY_SEARCH)) |
@@ -347,11 +365,10 @@ struct key *keyring_search_aux(struct key *keyring, | |||
347 | 365 | ||
348 | /* start processing a new keyring */ | 366 | /* start processing a new keyring */ |
349 | descend: | 367 | descend: |
350 | read_lock(&keyring->lock); | 368 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
351 | if (keyring->flags & KEY_FLAG_REVOKED) | ||
352 | goto not_this_keyring; | 369 | goto not_this_keyring; |
353 | 370 | ||
354 | keylist = keyring->payload.subscriptions; | 371 | keylist = rcu_dereference(keyring->payload.subscriptions); |
355 | if (!keylist) | 372 | if (!keylist) |
356 | goto not_this_keyring; | 373 | goto not_this_keyring; |
357 | 374 | ||
@@ -364,7 +381,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
364 | continue; | 381 | continue; |
365 | 382 | ||
366 | /* skip revoked keys and expired keys */ | 383 | /* skip revoked keys and expired keys */ |
367 | if (key->flags & KEY_FLAG_REVOKED) | 384 | if (test_bit(KEY_FLAG_REVOKED, &key->flags)) |
368 | continue; | 385 | continue; |
369 | 386 | ||
370 | if (key->expiry && now.tv_sec >= key->expiry) | 387 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -379,7 +396,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
379 | continue; | 396 | continue; |
380 | 397 | ||
381 | /* we set a different error code if we find a negative key */ | 398 | /* we set a different error code if we find a negative key */ |
382 | if (key->flags & KEY_FLAG_NEGATIVE) { | 399 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
383 | err = -ENOKEY; | 400 | err = -ENOKEY; |
384 | continue; | 401 | continue; |
385 | } | 402 | } |
@@ -390,48 +407,37 @@ struct key *keyring_search_aux(struct key *keyring, | |||
390 | /* search through the keyrings nested in this one */ | 407 | /* search through the keyrings nested in this one */ |
391 | kix = 0; | 408 | kix = 0; |
392 | ascend: | 409 | ascend: |
393 | while (kix < keylist->nkeys) { | 410 | for (; kix < keylist->nkeys; kix++) { |
394 | key = keylist->keys[kix]; | 411 | key = keylist->keys[kix]; |
395 | if (key->type != &key_type_keyring) | 412 | if (key->type != &key_type_keyring) |
396 | goto next; | 413 | continue; |
397 | 414 | ||
398 | /* recursively search nested keyrings | 415 | /* recursively search nested keyrings |
399 | * - only search keyrings for which we have search permission | 416 | * - only search keyrings for which we have search permission |
400 | */ | 417 | */ |
401 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) | 418 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) |
402 | goto next; | 419 | continue; |
403 | 420 | ||
404 | if (!key_permission(key, KEY_SEARCH)) | 421 | if (!key_permission(key, KEY_SEARCH)) |
405 | goto next; | 422 | continue; |
406 | |||
407 | /* evade loops in the keyring tree */ | ||
408 | for (psp = 0; psp < sp; psp++) | ||
409 | if (stack[psp].keyring == keyring) | ||
410 | goto next; | ||
411 | 423 | ||
412 | /* stack the current position */ | 424 | /* stack the current position */ |
413 | stack[sp].keyring = keyring; | 425 | stack[sp].keylist = keylist; |
414 | stack[sp].kix = kix; | 426 | stack[sp].kix = kix; |
415 | sp++; | 427 | sp++; |
416 | 428 | ||
417 | /* begin again with the new keyring */ | 429 | /* begin again with the new keyring */ |
418 | keyring = key; | 430 | keyring = key; |
419 | goto descend; | 431 | goto descend; |
420 | |||
421 | next: | ||
422 | kix++; | ||
423 | } | 432 | } |
424 | 433 | ||
425 | /* the keyring we're looking at was disqualified or didn't contain a | 434 | /* the keyring we're looking at was disqualified or didn't contain a |
426 | * matching key */ | 435 | * matching key */ |
427 | not_this_keyring: | 436 | not_this_keyring: |
428 | read_unlock(&keyring->lock); | ||
429 | |||
430 | if (sp > 0) { | 437 | if (sp > 0) { |
431 | /* resume the processing of a keyring higher up in the tree */ | 438 | /* resume the processing of a keyring higher up in the tree */ |
432 | sp--; | 439 | sp--; |
433 | keyring = stack[sp].keyring; | 440 | keylist = stack[sp].keylist; |
434 | keylist = keyring->payload.subscriptions; | ||
435 | kix = stack[sp].kix + 1; | 441 | kix = stack[sp].kix + 1; |
436 | goto ascend; | 442 | goto ascend; |
437 | } | 443 | } |
@@ -442,16 +448,9 @@ struct key *keyring_search_aux(struct key *keyring, | |||
442 | /* we found a viable match */ | 448 | /* we found a viable match */ |
443 | found: | 449 | found: |
444 | atomic_inc(&key->usage); | 450 | atomic_inc(&key->usage); |
445 | read_unlock(&keyring->lock); | ||
446 | |||
447 | /* unwind the keyring stack */ | ||
448 | while (sp > 0) { | ||
449 | sp--; | ||
450 | read_unlock(&stack[sp].keyring->lock); | ||
451 | } | ||
452 | |||
453 | key_check(key); | 451 | key_check(key); |
454 | error: | 452 | error: |
453 | rcu_read_unlock(); | ||
455 | return key; | 454 | return key; |
456 | 455 | ||
457 | } /* end keyring_search_aux() */ | 456 | } /* end keyring_search_aux() */ |
@@ -489,7 +488,9 @@ struct key *__keyring_search_one(struct key *keyring, | |||
489 | struct key *key; | 488 | struct key *key; |
490 | int loop; | 489 | int loop; |
491 | 490 | ||
492 | klist = keyring->payload.subscriptions; | 491 | rcu_read_lock(); |
492 | |||
493 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
493 | if (klist) { | 494 | if (klist) { |
494 | for (loop = 0; loop < klist->nkeys; loop++) { | 495 | for (loop = 0; loop < klist->nkeys; loop++) { |
495 | key = klist->keys[loop]; | 496 | key = klist->keys[loop]; |
@@ -497,7 +498,7 @@ struct key *__keyring_search_one(struct key *keyring, | |||
497 | if (key->type == ktype && | 498 | if (key->type == ktype && |
498 | key->type->match(key, description) && | 499 | key->type->match(key, description) && |
499 | key_permission(key, perm) && | 500 | key_permission(key, perm) && |
500 | !(key->flags & KEY_FLAG_REVOKED) | 501 | !test_bit(KEY_FLAG_REVOKED, &key->flags) |
501 | ) | 502 | ) |
502 | goto found; | 503 | goto found; |
503 | } | 504 | } |
@@ -509,6 +510,7 @@ struct key *__keyring_search_one(struct key *keyring, | |||
509 | found: | 510 | found: |
510 | atomic_inc(&key->usage); | 511 | atomic_inc(&key->usage); |
511 | error: | 512 | error: |
513 | rcu_read_unlock(); | ||
512 | return key; | 514 | return key; |
513 | 515 | ||
514 | } /* end __keyring_search_one() */ | 516 | } /* end __keyring_search_one() */ |
@@ -540,7 +542,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
540 | &keyring_name_hash[bucket], | 542 | &keyring_name_hash[bucket], |
541 | type_data.link | 543 | type_data.link |
542 | ) { | 544 | ) { |
543 | if (keyring->flags & KEY_FLAG_REVOKED) | 545 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
544 | continue; | 546 | continue; |
545 | 547 | ||
546 | if (strcmp(keyring->description, name) != 0) | 548 | if (strcmp(keyring->description, name) != 0) |
@@ -579,7 +581,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
579 | static int keyring_detect_cycle(struct key *A, struct key *B) | 581 | static int keyring_detect_cycle(struct key *A, struct key *B) |
580 | { | 582 | { |
581 | struct { | 583 | struct { |
582 | struct key *subtree; | 584 | struct keyring_list *keylist; |
583 | int kix; | 585 | int kix; |
584 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 586 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
585 | 587 | ||
@@ -587,20 +589,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
587 | struct key *subtree, *key; | 589 | struct key *subtree, *key; |
588 | int sp, kix, ret; | 590 | int sp, kix, ret; |
589 | 591 | ||
592 | rcu_read_lock(); | ||
593 | |||
590 | ret = -EDEADLK; | 594 | ret = -EDEADLK; |
591 | if (A == B) | 595 | if (A == B) |
592 | goto error; | 596 | goto cycle_detected; |
593 | 597 | ||
594 | subtree = B; | 598 | subtree = B; |
595 | sp = 0; | 599 | sp = 0; |
596 | 600 | ||
597 | /* start processing a new keyring */ | 601 | /* start processing a new keyring */ |
598 | descend: | 602 | descend: |
599 | read_lock(&subtree->lock); | 603 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
600 | if (subtree->flags & KEY_FLAG_REVOKED) | ||
601 | goto not_this_keyring; | 604 | goto not_this_keyring; |
602 | 605 | ||
603 | keylist = subtree->payload.subscriptions; | 606 | keylist = rcu_dereference(subtree->payload.subscriptions); |
604 | if (!keylist) | 607 | if (!keylist) |
605 | goto not_this_keyring; | 608 | goto not_this_keyring; |
606 | kix = 0; | 609 | kix = 0; |
@@ -619,7 +622,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
619 | goto too_deep; | 622 | goto too_deep; |
620 | 623 | ||
621 | /* stack the current position */ | 624 | /* stack the current position */ |
622 | stack[sp].subtree = subtree; | 625 | stack[sp].keylist = keylist; |
623 | stack[sp].kix = kix; | 626 | stack[sp].kix = kix; |
624 | sp++; | 627 | sp++; |
625 | 628 | ||
@@ -632,13 +635,10 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
632 | /* the keyring we're looking at was disqualified or didn't contain a | 635 | /* the keyring we're looking at was disqualified or didn't contain a |
633 | * matching key */ | 636 | * matching key */ |
634 | not_this_keyring: | 637 | not_this_keyring: |
635 | read_unlock(&subtree->lock); | ||
636 | |||
637 | if (sp > 0) { | 638 | if (sp > 0) { |
638 | /* resume the checking of a keyring higher up in the tree */ | 639 | /* resume the checking of a keyring higher up in the tree */ |
639 | sp--; | 640 | sp--; |
640 | subtree = stack[sp].subtree; | 641 | keylist = stack[sp].keylist; |
641 | keylist = subtree->payload.subscriptions; | ||
642 | kix = stack[sp].kix + 1; | 642 | kix = stack[sp].kix + 1; |
643 | goto ascend; | 643 | goto ascend; |
644 | } | 644 | } |
@@ -646,30 +646,36 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
646 | ret = 0; /* no cycles detected */ | 646 | ret = 0; /* no cycles detected */ |
647 | 647 | ||
648 | error: | 648 | error: |
649 | rcu_read_unlock(); | ||
649 | return ret; | 650 | return ret; |
650 | 651 | ||
651 | too_deep: | 652 | too_deep: |
652 | ret = -ELOOP; | 653 | ret = -ELOOP; |
653 | goto error_unwind; | 654 | goto error; |
655 | |||
654 | cycle_detected: | 656 | cycle_detected: |
655 | ret = -EDEADLK; | 657 | ret = -EDEADLK; |
656 | error_unwind: | ||
657 | read_unlock(&subtree->lock); | ||
658 | |||
659 | /* unwind the keyring stack */ | ||
660 | while (sp > 0) { | ||
661 | sp--; | ||
662 | read_unlock(&stack[sp].subtree->lock); | ||
663 | } | ||
664 | |||
665 | goto error; | 658 | goto error; |
666 | 659 | ||
667 | } /* end keyring_detect_cycle() */ | 660 | } /* end keyring_detect_cycle() */ |
668 | 661 | ||
669 | /*****************************************************************************/ | 662 | /*****************************************************************************/ |
670 | /* | 663 | /* |
664 | * dispose of a keyring list after the RCU grace period | ||
665 | */ | ||
666 | static void keyring_link_rcu_disposal(struct rcu_head *rcu) | ||
667 | { | ||
668 | struct keyring_list *klist = | ||
669 | container_of(rcu, struct keyring_list, rcu); | ||
670 | |||
671 | kfree(klist); | ||
672 | |||
673 | } /* end keyring_link_rcu_disposal() */ | ||
674 | |||
675 | /*****************************************************************************/ | ||
676 | /* | ||
671 | * link a key into to a keyring | 677 | * link a key into to a keyring |
672 | * - must be called with the keyring's semaphore held | 678 | * - must be called with the keyring's semaphore write-locked |
673 | */ | 679 | */ |
674 | int __key_link(struct key *keyring, struct key *key) | 680 | int __key_link(struct key *keyring, struct key *key) |
675 | { | 681 | { |
@@ -679,7 +685,7 @@ int __key_link(struct key *keyring, struct key *key) | |||
679 | int ret; | 685 | int ret; |
680 | 686 | ||
681 | ret = -EKEYREVOKED; | 687 | ret = -EKEYREVOKED; |
682 | if (keyring->flags & KEY_FLAG_REVOKED) | 688 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
683 | goto error; | 689 | goto error; |
684 | 690 | ||
685 | ret = -ENOTDIR; | 691 | ret = -ENOTDIR; |
@@ -710,9 +716,10 @@ int __key_link(struct key *keyring, struct key *key) | |||
710 | /* there's sufficient slack space to add directly */ | 716 | /* there's sufficient slack space to add directly */ |
711 | atomic_inc(&key->usage); | 717 | atomic_inc(&key->usage); |
712 | 718 | ||
713 | write_lock(&keyring->lock); | 719 | klist->keys[klist->nkeys] = key; |
714 | klist->keys[klist->nkeys++] = key; | 720 | smp_wmb(); |
715 | write_unlock(&keyring->lock); | 721 | klist->nkeys++; |
722 | smp_wmb(); | ||
716 | 723 | ||
717 | ret = 0; | 724 | ret = 0; |
718 | } | 725 | } |
@@ -723,6 +730,8 @@ int __key_link(struct key *keyring, struct key *key) | |||
723 | max += klist->maxkeys; | 730 | max += klist->maxkeys; |
724 | 731 | ||
725 | ret = -ENFILE; | 732 | ret = -ENFILE; |
733 | if (max > 65535) | ||
734 | goto error3; | ||
726 | size = sizeof(*klist) + sizeof(*key) * max; | 735 | size = sizeof(*klist) + sizeof(*key) * max; |
727 | if (size > PAGE_SIZE) | 736 | if (size > PAGE_SIZE) |
728 | goto error3; | 737 | goto error3; |
@@ -743,14 +752,13 @@ int __key_link(struct key *keyring, struct key *key) | |||
743 | 752 | ||
744 | /* add the key into the new space */ | 753 | /* add the key into the new space */ |
745 | atomic_inc(&key->usage); | 754 | atomic_inc(&key->usage); |
746 | |||
747 | write_lock(&keyring->lock); | ||
748 | keyring->payload.subscriptions = nklist; | ||
749 | nklist->keys[nklist->nkeys++] = key; | 755 | nklist->keys[nklist->nkeys++] = key; |
750 | write_unlock(&keyring->lock); | 756 | |
757 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
751 | 758 | ||
752 | /* dispose of the old keyring list */ | 759 | /* dispose of the old keyring list */ |
753 | kfree(klist); | 760 | if (klist) |
761 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | ||
754 | 762 | ||
755 | ret = 0; | 763 | ret = 0; |
756 | } | 764 | } |
@@ -791,11 +799,26 @@ EXPORT_SYMBOL(key_link); | |||
791 | 799 | ||
792 | /*****************************************************************************/ | 800 | /*****************************************************************************/ |
793 | /* | 801 | /* |
802 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | ||
803 | * key | ||
804 | */ | ||
805 | static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | ||
806 | { | ||
807 | struct keyring_list *klist = | ||
808 | container_of(rcu, struct keyring_list, rcu); | ||
809 | |||
810 | key_put(klist->keys[klist->delkey]); | ||
811 | kfree(klist); | ||
812 | |||
813 | } /* end keyring_unlink_rcu_disposal() */ | ||
814 | |||
815 | /*****************************************************************************/ | ||
816 | /* | ||
794 | * unlink the first link to a key from a keyring | 817 | * unlink the first link to a key from a keyring |
795 | */ | 818 | */ |
796 | int key_unlink(struct key *keyring, struct key *key) | 819 | int key_unlink(struct key *keyring, struct key *key) |
797 | { | 820 | { |
798 | struct keyring_list *klist; | 821 | struct keyring_list *klist, *nklist; |
799 | int loop, ret; | 822 | int loop, ret; |
800 | 823 | ||
801 | key_check(keyring); | 824 | key_check(keyring); |
@@ -819,31 +842,45 @@ int key_unlink(struct key *keyring, struct key *key) | |||
819 | ret = -ENOENT; | 842 | ret = -ENOENT; |
820 | goto error; | 843 | goto error; |
821 | 844 | ||
822 | key_is_present: | 845 | key_is_present: |
846 | /* we need to copy the key list for RCU purposes */ | ||
847 | nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys, | ||
848 | GFP_KERNEL); | ||
849 | if (!nklist) | ||
850 | goto nomem; | ||
851 | nklist->maxkeys = klist->maxkeys; | ||
852 | nklist->nkeys = klist->nkeys - 1; | ||
853 | |||
854 | if (loop > 0) | ||
855 | memcpy(&nklist->keys[0], | ||
856 | &klist->keys[0], | ||
857 | loop * sizeof(klist->keys[0])); | ||
858 | |||
859 | if (loop < nklist->nkeys) | ||
860 | memcpy(&nklist->keys[loop], | ||
861 | &klist->keys[loop + 1], | ||
862 | (nklist->nkeys - loop) * sizeof(klist->keys[0])); | ||
863 | |||
823 | /* adjust the user's quota */ | 864 | /* adjust the user's quota */ |
824 | key_payload_reserve(keyring, | 865 | key_payload_reserve(keyring, |
825 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 866 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
826 | 867 | ||
827 | /* shuffle down the key pointers | 868 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
828 | * - it might be worth shrinking the allocated memory, but that runs | ||
829 | * the risk of ENOMEM as we would have to copy | ||
830 | */ | ||
831 | write_lock(&keyring->lock); | ||
832 | 869 | ||
833 | klist->nkeys--; | 870 | up_write(&keyring->sem); |
834 | if (loop < klist->nkeys) | ||
835 | memcpy(&klist->keys[loop], | ||
836 | &klist->keys[loop + 1], | ||
837 | (klist->nkeys - loop) * sizeof(struct key *)); | ||
838 | 871 | ||
839 | write_unlock(&keyring->lock); | 872 | /* schedule for later cleanup */ |
873 | klist->delkey = loop; | ||
874 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | ||
840 | 875 | ||
841 | up_write(&keyring->sem); | ||
842 | key_put(key); | ||
843 | ret = 0; | 876 | ret = 0; |
844 | 877 | ||
845 | error: | 878 | error: |
846 | return ret; | 879 | return ret; |
880 | nomem: | ||
881 | ret = -ENOMEM; | ||
882 | up_write(&keyring->sem); | ||
883 | goto error; | ||
847 | 884 | ||
848 | } /* end key_unlink() */ | 885 | } /* end key_unlink() */ |
849 | 886 | ||
@@ -851,13 +888,32 @@ EXPORT_SYMBOL(key_unlink); | |||
851 | 888 | ||
852 | /*****************************************************************************/ | 889 | /*****************************************************************************/ |
853 | /* | 890 | /* |
891 | * dispose of a keyring list after the RCU grace period, releasing the keys it | ||
892 | * links to | ||
893 | */ | ||
894 | static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | ||
895 | { | ||
896 | struct keyring_list *klist; | ||
897 | int loop; | ||
898 | |||
899 | klist = container_of(rcu, struct keyring_list, rcu); | ||
900 | |||
901 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | ||
902 | key_put(klist->keys[loop]); | ||
903 | |||
904 | kfree(klist); | ||
905 | |||
906 | } /* end keyring_clear_rcu_disposal() */ | ||
907 | |||
908 | /*****************************************************************************/ | ||
909 | /* | ||
854 | * clear the specified process keyring | 910 | * clear the specified process keyring |
855 | * - implements keyctl(KEYCTL_CLEAR) | 911 | * - implements keyctl(KEYCTL_CLEAR) |
856 | */ | 912 | */ |
857 | int keyring_clear(struct key *keyring) | 913 | int keyring_clear(struct key *keyring) |
858 | { | 914 | { |
859 | struct keyring_list *klist; | 915 | struct keyring_list *klist; |
860 | int loop, ret; | 916 | int ret; |
861 | 917 | ||
862 | ret = -ENOTDIR; | 918 | ret = -ENOTDIR; |
863 | if (keyring->type == &key_type_keyring) { | 919 | if (keyring->type == &key_type_keyring) { |
@@ -870,20 +926,15 @@ int keyring_clear(struct key *keyring) | |||
870 | key_payload_reserve(keyring, | 926 | key_payload_reserve(keyring, |
871 | sizeof(struct keyring_list)); | 927 | sizeof(struct keyring_list)); |
872 | 928 | ||
873 | write_lock(&keyring->lock); | 929 | rcu_assign_pointer(keyring->payload.subscriptions, |
874 | keyring->payload.subscriptions = NULL; | 930 | NULL); |
875 | write_unlock(&keyring->lock); | ||
876 | } | 931 | } |
877 | 932 | ||
878 | up_write(&keyring->sem); | 933 | up_write(&keyring->sem); |
879 | 934 | ||
880 | /* free the keys after the locks have been dropped */ | 935 | /* free the keys after the locks have been dropped */ |
881 | if (klist) { | 936 | if (klist) |
882 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 937 | call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
883 | key_put(klist->keys[loop]); | ||
884 | |||
885 | kfree(klist); | ||
886 | } | ||
887 | 938 | ||
888 | ret = 0; | 939 | ret = 0; |
889 | } | 940 | } |