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 50d96d4e06f2..1d039af99f50 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -412,8 +412,7 @@ EXPORT_SYMBOL(key_payload_reserve); | |||
412 | * key_construction_mutex. | 412 | * key_construction_mutex. |
413 | */ | 413 | */ |
414 | static int __key_instantiate_and_link(struct key *key, | 414 | static int __key_instantiate_and_link(struct key *key, |
415 | const void *data, | 415 | struct key_preparsed_payload *prep, |
416 | size_t datalen, | ||
417 | struct key *keyring, | 416 | struct key *keyring, |
418 | struct key *authkey, | 417 | struct key *authkey, |
419 | unsigned long *_prealloc) | 418 | unsigned long *_prealloc) |
@@ -431,7 +430,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
431 | /* can't instantiate twice */ | 430 | /* can't instantiate twice */ |
432 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | 431 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
433 | /* instantiate the key */ | 432 | /* instantiate the key */ |
434 | ret = key->type->instantiate(key, data, datalen); | 433 | ret = key->type->instantiate(key, prep); |
435 | 434 | ||
436 | if (ret == 0) { | 435 | if (ret == 0) { |
437 | /* mark the key as being instantiated */ | 436 | /* mark the key as being instantiated */ |
@@ -482,22 +481,37 @@ int key_instantiate_and_link(struct key *key, | |||
482 | struct key *keyring, | 481 | struct key *keyring, |
483 | struct key *authkey) | 482 | struct key *authkey) |
484 | { | 483 | { |
484 | struct key_preparsed_payload prep; | ||
485 | unsigned long prealloc; | 485 | unsigned long prealloc; |
486 | int ret; | 486 | int ret; |
487 | 487 | ||
488 | memset(&prep, 0, sizeof(prep)); | ||
489 | prep.data = data; | ||
490 | prep.datalen = datalen; | ||
491 | prep.quotalen = key->type->def_datalen; | ||
492 | if (key->type->preparse) { | ||
493 | ret = key->type->preparse(&prep); | ||
494 | if (ret < 0) | ||
495 | goto error; | ||
496 | } | ||
497 | |||
488 | if (keyring) { | 498 | if (keyring) { |
489 | ret = __key_link_begin(keyring, key->type, key->description, | 499 | ret = __key_link_begin(keyring, key->type, key->description, |
490 | &prealloc); | 500 | &prealloc); |
491 | if (ret < 0) | 501 | if (ret < 0) |
492 | return ret; | 502 | goto error_free_preparse; |
493 | } | 503 | } |
494 | 504 | ||
495 | ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey, | 505 | ret = __key_instantiate_and_link(key, &prep, keyring, authkey, |
496 | &prealloc); | 506 | &prealloc); |
497 | 507 | ||
498 | if (keyring) | 508 | if (keyring) |
499 | __key_link_end(keyring, key->type, prealloc); | 509 | __key_link_end(keyring, key->type, prealloc); |
500 | 510 | ||
511 | error_free_preparse: | ||
512 | if (key->type->preparse) | ||
513 | key->type->free_preparse(&prep); | ||
514 | error: | ||
501 | return ret; | 515 | return ret; |
502 | } | 516 | } |
503 | 517 | ||
@@ -706,7 +720,7 @@ void key_type_put(struct key_type *ktype) | |||
706 | * if we get an error. | 720 | * if we get an error. |
707 | */ | 721 | */ |
708 | static inline key_ref_t __key_update(key_ref_t key_ref, | 722 | static inline key_ref_t __key_update(key_ref_t key_ref, |
709 | const void *payload, size_t plen) | 723 | struct key_preparsed_payload *prep) |
710 | { | 724 | { |
711 | struct key *key = key_ref_to_ptr(key_ref); | 725 | struct key *key = key_ref_to_ptr(key_ref); |
712 | int ret; | 726 | int ret; |
@@ -722,7 +736,7 @@ static inline key_ref_t __key_update(key_ref_t key_ref, | |||
722 | 736 | ||
723 | down_write(&key->sem); | 737 | down_write(&key->sem); |
724 | 738 | ||
725 | ret = key->type->update(key, payload, plen); | 739 | ret = key->type->update(key, prep); |
726 | if (ret == 0) | 740 | if (ret == 0) |
727 | /* updating a negative key instantiates it */ | 741 | /* updating a negative key instantiates it */ |
728 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | 742 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
@@ -774,6 +788,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
774 | unsigned long flags) | 788 | unsigned long flags) |
775 | { | 789 | { |
776 | unsigned long prealloc; | 790 | unsigned long prealloc; |
791 | struct key_preparsed_payload prep; | ||
777 | const struct cred *cred = current_cred(); | 792 | const struct cred *cred = current_cred(); |
778 | struct key_type *ktype; | 793 | struct key_type *ktype; |
779 | struct key *keyring, *key = NULL; | 794 | struct key *keyring, *key = NULL; |
@@ -789,8 +804,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
789 | } | 804 | } |
790 | 805 | ||
791 | key_ref = ERR_PTR(-EINVAL); | 806 | key_ref = ERR_PTR(-EINVAL); |
792 | if (!ktype->match || !ktype->instantiate) | 807 | if (!ktype->match || !ktype->instantiate || |
793 | goto error_2; | 808 | (!description && !ktype->preparse)) |
809 | goto error_put_type; | ||
794 | 810 | ||
795 | keyring = key_ref_to_ptr(keyring_ref); | 811 | keyring = key_ref_to_ptr(keyring_ref); |
796 | 812 | ||
@@ -798,18 +814,37 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
798 | 814 | ||
799 | key_ref = ERR_PTR(-ENOTDIR); | 815 | key_ref = ERR_PTR(-ENOTDIR); |
800 | if (keyring->type != &key_type_keyring) | 816 | if (keyring->type != &key_type_keyring) |
801 | goto error_2; | 817 | goto error_put_type; |
818 | |||
819 | memset(&prep, 0, sizeof(prep)); | ||
820 | prep.data = payload; | ||
821 | prep.datalen = plen; | ||
822 | prep.quotalen = ktype->def_datalen; | ||
823 | if (ktype->preparse) { | ||
824 | ret = ktype->preparse(&prep); | ||
825 | if (ret < 0) { | ||
826 | key_ref = ERR_PTR(ret); | ||
827 | goto error_put_type; | ||
828 | } | ||
829 | if (!description) | ||
830 | description = prep.description; | ||
831 | key_ref = ERR_PTR(-EINVAL); | ||
832 | if (!description) | ||
833 | goto error_free_prep; | ||
834 | } | ||
802 | 835 | ||
803 | ret = __key_link_begin(keyring, ktype, description, &prealloc); | 836 | ret = __key_link_begin(keyring, ktype, description, &prealloc); |
804 | if (ret < 0) | 837 | if (ret < 0) { |
805 | goto error_2; | 838 | key_ref = ERR_PTR(ret); |
839 | goto error_free_prep; | ||
840 | } | ||
806 | 841 | ||
807 | /* if we're going to allocate a new key, we're going to have | 842 | /* if we're going to allocate a new key, we're going to have |
808 | * to modify the keyring */ | 843 | * to modify the keyring */ |
809 | ret = key_permission(keyring_ref, KEY_WRITE); | 844 | ret = key_permission(keyring_ref, KEY_WRITE); |
810 | if (ret < 0) { | 845 | if (ret < 0) { |
811 | key_ref = ERR_PTR(ret); | 846 | key_ref = ERR_PTR(ret); |
812 | goto error_3; | 847 | goto error_link_end; |
813 | } | 848 | } |
814 | 849 | ||
815 | /* if it's possible to update this type of key, search for an existing | 850 | /* if it's possible to update this type of key, search for an existing |
@@ -840,25 +875,27 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
840 | perm, flags); | 875 | perm, flags); |
841 | if (IS_ERR(key)) { | 876 | if (IS_ERR(key)) { |
842 | key_ref = ERR_CAST(key); | 877 | key_ref = ERR_CAST(key); |
843 | goto error_3; | 878 | goto error_link_end; |
844 | } | 879 | } |
845 | 880 | ||
846 | /* instantiate it and link it into the target keyring */ | 881 | /* instantiate it and link it into the target keyring */ |
847 | ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL, | 882 | ret = __key_instantiate_and_link(key, &prep, keyring, NULL, &prealloc); |
848 | &prealloc); | ||
849 | if (ret < 0) { | 883 | if (ret < 0) { |
850 | key_put(key); | 884 | key_put(key); |
851 | key_ref = ERR_PTR(ret); | 885 | key_ref = ERR_PTR(ret); |
852 | goto error_3; | 886 | goto error_link_end; |
853 | } | 887 | } |
854 | 888 | ||
855 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); | 889 | key_ref = make_key_ref(key, is_key_possessed(keyring_ref)); |
856 | 890 | ||
857 | error_3: | 891 | error_link_end: |
858 | __key_link_end(keyring, ktype, prealloc); | 892 | __key_link_end(keyring, ktype, prealloc); |
859 | error_2: | 893 | error_free_prep: |
894 | if (ktype->preparse) | ||
895 | ktype->free_preparse(&prep); | ||
896 | error_put_type: | ||
860 | key_type_put(ktype); | 897 | key_type_put(ktype); |
861 | error: | 898 | error: |
862 | return key_ref; | 899 | return key_ref; |
863 | 900 | ||
864 | found_matching_key: | 901 | found_matching_key: |
@@ -866,10 +903,9 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
866 | * - we can drop the locks first as we have the key pinned | 903 | * - we can drop the locks first as we have the key pinned |
867 | */ | 904 | */ |
868 | __key_link_end(keyring, ktype, prealloc); | 905 | __key_link_end(keyring, ktype, prealloc); |
869 | key_type_put(ktype); | ||
870 | 906 | ||
871 | key_ref = __key_update(key_ref, payload, plen); | 907 | key_ref = __key_update(key_ref, &prep); |
872 | goto error; | 908 | goto error_free_prep; |
873 | } | 909 | } |
874 | EXPORT_SYMBOL(key_create_or_update); | 910 | EXPORT_SYMBOL(key_create_or_update); |
875 | 911 | ||
@@ -888,6 +924,7 @@ EXPORT_SYMBOL(key_create_or_update); | |||
888 | */ | 924 | */ |
889 | int key_update(key_ref_t key_ref, const void *payload, size_t plen) | 925 | int key_update(key_ref_t key_ref, const void *payload, size_t plen) |
890 | { | 926 | { |
927 | struct key_preparsed_payload prep; | ||
891 | struct key *key = key_ref_to_ptr(key_ref); | 928 | struct key *key = key_ref_to_ptr(key_ref); |
892 | int ret; | 929 | int ret; |
893 | 930 | ||
@@ -900,18 +937,31 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
900 | 937 | ||
901 | /* attempt to update it if supported */ | 938 | /* attempt to update it if supported */ |
902 | ret = -EOPNOTSUPP; | 939 | ret = -EOPNOTSUPP; |
903 | if (key->type->update) { | 940 | if (!key->type->update) |
904 | down_write(&key->sem); | 941 | goto error; |
905 | |||
906 | ret = key->type->update(key, payload, plen); | ||
907 | if (ret == 0) | ||
908 | /* updating a negative key instantiates it */ | ||
909 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
910 | 942 | ||
911 | up_write(&key->sem); | 943 | memset(&prep, 0, sizeof(prep)); |
944 | prep.data = payload; | ||
945 | prep.datalen = plen; | ||
946 | prep.quotalen = key->type->def_datalen; | ||
947 | if (key->type->preparse) { | ||
948 | ret = key->type->preparse(&prep); | ||
949 | if (ret < 0) | ||
950 | goto error; | ||
912 | } | 951 | } |
913 | 952 | ||
914 | error: | 953 | down_write(&key->sem); |
954 | |||
955 | ret = key->type->update(key, &prep); | ||
956 | if (ret == 0) | ||
957 | /* updating a negative key instantiates it */ | ||
958 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); | ||
959 | |||
960 | up_write(&key->sem); | ||
961 | |||
962 | if (key->type->preparse) | ||
963 | key->type->free_preparse(&prep); | ||
964 | error: | ||
915 | return ret; | 965 | return ret; |
916 | } | 966 | } |
917 | EXPORT_SYMBOL(key_update); | 967 | EXPORT_SYMBOL(key_update); |