aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/key.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2005-06-24 01:00:49 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:05:18 -0400
commit76d8aeabfeb1c42641a81c44280177b9a08670d8 (patch)
tree0a584439bb44e440717aa77a1398ba9eea24a137 /security/keys/key.c
parent7286aa9b9ab35f20b1ff16d867f4535701df99b5 (diff)
[PATCH] keys: Discard key spinlock and use RCU for key payload
The attached patch changes the key implementation in a number of ways: (1) It removes the spinlock from the key structure. (2) The key flags are now accessed using atomic bitops instead of write-locking the key spinlock and using C bitwise operators. The three instantiation flags are dealt with with the construction semaphore held during the request_key/instantiate/negate sequence, thus rendering the spinlock superfluous. The key flags are also now bit numbers not bit masks. (3) The key payload is now accessed using RCU. This permits the recursive keyring search algorithm to be simplified greatly since no locks need be taken other than the usual RCU preemption disablement. Searching now does not require any locks or semaphores to be held; merely that the starting keyring be pinned. (4) The keyring payload now includes an RCU head so that it can be disposed of by call_rcu(). This requires that the payload be copied on unlink to prevent introducing races in copy-down vs search-up. (5) The user key payload is now a structure with the data following it. It includes an RCU head like the keyring payload and for the same reason. It also contains a data length because the data length in the key may be changed on another CPU whilst an RCU protected read is in progress on the payload. This would then see the supposed RCU payload and the on-key data length getting out of sync. I'm tempted to drop the key's datalen entirely, except that it's used in conjunction with quota management and so is a little tricky to get rid of. (6) Update the keys documentation. Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/keys/key.c')
-rw-r--r--security/keys/key.c94
1 files changed, 42 insertions, 52 deletions
diff --git a/security/keys/key.c b/security/keys/key.c
index 59402c843203..1fdfccb3fe43 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -294,7 +294,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
294 } 294 }
295 295
296 atomic_set(&key->usage, 1); 296 atomic_set(&key->usage, 1);
297 rwlock_init(&key->lock);
298 init_rwsem(&key->sem); 297 init_rwsem(&key->sem);
299 key->type = type; 298 key->type = type;
300 key->user = user; 299 key->user = user;
@@ -308,7 +307,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
308 key->payload.data = NULL; 307 key->payload.data = NULL;
309 308
310 if (!not_in_quota) 309 if (!not_in_quota)
311 key->flags |= KEY_FLAG_IN_QUOTA; 310 key->flags |= 1 << KEY_FLAG_IN_QUOTA;
312 311
313 memset(&key->type_data, 0, sizeof(key->type_data)); 312 memset(&key->type_data, 0, sizeof(key->type_data));
314 313
@@ -359,7 +358,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
359 key_check(key); 358 key_check(key);
360 359
361 /* contemplate the quota adjustment */ 360 /* contemplate the quota adjustment */
362 if (delta != 0 && key->flags & KEY_FLAG_IN_QUOTA) { 361 if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
363 spin_lock(&key->user->lock); 362 spin_lock(&key->user->lock);
364 363
365 if (delta > 0 && 364 if (delta > 0 &&
@@ -405,23 +404,17 @@ static int __key_instantiate_and_link(struct key *key,
405 down_write(&key_construction_sem); 404 down_write(&key_construction_sem);
406 405
407 /* can't instantiate twice */ 406 /* can't instantiate twice */
408 if (!(key->flags & KEY_FLAG_INSTANTIATED)) { 407 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
409 /* instantiate the key */ 408 /* instantiate the key */
410 ret = key->type->instantiate(key, data, datalen); 409 ret = key->type->instantiate(key, data, datalen);
411 410
412 if (ret == 0) { 411 if (ret == 0) {
413 /* mark the key as being instantiated */ 412 /* mark the key as being instantiated */
414 write_lock(&key->lock);
415
416 atomic_inc(&key->user->nikeys); 413 atomic_inc(&key->user->nikeys);
417 key->flags |= KEY_FLAG_INSTANTIATED; 414 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
418 415
419 if (key->flags & KEY_FLAG_USER_CONSTRUCT) { 416 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
420 key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
421 awaken = 1; 417 awaken = 1;
422 }
423
424 write_unlock(&key->lock);
425 418
426 /* and link it into the destination keyring */ 419 /* and link it into the destination keyring */
427 if (keyring) 420 if (keyring)
@@ -486,21 +479,17 @@ int key_negate_and_link(struct key *key,
486 down_write(&key_construction_sem); 479 down_write(&key_construction_sem);
487 480
488 /* can't instantiate twice */ 481 /* can't instantiate twice */
489 if (!(key->flags & KEY_FLAG_INSTANTIATED)) { 482 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
490 /* mark the key as being negatively instantiated */ 483 /* mark the key as being negatively instantiated */
491 write_lock(&key->lock);
492
493 atomic_inc(&key->user->nikeys); 484 atomic_inc(&key->user->nikeys);
494 key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; 485 set_bit(KEY_FLAG_NEGATIVE, &key->flags);
486 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
495 now = current_kernel_time(); 487 now = current_kernel_time();
496 key->expiry = now.tv_sec + timeout; 488 key->expiry = now.tv_sec + timeout;
497 489
498 if (key->flags & KEY_FLAG_USER_CONSTRUCT) { 490 if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
499 key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
500 awaken = 1; 491 awaken = 1;
501 }
502 492
503 write_unlock(&key->lock);
504 ret = 0; 493 ret = 0;
505 494
506 /* and link it into the destination keyring */ 495 /* and link it into the destination keyring */
@@ -553,8 +542,10 @@ static void key_cleanup(void *data)
553 rb_erase(&key->serial_node, &key_serial_tree); 542 rb_erase(&key->serial_node, &key_serial_tree);
554 spin_unlock(&key_serial_lock); 543 spin_unlock(&key_serial_lock);
555 544
545 key_check(key);
546
556 /* deal with the user's key tracking and quota */ 547 /* deal with the user's key tracking and quota */
557 if (key->flags & KEY_FLAG_IN_QUOTA) { 548 if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
558 spin_lock(&key->user->lock); 549 spin_lock(&key->user->lock);
559 key->user->qnkeys--; 550 key->user->qnkeys--;
560 key->user->qnbytes -= key->quotalen; 551 key->user->qnbytes -= key->quotalen;
@@ -562,7 +553,7 @@ static void key_cleanup(void *data)
562 } 553 }
563 554
564 atomic_dec(&key->user->nkeys); 555 atomic_dec(&key->user->nkeys);
565 if (key->flags & KEY_FLAG_INSTANTIATED) 556 if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
566 atomic_dec(&key->user->nikeys); 557 atomic_dec(&key->user->nikeys);
567 558
568 key_user_put(key->user); 559 key_user_put(key->user);
@@ -631,9 +622,9 @@ struct key *key_lookup(key_serial_t id)
631 goto error; 622 goto error;
632 623
633 found: 624 found:
634 /* pretent doesn't exist if it's dead */ 625 /* pretend it doesn't exist if it's dead */
635 if (atomic_read(&key->usage) == 0 || 626 if (atomic_read(&key->usage) == 0 ||
636 (key->flags & KEY_FLAG_DEAD) || 627 test_bit(KEY_FLAG_DEAD, &key->flags) ||
637 key->type == &key_type_dead) 628 key->type == &key_type_dead)
638 goto not_found; 629 goto not_found;
639 630
@@ -708,12 +699,9 @@ static inline struct key *__key_update(struct key *key, const void *payload,
708 699
709 ret = key->type->update(key, payload, plen); 700 ret = key->type->update(key, payload, plen);
710 701
711 if (ret == 0) { 702 if (ret == 0)
712 /* updating a negative key instantiates it */ 703 /* updating a negative key instantiates it */
713 write_lock(&key->lock); 704 clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
714 key->flags &= ~KEY_FLAG_NEGATIVE;
715 write_unlock(&key->lock);
716 }
717 705
718 up_write(&key->sem); 706 up_write(&key->sem);
719 707
@@ -841,12 +829,9 @@ int key_update(struct key *key, const void *payload, size_t plen)
841 down_write(&key->sem); 829 down_write(&key->sem);
842 ret = key->type->update(key, payload, plen); 830 ret = key->type->update(key, payload, plen);
843 831
844 if (ret == 0) { 832 if (ret == 0)
845 /* updating a negative key instantiates it */ 833 /* updating a negative key instantiates it */
846 write_lock(&key->lock); 834 clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
847 key->flags &= ~KEY_FLAG_NEGATIVE;
848 write_unlock(&key->lock);
849 }
850 835
851 up_write(&key->sem); 836 up_write(&key->sem);
852 } 837 }
@@ -892,10 +877,7 @@ struct key *key_duplicate(struct key *source, const char *desc)
892 goto error2; 877 goto error2;
893 878
894 atomic_inc(&key->user->nikeys); 879 atomic_inc(&key->user->nikeys);
895 880 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
896 write_lock(&key->lock);
897 key->flags |= KEY_FLAG_INSTANTIATED;
898 write_unlock(&key->lock);
899 881
900 error_k: 882 error_k:
901 up_read(&key_types_sem); 883 up_read(&key_types_sem);
@@ -922,9 +904,7 @@ void key_revoke(struct key *key)
922 /* make sure no one's trying to change or use the key when we mark 904 /* make sure no one's trying to change or use the key when we mark
923 * it */ 905 * it */
924 down_write(&key->sem); 906 down_write(&key->sem);
925 write_lock(&key->lock); 907 set_bit(KEY_FLAG_REVOKED, &key->flags);
926 key->flags |= KEY_FLAG_REVOKED;
927 write_unlock(&key->lock);
928 up_write(&key->sem); 908 up_write(&key->sem);
929 909
930} /* end key_revoke() */ 910} /* end key_revoke() */
@@ -975,24 +955,33 @@ void unregister_key_type(struct key_type *ktype)
975 /* withdraw the key type */ 955 /* withdraw the key type */
976 list_del_init(&ktype->link); 956 list_del_init(&ktype->link);
977 957
978 /* need to withdraw all keys of this type */ 958 /* mark all the keys of this type dead */
979 spin_lock(&key_serial_lock); 959 spin_lock(&key_serial_lock);
980 960
981 for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { 961 for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
982 key = rb_entry(_n, struct key, serial_node); 962 key = rb_entry(_n, struct key, serial_node);
983 963
984 if (key->type != ktype) 964 if (key->type == ktype)
985 continue; 965 key->type = &key_type_dead;
966 }
967
968 spin_unlock(&key_serial_lock);
969
970 /* make sure everyone revalidates their keys */
971 synchronize_kernel();
972
973 /* we should now be able to destroy the payloads of all the keys of
974 * this type with impunity */
975 spin_lock(&key_serial_lock);
986 976
987 write_lock(&key->lock); 977 for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
988 key->type = &key_type_dead; 978 key = rb_entry(_n, struct key, serial_node);
989 write_unlock(&key->lock);
990 979
991 /* there shouldn't be anyone looking at the description or 980 if (key->type == ktype) {
992 * payload now */ 981 if (ktype->destroy)
993 if (ktype->destroy) 982 ktype->destroy(key);
994 ktype->destroy(key); 983 memset(&key->payload, 0xbd, sizeof(key->payload));
995 memset(&key->payload, 0xbd, sizeof(key->payload)); 984 }
996 } 985 }
997 986
998 spin_unlock(&key_serial_lock); 987 spin_unlock(&key_serial_lock);
@@ -1037,4 +1026,5 @@ void __init key_init(void)
1037 1026
1038 /* link the two root keyrings together */ 1027 /* link the two root keyrings together */
1039 key_link(&root_session_keyring, &root_user_keyring); 1028 key_link(&root_session_keyring, &root_user_keyring);
1029
1040} /* end key_init() */ 1030} /* end key_init() */