diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 08:39:09 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-07-02 08:39:09 -0400 |
commit | d2f6409584e2c62ffad81690562330ff3bf4a458 (patch) | |
tree | 3bdfb97d0b51be2f7f414f2107e97603c1206abb /security/keys/key.c | |
parent | e1b09eba2686eca94a3a188042b518df6044a3c1 (diff) | |
parent | 4a89a04f1ee21a7c1f4413f1ad7dcfac50ff9b63 (diff) |
Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 118 |
1 files changed, 60 insertions, 58 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 59402c843203..fb89f9844465 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* key.c: basic authentication token and access key management | 1 | /* key.c: basic authentication token and access key management |
2 | * | 2 | * |
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -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 && |
@@ -392,7 +391,8 @@ EXPORT_SYMBOL(key_payload_reserve); | |||
392 | static int __key_instantiate_and_link(struct key *key, | 391 | static int __key_instantiate_and_link(struct key *key, |
393 | const void *data, | 392 | const void *data, |
394 | size_t datalen, | 393 | size_t datalen, |
395 | struct key *keyring) | 394 | struct key *keyring, |
395 | struct key *instkey) | ||
396 | { | 396 | { |
397 | int ret, awaken; | 397 | int ret, awaken; |
398 | 398 | ||
@@ -405,27 +405,25 @@ static int __key_instantiate_and_link(struct key *key, | |||
405 | down_write(&key_construction_sem); | 405 | down_write(&key_construction_sem); |
406 | 406 | ||
407 | /* can't instantiate twice */ | 407 | /* can't instantiate twice */ |
408 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 408 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
409 | /* instantiate the key */ | 409 | /* instantiate the key */ |
410 | ret = key->type->instantiate(key, data, datalen); | 410 | ret = key->type->instantiate(key, data, datalen); |
411 | 411 | ||
412 | if (ret == 0) { | 412 | if (ret == 0) { |
413 | /* mark the key as being instantiated */ | 413 | /* mark the key as being instantiated */ |
414 | write_lock(&key->lock); | ||
415 | |||
416 | atomic_inc(&key->user->nikeys); | 414 | atomic_inc(&key->user->nikeys); |
417 | key->flags |= KEY_FLAG_INSTANTIATED; | 415 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
418 | 416 | ||
419 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 417 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
420 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
421 | awaken = 1; | 418 | awaken = 1; |
422 | } | ||
423 | |||
424 | write_unlock(&key->lock); | ||
425 | 419 | ||
426 | /* and link it into the destination keyring */ | 420 | /* and link it into the destination keyring */ |
427 | if (keyring) | 421 | if (keyring) |
428 | ret = __key_link(keyring, key); | 422 | ret = __key_link(keyring, key); |
423 | |||
424 | /* disable the authorisation key */ | ||
425 | if (instkey) | ||
426 | key_revoke(instkey); | ||
429 | } | 427 | } |
430 | } | 428 | } |
431 | 429 | ||
@@ -446,19 +444,21 @@ static int __key_instantiate_and_link(struct key *key, | |||
446 | int key_instantiate_and_link(struct key *key, | 444 | int key_instantiate_and_link(struct key *key, |
447 | const void *data, | 445 | const void *data, |
448 | size_t datalen, | 446 | size_t datalen, |
449 | struct key *keyring) | 447 | struct key *keyring, |
448 | struct key *instkey) | ||
450 | { | 449 | { |
451 | int ret; | 450 | int ret; |
452 | 451 | ||
453 | if (keyring) | 452 | if (keyring) |
454 | down_write(&keyring->sem); | 453 | down_write(&keyring->sem); |
455 | 454 | ||
456 | ret = __key_instantiate_and_link(key, data, datalen, keyring); | 455 | ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey); |
457 | 456 | ||
458 | if (keyring) | 457 | if (keyring) |
459 | up_write(&keyring->sem); | 458 | up_write(&keyring->sem); |
460 | 459 | ||
461 | return ret; | 460 | return ret; |
461 | |||
462 | } /* end key_instantiate_and_link() */ | 462 | } /* end key_instantiate_and_link() */ |
463 | 463 | ||
464 | EXPORT_SYMBOL(key_instantiate_and_link); | 464 | EXPORT_SYMBOL(key_instantiate_and_link); |
@@ -469,7 +469,8 @@ EXPORT_SYMBOL(key_instantiate_and_link); | |||
469 | */ | 469 | */ |
470 | int key_negate_and_link(struct key *key, | 470 | int key_negate_and_link(struct key *key, |
471 | unsigned timeout, | 471 | unsigned timeout, |
472 | struct key *keyring) | 472 | struct key *keyring, |
473 | struct key *instkey) | ||
473 | { | 474 | { |
474 | struct timespec now; | 475 | struct timespec now; |
475 | int ret, awaken; | 476 | int ret, awaken; |
@@ -486,26 +487,26 @@ int key_negate_and_link(struct key *key, | |||
486 | down_write(&key_construction_sem); | 487 | down_write(&key_construction_sem); |
487 | 488 | ||
488 | /* can't instantiate twice */ | 489 | /* can't instantiate twice */ |
489 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 490 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
490 | /* mark the key as being negatively instantiated */ | 491 | /* mark the key as being negatively instantiated */ |
491 | write_lock(&key->lock); | ||
492 | |||
493 | atomic_inc(&key->user->nikeys); | 492 | atomic_inc(&key->user->nikeys); |
494 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 493 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
494 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | ||
495 | now = current_kernel_time(); | 495 | now = current_kernel_time(); |
496 | key->expiry = now.tv_sec + timeout; | 496 | key->expiry = now.tv_sec + timeout; |
497 | 497 | ||
498 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 498 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
499 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
500 | awaken = 1; | 499 | awaken = 1; |
501 | } | ||
502 | 500 | ||
503 | write_unlock(&key->lock); | ||
504 | ret = 0; | 501 | ret = 0; |
505 | 502 | ||
506 | /* and link it into the destination keyring */ | 503 | /* and link it into the destination keyring */ |
507 | if (keyring) | 504 | if (keyring) |
508 | ret = __key_link(keyring, key); | 505 | ret = __key_link(keyring, key); |
506 | |||
507 | /* disable the authorisation key */ | ||
508 | if (instkey) | ||
509 | key_revoke(instkey); | ||
509 | } | 510 | } |
510 | 511 | ||
511 | up_write(&key_construction_sem); | 512 | up_write(&key_construction_sem); |
@@ -553,8 +554,10 @@ static void key_cleanup(void *data) | |||
553 | rb_erase(&key->serial_node, &key_serial_tree); | 554 | rb_erase(&key->serial_node, &key_serial_tree); |
554 | spin_unlock(&key_serial_lock); | 555 | spin_unlock(&key_serial_lock); |
555 | 556 | ||
557 | key_check(key); | ||
558 | |||
556 | /* deal with the user's key tracking and quota */ | 559 | /* deal with the user's key tracking and quota */ |
557 | if (key->flags & KEY_FLAG_IN_QUOTA) { | 560 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
558 | spin_lock(&key->user->lock); | 561 | spin_lock(&key->user->lock); |
559 | key->user->qnkeys--; | 562 | key->user->qnkeys--; |
560 | key->user->qnbytes -= key->quotalen; | 563 | key->user->qnbytes -= key->quotalen; |
@@ -562,7 +565,7 @@ static void key_cleanup(void *data) | |||
562 | } | 565 | } |
563 | 566 | ||
564 | atomic_dec(&key->user->nkeys); | 567 | atomic_dec(&key->user->nkeys); |
565 | if (key->flags & KEY_FLAG_INSTANTIATED) | 568 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
566 | atomic_dec(&key->user->nikeys); | 569 | atomic_dec(&key->user->nikeys); |
567 | 570 | ||
568 | key_user_put(key->user); | 571 | key_user_put(key->user); |
@@ -631,9 +634,9 @@ struct key *key_lookup(key_serial_t id) | |||
631 | goto error; | 634 | goto error; |
632 | 635 | ||
633 | found: | 636 | found: |
634 | /* pretent doesn't exist if it's dead */ | 637 | /* pretend it doesn't exist if it's dead */ |
635 | if (atomic_read(&key->usage) == 0 || | 638 | if (atomic_read(&key->usage) == 0 || |
636 | (key->flags & KEY_FLAG_DEAD) || | 639 | test_bit(KEY_FLAG_DEAD, &key->flags) || |
637 | key->type == &key_type_dead) | 640 | key->type == &key_type_dead) |
638 | goto not_found; | 641 | goto not_found; |
639 | 642 | ||
@@ -708,12 +711,9 @@ static inline struct key *__key_update(struct key *key, const void *payload, | |||
708 | 711 | ||
709 | ret = key->type->update(key, payload, plen); | 712 | ret = key->type->update(key, payload, plen); |
710 | 713 | ||
711 | if (ret == 0) { | 714 | if (ret == 0) |
712 | /* updating a negative key instantiates it */ | 715 | /* updating a negative key instantiates it */ |
713 | write_lock(&key->lock); | 716 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
714 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
715 | write_unlock(&key->lock); | ||
716 | } | ||
717 | 717 | ||
718 | up_write(&key->sem); | 718 | up_write(&key->sem); |
719 | 719 | ||
@@ -793,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring, | |||
793 | } | 793 | } |
794 | 794 | ||
795 | /* instantiate it and link it into the target keyring */ | 795 | /* instantiate it and link it into the target keyring */ |
796 | ret = __key_instantiate_and_link(key, payload, plen, keyring); | 796 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL); |
797 | if (ret < 0) { | 797 | if (ret < 0) { |
798 | key_put(key); | 798 | key_put(key); |
799 | key = ERR_PTR(ret); | 799 | key = ERR_PTR(ret); |
@@ -841,12 +841,9 @@ int key_update(struct key *key, const void *payload, size_t plen) | |||
841 | down_write(&key->sem); | 841 | down_write(&key->sem); |
842 | ret = key->type->update(key, payload, plen); | 842 | ret = key->type->update(key, payload, plen); |
843 | 843 | ||
844 | if (ret == 0) { | 844 | if (ret == 0) |
845 | /* updating a negative key instantiates it */ | 845 | /* updating a negative key instantiates it */ |
846 | write_lock(&key->lock); | 846 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
847 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
848 | write_unlock(&key->lock); | ||
849 | } | ||
850 | 847 | ||
851 | up_write(&key->sem); | 848 | up_write(&key->sem); |
852 | } | 849 | } |
@@ -892,10 +889,7 @@ struct key *key_duplicate(struct key *source, const char *desc) | |||
892 | goto error2; | 889 | goto error2; |
893 | 890 | ||
894 | atomic_inc(&key->user->nikeys); | 891 | atomic_inc(&key->user->nikeys); |
895 | 892 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | |
896 | write_lock(&key->lock); | ||
897 | key->flags |= KEY_FLAG_INSTANTIATED; | ||
898 | write_unlock(&key->lock); | ||
899 | 893 | ||
900 | error_k: | 894 | error_k: |
901 | up_read(&key_types_sem); | 895 | up_read(&key_types_sem); |
@@ -922,9 +916,7 @@ void key_revoke(struct key *key) | |||
922 | /* make sure no one's trying to change or use the key when we mark | 916 | /* make sure no one's trying to change or use the key when we mark |
923 | * it */ | 917 | * it */ |
924 | down_write(&key->sem); | 918 | down_write(&key->sem); |
925 | write_lock(&key->lock); | 919 | set_bit(KEY_FLAG_REVOKED, &key->flags); |
926 | key->flags |= KEY_FLAG_REVOKED; | ||
927 | write_unlock(&key->lock); | ||
928 | up_write(&key->sem); | 920 | up_write(&key->sem); |
929 | 921 | ||
930 | } /* end key_revoke() */ | 922 | } /* end key_revoke() */ |
@@ -975,24 +967,33 @@ void unregister_key_type(struct key_type *ktype) | |||
975 | /* withdraw the key type */ | 967 | /* withdraw the key type */ |
976 | list_del_init(&ktype->link); | 968 | list_del_init(&ktype->link); |
977 | 969 | ||
978 | /* need to withdraw all keys of this type */ | 970 | /* mark all the keys of this type dead */ |
979 | spin_lock(&key_serial_lock); | 971 | spin_lock(&key_serial_lock); |
980 | 972 | ||
981 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | 973 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
982 | key = rb_entry(_n, struct key, serial_node); | 974 | key = rb_entry(_n, struct key, serial_node); |
983 | 975 | ||
984 | if (key->type != ktype) | 976 | if (key->type == ktype) |
985 | continue; | 977 | key->type = &key_type_dead; |
978 | } | ||
979 | |||
980 | spin_unlock(&key_serial_lock); | ||
981 | |||
982 | /* make sure everyone revalidates their keys */ | ||
983 | synchronize_rcu(); | ||
986 | 984 | ||
987 | write_lock(&key->lock); | 985 | /* we should now be able to destroy the payloads of all the keys of |
988 | key->type = &key_type_dead; | 986 | * this type with impunity */ |
989 | write_unlock(&key->lock); | 987 | spin_lock(&key_serial_lock); |
988 | |||
989 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | ||
990 | key = rb_entry(_n, struct key, serial_node); | ||
990 | 991 | ||
991 | /* there shouldn't be anyone looking at the description or | 992 | if (key->type == ktype) { |
992 | * payload now */ | 993 | if (ktype->destroy) |
993 | if (ktype->destroy) | 994 | ktype->destroy(key); |
994 | ktype->destroy(key); | 995 | memset(&key->payload, 0xbd, sizeof(key->payload)); |
995 | memset(&key->payload, 0xbd, sizeof(key->payload)); | 996 | } |
996 | } | 997 | } |
997 | 998 | ||
998 | spin_unlock(&key_serial_lock); | 999 | spin_unlock(&key_serial_lock); |
@@ -1037,4 +1038,5 @@ void __init key_init(void) | |||
1037 | 1038 | ||
1038 | /* link the two root keyrings together */ | 1039 | /* link the two root keyrings together */ |
1039 | key_link(&root_session_keyring, &root_user_keyring); | 1040 | key_link(&root_session_keyring, &root_user_keyring); |
1041 | |||
1040 | } /* end key_init() */ | 1042 | } /* end key_init() */ |