Commit ceb73c12047b8d543570b23353e7848eb7c540a1
Committed by
Linus Torvalds
1 parent
f5c66d70ac
Exists in
master
and in
7 other branches
KEYS: Fix __key_link_end() quota fixup on error
Fix __key_link_end()'s attempt to fix up the quota if an error occurs. There are two erroneous cases: Firstly, we always decrease the quota if the preallocated replacement keyring needs cleaning up, irrespective of whether or not we should (we may have replaced a pointer rather than adding another pointer). Secondly, we never clean up the quota if we added a pointer without the keyring storage being extended (we allocate multiple pointers at a time, even if we're not going to use them all immediately). We handle this by setting the bottom bit of the preallocation pointer in __key_link_begin() to indicate that the quota needs fixing up, which is then passed to __key_link() (which clears the whole thing) and __key_link_end(). Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 4 changed files with 27 additions and 20 deletions Side-by-side Diff
security/keys/internal.h
... | ... | @@ -87,13 +87,13 @@ |
87 | 87 | extern int __key_link_begin(struct key *keyring, |
88 | 88 | const struct key_type *type, |
89 | 89 | const char *description, |
90 | - struct keyring_list **_prealloc); | |
90 | + unsigned long *_prealloc); | |
91 | 91 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); |
92 | 92 | extern void __key_link(struct key *keyring, struct key *key, |
93 | - struct keyring_list **_prealloc); | |
93 | + unsigned long *_prealloc); | |
94 | 94 | extern void __key_link_end(struct key *keyring, |
95 | 95 | struct key_type *type, |
96 | - struct keyring_list *prealloc); | |
96 | + unsigned long prealloc); | |
97 | 97 | |
98 | 98 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
99 | 99 | const struct key_type *type, |
security/keys/key.c
... | ... | @@ -415,7 +415,7 @@ |
415 | 415 | size_t datalen, |
416 | 416 | struct key *keyring, |
417 | 417 | struct key *authkey, |
418 | - struct keyring_list **_prealloc) | |
418 | + unsigned long *_prealloc) | |
419 | 419 | { |
420 | 420 | int ret, awaken; |
421 | 421 | |
... | ... | @@ -481,7 +481,7 @@ |
481 | 481 | struct key *keyring, |
482 | 482 | struct key *authkey) |
483 | 483 | { |
484 | - struct keyring_list *prealloc; | |
484 | + unsigned long prealloc; | |
485 | 485 | int ret; |
486 | 486 | |
487 | 487 | if (keyring) { |
... | ... | @@ -526,7 +526,7 @@ |
526 | 526 | struct key *keyring, |
527 | 527 | struct key *authkey) |
528 | 528 | { |
529 | - struct keyring_list *prealloc; | |
529 | + unsigned long prealloc; | |
530 | 530 | struct timespec now; |
531 | 531 | int ret, awaken, link_ret = 0; |
532 | 532 | |
... | ... | @@ -814,7 +814,7 @@ |
814 | 814 | key_perm_t perm, |
815 | 815 | unsigned long flags) |
816 | 816 | { |
817 | - struct keyring_list *prealloc; | |
817 | + unsigned long prealloc; | |
818 | 818 | const struct cred *cred = current_cred(); |
819 | 819 | struct key_type *ktype; |
820 | 820 | struct key *keyring, *key = NULL; |
security/keys/keyring.c
... | ... | @@ -25,6 +25,8 @@ |
25 | 25 | (keyring)->payload.subscriptions, \ |
26 | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | |
28 | +#define KEY_LINK_FIXQUOTA 1UL | |
29 | + | |
28 | 30 | /* |
29 | 31 | * When plumbing the depths of the key tree, this sets a hard limit |
30 | 32 | * set on how deep we're willing to go. |
31 | 33 | |
... | ... | @@ -699,11 +701,11 @@ |
699 | 701 | * Preallocate memory so that a key can be linked into to a keyring. |
700 | 702 | */ |
701 | 703 | int __key_link_begin(struct key *keyring, const struct key_type *type, |
702 | - const char *description, | |
703 | - struct keyring_list **_prealloc) | |
704 | + const char *description, unsigned long *_prealloc) | |
704 | 705 | __acquires(&keyring->sem) |
705 | 706 | { |
706 | 707 | struct keyring_list *klist, *nklist; |
708 | + unsigned long prealloc; | |
707 | 709 | unsigned max; |
708 | 710 | size_t size; |
709 | 711 | int loop, ret; |
... | ... | @@ -746,6 +748,7 @@ |
746 | 748 | |
747 | 749 | /* note replacement slot */ |
748 | 750 | klist->delkey = nklist->delkey = loop; |
751 | + prealloc = (unsigned long)nklist; | |
749 | 752 | goto done; |
750 | 753 | } |
751 | 754 | } |
... | ... | @@ -760,6 +763,7 @@ |
760 | 763 | if (klist && klist->nkeys < klist->maxkeys) { |
761 | 764 | /* there's sufficient slack space to append directly */ |
762 | 765 | nklist = NULL; |
766 | + prealloc = KEY_LINK_FIXQUOTA; | |
763 | 767 | } else { |
764 | 768 | /* grow the key list */ |
765 | 769 | max = 4; |
766 | 770 | |
... | ... | @@ -794,8 +798,9 @@ |
794 | 798 | nklist->keys[nklist->delkey] = NULL; |
795 | 799 | } |
796 | 800 | |
801 | + prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | |
797 | 802 | done: |
798 | - *_prealloc = nklist; | |
803 | + *_prealloc = prealloc; | |
799 | 804 | kleave(" = 0"); |
800 | 805 | return 0; |
801 | 806 | |
802 | 807 | |
... | ... | @@ -836,12 +841,12 @@ |
836 | 841 | * combination. |
837 | 842 | */ |
838 | 843 | void __key_link(struct key *keyring, struct key *key, |
839 | - struct keyring_list **_prealloc) | |
844 | + unsigned long *_prealloc) | |
840 | 845 | { |
841 | 846 | struct keyring_list *klist, *nklist; |
842 | 847 | |
843 | - nklist = *_prealloc; | |
844 | - *_prealloc = NULL; | |
848 | + nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | |
849 | + *_prealloc = 0; | |
845 | 850 | |
846 | 851 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); |
847 | 852 | |
848 | 853 | |
849 | 854 | |
... | ... | @@ -881,20 +886,22 @@ |
881 | 886 | * Must be called with __key_link_begin() having being called. |
882 | 887 | */ |
883 | 888 | void __key_link_end(struct key *keyring, struct key_type *type, |
884 | - struct keyring_list *prealloc) | |
889 | + unsigned long prealloc) | |
885 | 890 | __releases(&keyring->sem) |
886 | 891 | { |
887 | 892 | BUG_ON(type == NULL); |
888 | 893 | BUG_ON(type->name == NULL); |
889 | - kenter("%d,%s,%p", keyring->serial, type->name, prealloc); | |
894 | + kenter("%d,%s,%lx", keyring->serial, type->name, prealloc); | |
890 | 895 | |
891 | 896 | if (type == &key_type_keyring) |
892 | 897 | up_write(&keyring_serialise_link_sem); |
893 | 898 | |
894 | 899 | if (prealloc) { |
895 | - kfree(prealloc); | |
896 | - key_payload_reserve(keyring, | |
897 | - keyring->datalen - KEYQUOTA_LINK_BYTES); | |
900 | + if (prealloc & KEY_LINK_FIXQUOTA) | |
901 | + key_payload_reserve(keyring, | |
902 | + keyring->datalen - | |
903 | + KEYQUOTA_LINK_BYTES); | |
904 | + kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA)); | |
898 | 905 | } |
899 | 906 | up_write(&keyring->sem); |
900 | 907 | } |
... | ... | @@ -921,7 +928,7 @@ |
921 | 928 | */ |
922 | 929 | int key_link(struct key *keyring, struct key *key) |
923 | 930 | { |
924 | - struct keyring_list *prealloc; | |
931 | + unsigned long prealloc; | |
925 | 932 | int ret; |
926 | 933 | |
927 | 934 | key_check(keyring); |
security/keys/request_key.c