diff options
Diffstat (limited to 'security/keys/key.c')
-rw-r--r-- | security/keys/key.c | 114 |
1 files changed, 82 insertions, 32 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index a30e92734905..a15c9da8f971 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -405,8 +405,7 @@ EXPORT_SYMBOL(key_payload_reserve); | |||
405 | * key_construction_mutex. | 405 | * key_construction_mutex. |
406 | */ | 406 | */ |
407 | static int __key_instantiate_and_link(struct key *key, | 407 | static int __key_instantiate_and_link(struct key *key, |
408 | const void *data, | 408 | struct key_preparsed_payload *prep, |
409 | size_t datalen, | ||
410 | struct key *keyring, | 409 | struct key *keyring, |
411 | struct key *authkey, | 410 | struct key *authkey, |
412 | unsigned long *_prealloc) | 411 | unsigned long *_prealloc) |
@@ -424,7 +423,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
424 | /* can't instantiate twice */ | 423 | /* can't instantiate twice */ |
425 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 424 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
426 | /* instantiate the key */ | 425 | /* instantiate the key */ |
427 | ret = key->type->instantiate(key, data, datalen); | 426 | ret = key->type->instantiate(key, prep); |
428 | 427 | ||
429 | if (ret == 0) { | 428 | if (ret == 0) { |
430 | /* mark the key as being instantiated */ | 429 | /* mark the key as being instantiated */ |
@@ -475,22 +474,37 @@ int key_instantiate_and_link(struct key *key, | |||
475 | struct key *keyring, | 474 | struct key *keyring, |
476 | struct key *authkey) | 475 | struct key *authkey) |
477 | { | 476 | { |
477 | struct key_preparsed_payload prep; | ||
478 | unsigned long prealloc; | 478 | unsigned long prealloc; |
479 | int ret; | 479 | int ret; |
480 | 480 | ||
481 | memset(&prep, 0, sizeof(prep)); | ||
482 | prep.data = data; | ||
483 | prep.datalen = datalen; | ||
484 | prep.quotalen = key->type->def_datalen; | ||
485 | if (key->type->preparse) { | ||
486 | ret = key->type->preparse(&prep); | ||
487 | if (ret < 0) | ||
488 | goto error; | ||
489 | } | ||
490 | |||
481 | if (keyring) { | 491 | if (keyring) { |
482 | ret = __key_link_begin(keyring, key->type, key->description, | 492 | ret = __key_link_begin(keyring, key->type, key->description, |
483 | &prealloc); | 493 | &prealloc); |
484 | if (ret < 0) | 494 | if (ret < 0) |
485 | return ret; | 495 | goto error_free_preparse; |
486 | } | 496 | } |
487 | 497 | ||
488 | ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, | 498 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, |
489 | &prealloc); | 499 | &prealloc); |
490 | 500 | ||
491 | if (keyring) | 501 | if (keyring) |
492 | __key_link_end(keyring, key->type, prealloc); | 502 | __key_link_end(keyring, key->type, prealloc); |
493 | 503 | ||
504 | error_free_preparse: | ||
505 | if (key->type->preparse) | ||
506 | key->type->free_preparse(&prep); | ||
507 | error: | ||
494 | return ret; | 508 | return ret; |
495 | } | 509 | } |
496 | 510 | ||
@@ -699,7 +713,7 @@ void key_type_put(struct key_type *ktype) | |||
699 | * if we get an error. | 713 | * if we get an error. |
700 | */ | 714 | */ |
701 | static inline key_ref_t __key_update(key_ref_t key_ref, | 715 | static inline key_ref_t __key_update(key_ref_t key_ref, |
702 | const void *payload, size_t plen) | 716 | struct key_preparsed_payload *prep) |
703 | { | 717 | { |
704 | struct key *key = key_ref_to_ptr(key_ref); | 718 | struct key *key = key_ref_to_ptr(key_ref); |
705 | int ret; | 719 | int ret; |
@@ -715,7 +729,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, | |||
715 | 729 | ||
716 | down_write(&key->sem); | 730 | down_write(&key->sem); |
717 | 731 | ||
718 | ret = key->type->update(key, payload, plen); | 732 | ret = key->type->update(key, prep); |
719 | if (ret == 0) | 733 | if (ret == 0) |
720 | /* updating a negative key instantiates it */ | 734 | /* updating a negative key instantiates it */ |
721 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | 735 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
@@ -767,6 +781,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
767 | unsigned long flags) | 781 | unsigned long flags) |
768 | { | 782 | { |
769 | unsigned long prealloc; | 783 | unsigned long prealloc; |
784 | struct key_preparsed_payload prep; | ||
770 | const struct cred *cred = current_cred(); | 785 | const struct cred *cred = current_cred(); |
771 | struct key_type *ktype; | 786 | struct key_type *ktype; |
772 | struct key *keyring, *key = NULL; | 787 | struct key *keyring, *key = NULL; |
@@ -782,8 +797,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
782 | } | 797 | } |
783 | 798 | ||
784 | key_ref = ERR_PTR(-EINVAL); | 799 | key_ref = ERR_PTR(-EINVAL); |
785 | if (!ktype->match || !ktype->instantiate) | 800 | if (!ktype->match || !ktype->instantiate || |
786 | goto error_2; | 801 | (!description && !ktype->preparse)) |
802 | goto error_put_type; | ||
787 | 803 | ||
788 | keyring = key_ref_to_ptr(keyring_ref); | 804 | keyring = key_ref_to_ptr(keyring_ref); |
789 | 805 | ||
@@ -791,18 +807,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
791 | 807 | ||
792 | key_ref = ERR_PTR(-ENOTDIR); | 808 | key_ref = ERR_PTR(-ENOTDIR); |
793 | if (keyring->type != &key_type_keyring) | 809 | if (keyring->type != &key_type_keyring) |
794 | goto error_2; | 810 | goto error_put_type; |
811 | |||
812 | memset(&prep, 0, sizeof(prep)); | ||
813 | prep.data = payload; | ||
814 | prep.datalen = plen; | ||
815 | prep.quotalen = ktype->def_datalen; | ||
816 | if (ktype->preparse) { | ||
817 | ret = ktype->preparse(&prep); | ||
818 | if (ret < 0) { | ||
819 | key_ref = ERR_PTR(ret); | ||
820 | goto error_put_type; | ||
821 | } | ||
822 | if (!description) | ||
823 | description = prep.description; | ||
824 | key_ref = ERR_PTR(-EINVAL); | ||
825 | if (!description) | ||
826 | goto error_free_prep; | ||
827 | } | ||
795 | 828 | ||
796 | ret = __key_link_begin(keyring, ktype, description, &prealloc); | 829 | ret = __key_link_begin(keyring, ktype, description, &prealloc); |
797 | if (ret < 0) | 830 | if (ret < 0) { |
798 | goto error_2; | 831 | key_ref = ERR_PTR(ret); |
832 | goto error_free_prep; | ||
833 | } | ||
799 | 834 | ||
800 | /* if we're going to allocate a new key, we're going to have | 835 | /* if we're going to allocate a new key, we're going to have |
801 | * to modify the keyring */ | 836 | * to modify the keyring */ |
802 | ret = key_permission(keyring_ref, KEY_WRITE); | 837 | ret = key_permission(keyring_ref, KEY_WRITE); |
803 | if (ret < 0) { | 838 | if (ret < 0) { |
804 | key_ref = ERR_PTR(ret); | 839 | key_ref = ERR_PTR(ret); |
805 | goto error_3; | 840 | goto error_link_end; |
806 | } | 841 | } |
807 | 842 | ||
808 | /* if it's possible to update this type of key, search for an existing | 843 | /* if it's possible to update this type of key, search for an existing |
@@ -833,25 +868,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
833 | perm, flags); | 868 | perm, flags); |
834 | if (IS_ERR(key)) { | 869 | if (IS_ERR(key)) { |
835 | key_ref = ERR_CAST(key); | 870 | key_ref = ERR_CAST(key); |
836 | goto error_3; | 871 | goto error_link_end; |
837 | } | 872 | } |
838 | 873 | ||
839 | /* instantiate it and link it into the target keyring */ | 874 | /* instantiate it and link it into the target keyring */ |
840 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, | 875 | ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc); |
841 | &prealloc); | ||
842 | if (ret < 0) { | 876 | if (ret < 0) { |
843 | key_put(key); | 877 | key_put(key); |
844 | key_ref = ERR_PTR(ret); | 878 | key_ref = ERR_PTR(ret); |
845 | goto error_3; | 879 | goto error_link_end; |
846 | } | 880 | } |
847 | 881 | ||
848 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); | 882 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); |
849 | 883 | ||
850 | error_3: | 884 | error_link_end: |
851 | __key_link_end(keyring, ktype, prealloc); | 885 | __key_link_end(keyring, ktype, prealloc); |
852 | error_2: | 886 | error_free_prep: |
887 | if (ktype->preparse) | ||
888 | ktype->free_preparse(&prep); | ||
889 | error_put_type: | ||
853 | key_type_put(ktype); | 890 | key_type_put(ktype); |
854 | error: | 891 | error: |
855 | return key_ref; | 892 | return key_ref; |
856 | 893 | ||
857 | found_matching_key: | 894 | found_matching_key: |
@@ -859,10 +896,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
859 | * - we can drop the locks first as we have the key pinned | 896 | * - we can drop the locks first as we have the key pinned |
860 | */ | 897 | */ |
861 | __key_link_end(keyring, ktype, prealloc); | 898 | __key_link_end(keyring, ktype, prealloc); |
862 | key_type_put(ktype); | ||
863 | 899 | ||
864 | key_ref = __key_update(key_ref, payload, plen); | 900 | key_ref = __key_update(key_ref, &prep); |
865 | goto error; | 901 | goto error_free_prep; |
866 | } | 902 | } |
867 | EXPORT_SYMBOL(key_create_or_update); | 903 | EXPORT_SYMBOL(key_create_or_update); |
868 | 904 | ||
@@ -881,6 +917,7 @@ EXPORT_SYMBOL(key_create_or_update); | |||
881 | */ | 917 | */ |
882 | int key_update(key_ref_t key_ref, const void *payload, size_t plen) | 918 | int key_update(key_ref_t key_ref, const void *payload, size_t plen) |
883 | { | 919 | { |
920 | struct key_preparsed_payload prep; | ||
884 | struct key *key = key_ref_to_ptr(key_ref); | 921 | struct key *key = key_ref_to_ptr(key_ref); |
885 | int ret; | 922 | int ret; |
886 | 923 | ||
@@ -893,18 +930,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
893 | 930 | ||
894 | /* attempt to update it if supported */ | 931 | /* attempt to update it if supported */ |
895 | ret = -EOPNOTSUPP; | 932 | ret = -EOPNOTSUPP; |
896 | if (key->type->update) { | 933 | if (!key->type->update) |
897 | down_write(&key->sem); | 934 | goto error; |
898 | |||
899 | ret = key->type->update(key, payload, plen); | ||
900 | if (ret == 0) | ||
901 | /* updating a negative key instantiates it */ | ||
902 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
903 | 935 | ||
904 | up_write(&key->sem); | 936 | memset(&prep, 0, sizeof(prep)); |
937 | prep.data = payload; | ||
938 | prep.datalen = plen; | ||
939 | prep.quotalen = key->type->def_datalen; | ||
940 | if (key->type->preparse) { | ||
941 | ret = key->type->preparse(&prep); | ||
942 | if (ret < 0) | ||
943 | goto error; | ||
905 | } | 944 | } |
906 | 945 | ||
907 | error: | 946 | down_write(&key->sem); |
947 | |||
948 | ret = key->type->update(key, &prep); | ||
949 | if (ret == 0) | ||
950 | /* updating a negative key instantiates it */ | ||
951 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
952 | |||
953 | up_write(&key->sem); | ||
954 | |||
955 | if (key->type->preparse) | ||
956 | key->type->free_preparse(&prep); | ||
957 | error: | ||
908 | return ret; | 958 | return ret; |
909 | } | 959 | } |
910 | EXPORT_SYMBOL(key_update); | 960 | EXPORT_SYMBOL(key_update); |