diff options
author | David Howells <dhowells@redhat.com> | 2011-01-25 11:34:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-25 17:58:20 -0500 |
commit | ceb73c12047b8d543570b23353e7848eb7c540a1 (patch) | |
tree | a637dc88d418be1b705a66bea375af955bd14e22 /security | |
parent | f5c66d70ac2a9016a7ad481bd37e39afd7dd7369 (diff) |
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>
Diffstat (limited to 'security')
-rw-r--r-- | security/keys/internal.h | 6 | ||||
-rw-r--r-- | security/keys/key.c | 8 | ||||
-rw-r--r-- | security/keys/keyring.c | 31 | ||||
-rw-r--r-- | security/keys/request_key.c | 2 |
4 files changed, 27 insertions, 20 deletions
diff --git a/security/keys/internal.h b/security/keys/internal.h index edfa50dbd6f5..a52aa7c88b41 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -87,13 +87,13 @@ extern void key_type_put(struct key_type *ktype); | |||
87 | extern int __key_link_begin(struct key *keyring, | 87 | extern int __key_link_begin(struct key *keyring, |
88 | const struct key_type *type, | 88 | const struct key_type *type, |
89 | const char *description, | 89 | const char *description, |
90 | struct keyring_list **_prealloc); | 90 | unsigned long *_prealloc); |
91 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); | 91 | extern int __key_link_check_live_key(struct key *keyring, struct key *key); |
92 | extern void __key_link(struct key *keyring, struct key *key, | 92 | extern void __key_link(struct key *keyring, struct key *key, |
93 | struct keyring_list **_prealloc); | 93 | unsigned long *_prealloc); |
94 | extern void __key_link_end(struct key *keyring, | 94 | extern void __key_link_end(struct key *keyring, |
95 | struct key_type *type, | 95 | struct key_type *type, |
96 | struct keyring_list *prealloc); | 96 | unsigned long prealloc); |
97 | 97 | ||
98 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, | 98 | extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, |
99 | const struct key_type *type, | 99 | const struct key_type *type, |
diff --git a/security/keys/key.c b/security/keys/key.c index 84d4eb568b08..1c2d43dc5107 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -415,7 +415,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
415 | size_t datalen, | 415 | size_t datalen, |
416 | struct key *keyring, | 416 | struct key *keyring, |
417 | struct key *authkey, | 417 | struct key *authkey, |
418 | struct keyring_list **_prealloc) | 418 | unsigned long *_prealloc) |
419 | { | 419 | { |
420 | int ret, awaken; | 420 | int ret, awaken; |
421 | 421 | ||
@@ -481,7 +481,7 @@ int key_instantiate_and_link(struct key *key, | |||
481 | struct key *keyring, | 481 | struct key *keyring, |
482 | struct key *authkey) | 482 | struct key *authkey) |
483 | { | 483 | { |
484 | struct keyring_list *prealloc; | 484 | unsigned long prealloc; |
485 | int ret; | 485 | int ret; |
486 | 486 | ||
487 | if (keyring) { | 487 | if (keyring) { |
@@ -526,7 +526,7 @@ int key_negate_and_link(struct key *key, | |||
526 | struct key *keyring, | 526 | struct key *keyring, |
527 | struct key *authkey) | 527 | struct key *authkey) |
528 | { | 528 | { |
529 | struct keyring_list *prealloc; | 529 | unsigned long prealloc; |
530 | struct timespec now; | 530 | struct timespec now; |
531 | int ret, awaken, link_ret = 0; | 531 | int ret, awaken, link_ret = 0; |
532 | 532 | ||
@@ -814,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
814 | key_perm_t perm, | 814 | key_perm_t perm, |
815 | unsigned long flags) | 815 | unsigned long flags) |
816 | { | 816 | { |
817 | struct keyring_list *prealloc; | 817 | unsigned long prealloc; |
818 | const struct cred *cred = current_cred(); | 818 | const struct cred *cred = current_cred(); |
819 | struct key_type *ktype; | 819 | struct key_type *ktype; |
820 | struct key *keyring, *key = NULL; | 820 | struct key *keyring, *key = NULL; |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 92024ed12e0a..5620f084dede 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,6 +25,8 @@ | |||
25 | (keyring)->payload.subscriptions, \ | 25 | (keyring)->payload.subscriptions, \ |
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | ||
28 | #define KEY_LINK_FIXQUOTA 1UL | ||
29 | |||
28 | /* | 30 | /* |
29 | * When plumbing the depths of the key tree, this sets a hard limit | 31 | * When plumbing the depths of the key tree, this sets a hard limit |
30 | * set on how deep we're willing to go. | 32 | * set on how deep we're willing to go. |
@@ -699,11 +701,11 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
699 | * Preallocate memory so that a key can be linked into to a keyring. | 701 | * Preallocate memory so that a key can be linked into to a keyring. |
700 | */ | 702 | */ |
701 | int __key_link_begin(struct key *keyring, const struct key_type *type, | 703 | int __key_link_begin(struct key *keyring, const struct key_type *type, |
702 | const char *description, | 704 | const char *description, unsigned long *_prealloc) |
703 | struct keyring_list **_prealloc) | ||
704 | __acquires(&keyring->sem) | 705 | __acquires(&keyring->sem) |
705 | { | 706 | { |
706 | struct keyring_list *klist, *nklist; | 707 | struct keyring_list *klist, *nklist; |
708 | unsigned long prealloc; | ||
707 | unsigned max; | 709 | unsigned max; |
708 | size_t size; | 710 | size_t size; |
709 | int loop, ret; | 711 | int loop, ret; |
@@ -746,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
746 | 748 | ||
747 | /* note replacement slot */ | 749 | /* note replacement slot */ |
748 | klist->delkey = nklist->delkey = loop; | 750 | klist->delkey = nklist->delkey = loop; |
751 | prealloc = (unsigned long)nklist; | ||
749 | goto done; | 752 | goto done; |
750 | } | 753 | } |
751 | } | 754 | } |
@@ -760,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
760 | if (klist && klist->nkeys < klist->maxkeys) { | 763 | if (klist && klist->nkeys < klist->maxkeys) { |
761 | /* there's sufficient slack space to append directly */ | 764 | /* there's sufficient slack space to append directly */ |
762 | nklist = NULL; | 765 | nklist = NULL; |
766 | prealloc = KEY_LINK_FIXQUOTA; | ||
763 | } else { | 767 | } else { |
764 | /* grow the key list */ | 768 | /* grow the key list */ |
765 | max = 4; | 769 | max = 4; |
@@ -794,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
794 | nklist->keys[nklist->delkey] = NULL; | 798 | nklist->keys[nklist->delkey] = NULL; |
795 | } | 799 | } |
796 | 800 | ||
801 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
797 | done: | 802 | done: |
798 | *_prealloc = nklist; | 803 | *_prealloc = prealloc; |
799 | kleave(" = 0"); | 804 | kleave(" = 0"); |
800 | return 0; | 805 | return 0; |
801 | 806 | ||
@@ -836,12 +841,12 @@ int __key_link_check_live_key(struct key *keyring, struct key *key) | |||
836 | * combination. | 841 | * combination. |
837 | */ | 842 | */ |
838 | void __key_link(struct key *keyring, struct key *key, | 843 | void __key_link(struct key *keyring, struct key *key, |
839 | struct keyring_list **_prealloc) | 844 | unsigned long *_prealloc) |
840 | { | 845 | { |
841 | struct keyring_list *klist, *nklist; | 846 | struct keyring_list *klist, *nklist; |
842 | 847 | ||
843 | nklist = *_prealloc; | 848 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
844 | *_prealloc = NULL; | 849 | *_prealloc = 0; |
845 | 850 | ||
846 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); | 851 | kenter("%d,%d,%p", keyring->serial, key->serial, nklist); |
847 | 852 | ||
@@ -881,20 +886,22 @@ void __key_link(struct key *keyring, struct key *key, | |||
881 | * Must be called with __key_link_begin() having being called. | 886 | * Must be called with __key_link_begin() having being called. |
882 | */ | 887 | */ |
883 | void __key_link_end(struct key *keyring, struct key_type *type, | 888 | void __key_link_end(struct key *keyring, struct key_type *type, |
884 | struct keyring_list *prealloc) | 889 | unsigned long prealloc) |
885 | __releases(&keyring->sem) | 890 | __releases(&keyring->sem) |
886 | { | 891 | { |
887 | BUG_ON(type == NULL); | 892 | BUG_ON(type == NULL); |
888 | BUG_ON(type->name == NULL); | 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 | if (type == &key_type_keyring) | 896 | if (type == &key_type_keyring) |
892 | up_write(&keyring_serialise_link_sem); | 897 | up_write(&keyring_serialise_link_sem); |
893 | 898 | ||
894 | if (prealloc) { | 899 | if (prealloc) { |
895 | kfree(prealloc); | 900 | if (prealloc & KEY_LINK_FIXQUOTA) |
896 | key_payload_reserve(keyring, | 901 | key_payload_reserve(keyring, |
897 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 902 | keyring->datalen - |
903 | KEYQUOTA_LINK_BYTES); | ||
904 | kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA)); | ||
898 | } | 905 | } |
899 | up_write(&keyring->sem); | 906 | up_write(&keyring->sem); |
900 | } | 907 | } |
@@ -921,7 +928,7 @@ void __key_link_end(struct key *keyring, struct key_type *type, | |||
921 | */ | 928 | */ |
922 | int key_link(struct key *keyring, struct key *key) | 929 | int key_link(struct key *keyring, struct key *key) |
923 | { | 930 | { |
924 | struct keyring_list *prealloc; | 931 | unsigned long prealloc; |
925 | int ret; | 932 | int ret; |
926 | 933 | ||
927 | key_check(keyring); | 934 | key_check(keyring); |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 9a7fb3914b27..a3dc0d460def 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -352,8 +352,8 @@ static int construct_alloc_key(struct key_type *type, | |||
352 | struct key_user *user, | 352 | struct key_user *user, |
353 | struct key **_key) | 353 | struct key **_key) |
354 | { | 354 | { |
355 | struct keyring_list *prealloc; | ||
356 | const struct cred *cred = current_cred(); | 355 | const struct cred *cred = current_cred(); |
356 | unsigned long prealloc; | ||
357 | struct key *key; | 357 | struct key *key; |
358 | key_ref_t key_ref; | 358 | key_ref_t key_ref; |
359 | int ret; | 359 | int ret; |