diff options
author | David Howells <dhowells@redhat.com> | 2005-06-24 01:00:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-24 03:05:18 -0400 |
commit | 76d8aeabfeb1c42641a81c44280177b9a08670d8 (patch) | |
tree | 0a584439bb44e440717aa77a1398ba9eea24a137 /security | |
parent | 7286aa9b9ab35f20b1ff16d867f4535701df99b5 (diff) |
[PATCH] keys: Discard key spinlock and use RCU for key payload
The attached patch changes the key implementation in a number of ways:
(1) It removes the spinlock from the key structure.
(2) The key flags are now accessed using atomic bitops instead of
write-locking the key spinlock and using C bitwise operators.
The three instantiation flags are dealt with with the construction
semaphore held during the request_key/instantiate/negate sequence, thus
rendering the spinlock superfluous.
The key flags are also now bit numbers not bit masks.
(3) The key payload is now accessed using RCU. This permits the recursive
keyring search algorithm to be simplified greatly since no locks need be
taken other than the usual RCU preemption disablement. Searching now does
not require any locks or semaphores to be held; merely that the starting
keyring be pinned.
(4) The keyring payload now includes an RCU head so that it can be disposed
of by call_rcu(). This requires that the payload be copied on unlink to
prevent introducing races in copy-down vs search-up.
(5) The user key payload is now a structure with the data following it. It
includes an RCU head like the keyring payload and for the same reason. It
also contains a data length because the data length in the key may be
changed on another CPU whilst an RCU protected read is in progress on the
payload. This would then see the supposed RCU payload and the on-key data
length getting out of sync.
I'm tempted to drop the key's datalen entirely, except that it's used in
conjunction with quota management and so is a little tricky to get rid
of.
(6) Update the keys documentation.
Signed-Off-By: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security')
-rw-r--r-- | security/keys/key.c | 94 | ||||
-rw-r--r-- | security/keys/keyctl.c | 23 | ||||
-rw-r--r-- | security/keys/keyring.c | 245 | ||||
-rw-r--r-- | security/keys/proc.c | 21 | ||||
-rw-r--r-- | security/keys/process_keys.c | 12 | ||||
-rw-r--r-- | security/keys/request_key.c | 32 | ||||
-rw-r--r-- | security/keys/user_defined.c | 85 |
7 files changed, 289 insertions, 223 deletions
diff --git a/security/keys/key.c b/security/keys/key.c index 59402c843203..1fdfccb3fe43 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -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 && |
@@ -405,23 +404,17 @@ static int __key_instantiate_and_link(struct key *key, | |||
405 | down_write(&key_construction_sem); | 404 | down_write(&key_construction_sem); |
406 | 405 | ||
407 | /* can't instantiate twice */ | 406 | /* can't instantiate twice */ |
408 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 407 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
409 | /* instantiate the key */ | 408 | /* instantiate the key */ |
410 | ret = key->type->instantiate(key, data, datalen); | 409 | ret = key->type->instantiate(key, data, datalen); |
411 | 410 | ||
412 | if (ret == 0) { | 411 | if (ret == 0) { |
413 | /* mark the key as being instantiated */ | 412 | /* mark the key as being instantiated */ |
414 | write_lock(&key->lock); | ||
415 | |||
416 | atomic_inc(&key->user->nikeys); | 413 | atomic_inc(&key->user->nikeys); |
417 | key->flags |= KEY_FLAG_INSTANTIATED; | 414 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
418 | 415 | ||
419 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 416 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
420 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
421 | awaken = 1; | 417 | awaken = 1; |
422 | } | ||
423 | |||
424 | write_unlock(&key->lock); | ||
425 | 418 | ||
426 | /* and link it into the destination keyring */ | 419 | /* and link it into the destination keyring */ |
427 | if (keyring) | 420 | if (keyring) |
@@ -486,21 +479,17 @@ int key_negate_and_link(struct key *key, | |||
486 | down_write(&key_construction_sem); | 479 | down_write(&key_construction_sem); |
487 | 480 | ||
488 | /* can't instantiate twice */ | 481 | /* can't instantiate twice */ |
489 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 482 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
490 | /* mark the key as being negatively instantiated */ | 483 | /* mark the key as being negatively instantiated */ |
491 | write_lock(&key->lock); | ||
492 | |||
493 | atomic_inc(&key->user->nikeys); | 484 | atomic_inc(&key->user->nikeys); |
494 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 485 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
486 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | ||
495 | now = current_kernel_time(); | 487 | now = current_kernel_time(); |
496 | key->expiry = now.tv_sec + timeout; | 488 | key->expiry = now.tv_sec + timeout; |
497 | 489 | ||
498 | if (key->flags & KEY_FLAG_USER_CONSTRUCT) { | 490 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
499 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
500 | awaken = 1; | 491 | awaken = 1; |
501 | } | ||
502 | 492 | ||
503 | write_unlock(&key->lock); | ||
504 | ret = 0; | 493 | ret = 0; |
505 | 494 | ||
506 | /* and link it into the destination keyring */ | 495 | /* and link it into the destination keyring */ |
@@ -553,8 +542,10 @@ static void key_cleanup(void *data) | |||
553 | rb_erase(&key->serial_node, &key_serial_tree); | 542 | rb_erase(&key->serial_node, &key_serial_tree); |
554 | spin_unlock(&key_serial_lock); | 543 | spin_unlock(&key_serial_lock); |
555 | 544 | ||
545 | key_check(key); | ||
546 | |||
556 | /* deal with the user's key tracking and quota */ | 547 | /* deal with the user's key tracking and quota */ |
557 | if (key->flags & KEY_FLAG_IN_QUOTA) { | 548 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { |
558 | spin_lock(&key->user->lock); | 549 | spin_lock(&key->user->lock); |
559 | key->user->qnkeys--; | 550 | key->user->qnkeys--; |
560 | key->user->qnbytes -= key->quotalen; | 551 | key->user->qnbytes -= key->quotalen; |
@@ -562,7 +553,7 @@ static void key_cleanup(void *data) | |||
562 | } | 553 | } |
563 | 554 | ||
564 | atomic_dec(&key->user->nkeys); | 555 | atomic_dec(&key->user->nkeys); |
565 | if (key->flags & KEY_FLAG_INSTANTIATED) | 556 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
566 | atomic_dec(&key->user->nikeys); | 557 | atomic_dec(&key->user->nikeys); |
567 | 558 | ||
568 | key_user_put(key->user); | 559 | key_user_put(key->user); |
@@ -631,9 +622,9 @@ struct key *key_lookup(key_serial_t id) | |||
631 | goto error; | 622 | goto error; |
632 | 623 | ||
633 | found: | 624 | found: |
634 | /* pretent doesn't exist if it's dead */ | 625 | /* pretend it doesn't exist if it's dead */ |
635 | if (atomic_read(&key->usage) == 0 || | 626 | if (atomic_read(&key->usage) == 0 || |
636 | (key->flags & KEY_FLAG_DEAD) || | 627 | test_bit(KEY_FLAG_DEAD, &key->flags) || |
637 | key->type == &key_type_dead) | 628 | key->type == &key_type_dead) |
638 | goto not_found; | 629 | goto not_found; |
639 | 630 | ||
@@ -708,12 +699,9 @@ static inline struct key *__key_update(struct key *key, const void *payload, | |||
708 | 699 | ||
709 | ret = key->type->update(key, payload, plen); | 700 | ret = key->type->update(key, payload, plen); |
710 | 701 | ||
711 | if (ret == 0) { | 702 | if (ret == 0) |
712 | /* updating a negative key instantiates it */ | 703 | /* updating a negative key instantiates it */ |
713 | write_lock(&key->lock); | 704 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
714 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
715 | write_unlock(&key->lock); | ||
716 | } | ||
717 | 705 | ||
718 | up_write(&key->sem); | 706 | up_write(&key->sem); |
719 | 707 | ||
@@ -841,12 +829,9 @@ int key_update(struct key *key, const void *payload, size_t plen) | |||
841 | down_write(&key->sem); | 829 | down_write(&key->sem); |
842 | ret = key->type->update(key, payload, plen); | 830 | ret = key->type->update(key, payload, plen); |
843 | 831 | ||
844 | if (ret == 0) { | 832 | if (ret == 0) |
845 | /* updating a negative key instantiates it */ | 833 | /* updating a negative key instantiates it */ |
846 | write_lock(&key->lock); | 834 | clear_bit(KEY_FLAG_NEGATIVE, &key->flags); |
847 | key->flags &= ~KEY_FLAG_NEGATIVE; | ||
848 | write_unlock(&key->lock); | ||
849 | } | ||
850 | 835 | ||
851 | up_write(&key->sem); | 836 | up_write(&key->sem); |
852 | } | 837 | } |
@@ -892,10 +877,7 @@ struct key *key_duplicate(struct key *source, const char *desc) | |||
892 | goto error2; | 877 | goto error2; |
893 | 878 | ||
894 | atomic_inc(&key->user->nikeys); | 879 | atomic_inc(&key->user->nikeys); |
895 | 880 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); | |
896 | write_lock(&key->lock); | ||
897 | key->flags |= KEY_FLAG_INSTANTIATED; | ||
898 | write_unlock(&key->lock); | ||
899 | 881 | ||
900 | error_k: | 882 | error_k: |
901 | up_read(&key_types_sem); | 883 | up_read(&key_types_sem); |
@@ -922,9 +904,7 @@ void key_revoke(struct key *key) | |||
922 | /* make sure no one's trying to change or use the key when we mark | 904 | /* make sure no one's trying to change or use the key when we mark |
923 | * it */ | 905 | * it */ |
924 | down_write(&key->sem); | 906 | down_write(&key->sem); |
925 | write_lock(&key->lock); | 907 | set_bit(KEY_FLAG_REVOKED, &key->flags); |
926 | key->flags |= KEY_FLAG_REVOKED; | ||
927 | write_unlock(&key->lock); | ||
928 | up_write(&key->sem); | 908 | up_write(&key->sem); |
929 | 909 | ||
930 | } /* end key_revoke() */ | 910 | } /* end key_revoke() */ |
@@ -975,24 +955,33 @@ void unregister_key_type(struct key_type *ktype) | |||
975 | /* withdraw the key type */ | 955 | /* withdraw the key type */ |
976 | list_del_init(&ktype->link); | 956 | list_del_init(&ktype->link); |
977 | 957 | ||
978 | /* need to withdraw all keys of this type */ | 958 | /* mark all the keys of this type dead */ |
979 | spin_lock(&key_serial_lock); | 959 | spin_lock(&key_serial_lock); |
980 | 960 | ||
981 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { | 961 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
982 | key = rb_entry(_n, struct key, serial_node); | 962 | key = rb_entry(_n, struct key, serial_node); |
983 | 963 | ||
984 | if (key->type != ktype) | 964 | if (key->type == ktype) |
985 | continue; | 965 | key->type = &key_type_dead; |
966 | } | ||
967 | |||
968 | spin_unlock(&key_serial_lock); | ||
969 | |||
970 | /* make sure everyone revalidates their keys */ | ||
971 | synchronize_kernel(); | ||
972 | |||
973 | /* we should now be able to destroy the payloads of all the keys of | ||
974 | * this type with impunity */ | ||
975 | spin_lock(&key_serial_lock); | ||
986 | 976 | ||
987 | write_lock(&key->lock); | 977 | for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) { |
988 | key->type = &key_type_dead; | 978 | key = rb_entry(_n, struct key, serial_node); |
989 | write_unlock(&key->lock); | ||
990 | 979 | ||
991 | /* there shouldn't be anyone looking at the description or | 980 | if (key->type == ktype) { |
992 | * payload now */ | 981 | if (ktype->destroy) |
993 | if (ktype->destroy) | 982 | ktype->destroy(key); |
994 | ktype->destroy(key); | 983 | memset(&key->payload, 0xbd, sizeof(key->payload)); |
995 | memset(&key->payload, 0xbd, sizeof(key->payload)); | 984 | } |
996 | } | 985 | } |
997 | 986 | ||
998 | spin_unlock(&key_serial_lock); | 987 | spin_unlock(&key_serial_lock); |
@@ -1037,4 +1026,5 @@ void __init key_init(void) | |||
1037 | 1026 | ||
1038 | /* link the two root keyrings together */ | 1027 | /* link the two root keyrings together */ |
1039 | key_link(&root_session_keyring, &root_user_keyring); | 1028 | key_link(&root_session_keyring, &root_user_keyring); |
1029 | |||
1040 | } /* end key_init() */ | 1030 | } /* end key_init() */ |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index dc0011b3fac9..cedb7326de29 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -728,7 +728,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
728 | /* make the changes with the locks held to prevent chown/chown races */ | 728 | /* make the changes with the locks held to prevent chown/chown races */ |
729 | ret = -EACCES; | 729 | ret = -EACCES; |
730 | down_write(&key->sem); | 730 | down_write(&key->sem); |
731 | write_lock(&key->lock); | ||
732 | 731 | ||
733 | if (!capable(CAP_SYS_ADMIN)) { | 732 | if (!capable(CAP_SYS_ADMIN)) { |
734 | /* only the sysadmin can chown a key to some other UID */ | 733 | /* only the sysadmin can chown a key to some other UID */ |
@@ -755,7 +754,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
755 | ret = 0; | 754 | ret = 0; |
756 | 755 | ||
757 | no_access: | 756 | no_access: |
758 | write_unlock(&key->lock); | ||
759 | up_write(&key->sem); | 757 | up_write(&key->sem); |
760 | key_put(key); | 758 | key_put(key); |
761 | error: | 759 | error: |
@@ -784,26 +782,19 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
784 | goto error; | 782 | goto error; |
785 | } | 783 | } |
786 | 784 | ||
787 | /* make the changes with the locks held to prevent chown/chmod | 785 | /* make the changes with the locks held to prevent chown/chmod races */ |
788 | * races */ | ||
789 | ret = -EACCES; | 786 | ret = -EACCES; |
790 | down_write(&key->sem); | 787 | down_write(&key->sem); |
791 | write_lock(&key->lock); | ||
792 | 788 | ||
793 | /* if we're not the sysadmin, we can only chmod a key that we | 789 | /* if we're not the sysadmin, we can only change a key that we own */ |
794 | * own */ | 790 | if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { |
795 | if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid) | 791 | key->perm = perm; |
796 | goto no_access; | 792 | ret = 0; |
797 | 793 | } | |
798 | /* changing the permissions mask */ | ||
799 | key->perm = perm; | ||
800 | ret = 0; | ||
801 | 794 | ||
802 | no_access: | ||
803 | write_unlock(&key->lock); | ||
804 | up_write(&key->sem); | 795 | up_write(&key->sem); |
805 | key_put(key); | 796 | key_put(key); |
806 | error: | 797 | error: |
807 | return ret; | 798 | return ret; |
808 | 799 | ||
809 | } /* end keyctl_setperm_key() */ | 800 | } /* end keyctl_setperm_key() */ |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e2ab4f8e7481..c9a5de197487 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -132,10 +132,17 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); | 132 | (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key); |
133 | 133 | ||
134 | ret = 0; | 134 | ret = 0; |
135 | sklist = source->payload.subscriptions; | ||
136 | 135 | ||
137 | if (sklist && sklist->nkeys > 0) { | 136 | /* find out how many keys are currently linked */ |
137 | rcu_read_lock(); | ||
138 | sklist = rcu_dereference(source->payload.subscriptions); | ||
139 | max = 0; | ||
140 | if (sklist) | ||
138 | max = sklist->nkeys; | 141 | max = sklist->nkeys; |
142 | rcu_read_unlock(); | ||
143 | |||
144 | /* allocate a new payload and stuff load with key links */ | ||
145 | if (max > 0) { | ||
139 | BUG_ON(max > limit); | 146 | BUG_ON(max > limit); |
140 | 147 | ||
141 | max = (max + 3) & ~3; | 148 | max = (max + 3) & ~3; |
@@ -148,6 +155,10 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
148 | if (!klist) | 155 | if (!klist) |
149 | goto error; | 156 | goto error; |
150 | 157 | ||
158 | /* set links */ | ||
159 | rcu_read_lock(); | ||
160 | sklist = rcu_dereference(source->payload.subscriptions); | ||
161 | |||
151 | klist->maxkeys = max; | 162 | klist->maxkeys = max; |
152 | klist->nkeys = sklist->nkeys; | 163 | klist->nkeys = sklist->nkeys; |
153 | memcpy(klist->keys, | 164 | memcpy(klist->keys, |
@@ -157,7 +168,9 @@ static int keyring_duplicate(struct key *keyring, const struct key *source) | |||
157 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 168 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
158 | atomic_inc(&klist->keys[loop]->usage); | 169 | atomic_inc(&klist->keys[loop]->usage); |
159 | 170 | ||
160 | keyring->payload.subscriptions = klist; | 171 | rcu_read_unlock(); |
172 | |||
173 | rcu_assign_pointer(keyring->payload.subscriptions, klist); | ||
161 | ret = 0; | 174 | ret = 0; |
162 | } | 175 | } |
163 | 176 | ||
@@ -192,7 +205,7 @@ static void keyring_destroy(struct key *keyring) | |||
192 | write_unlock(&keyring_name_lock); | 205 | write_unlock(&keyring_name_lock); |
193 | } | 206 | } |
194 | 207 | ||
195 | klist = keyring->payload.subscriptions; | 208 | klist = rcu_dereference(keyring->payload.subscriptions); |
196 | if (klist) { | 209 | if (klist) { |
197 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 210 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
198 | key_put(klist->keys[loop]); | 211 | key_put(klist->keys[loop]); |
@@ -216,17 +229,20 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m) | |||
216 | seq_puts(m, "[anon]"); | 229 | seq_puts(m, "[anon]"); |
217 | } | 230 | } |
218 | 231 | ||
219 | klist = keyring->payload.subscriptions; | 232 | rcu_read_lock(); |
233 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
220 | if (klist) | 234 | if (klist) |
221 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); | 235 | seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys); |
222 | else | 236 | else |
223 | seq_puts(m, ": empty"); | 237 | seq_puts(m, ": empty"); |
238 | rcu_read_unlock(); | ||
224 | 239 | ||
225 | } /* end keyring_describe() */ | 240 | } /* end keyring_describe() */ |
226 | 241 | ||
227 | /*****************************************************************************/ | 242 | /*****************************************************************************/ |
228 | /* | 243 | /* |
229 | * read a list of key IDs from the keyring's contents | 244 | * read a list of key IDs from the keyring's contents |
245 | * - the keyring's semaphore is read-locked | ||
230 | */ | 246 | */ |
231 | static long keyring_read(const struct key *keyring, | 247 | static long keyring_read(const struct key *keyring, |
232 | char __user *buffer, size_t buflen) | 248 | char __user *buffer, size_t buflen) |
@@ -237,7 +253,7 @@ static long keyring_read(const struct key *keyring, | |||
237 | int loop, ret; | 253 | int loop, ret; |
238 | 254 | ||
239 | ret = 0; | 255 | ret = 0; |
240 | klist = keyring->payload.subscriptions; | 256 | klist = rcu_dereference(keyring->payload.subscriptions); |
241 | 257 | ||
242 | if (klist) { | 258 | if (klist) { |
243 | /* calculate how much data we could return */ | 259 | /* calculate how much data we could return */ |
@@ -320,7 +336,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
320 | key_match_func_t match) | 336 | key_match_func_t match) |
321 | { | 337 | { |
322 | struct { | 338 | struct { |
323 | struct key *keyring; | 339 | struct keyring_list *keylist; |
324 | int kix; | 340 | int kix; |
325 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 341 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
326 | 342 | ||
@@ -328,10 +344,12 @@ struct key *keyring_search_aux(struct key *keyring, | |||
328 | struct timespec now; | 344 | struct timespec now; |
329 | struct key *key; | 345 | struct key *key; |
330 | long err; | 346 | long err; |
331 | int sp, psp, kix; | 347 | int sp, kix; |
332 | 348 | ||
333 | key_check(keyring); | 349 | key_check(keyring); |
334 | 350 | ||
351 | rcu_read_lock(); | ||
352 | |||
335 | /* top keyring must have search permission to begin the search */ | 353 | /* top keyring must have search permission to begin the search */ |
336 | key = ERR_PTR(-EACCES); | 354 | key = ERR_PTR(-EACCES); |
337 | if (!key_permission(keyring, KEY_SEARCH)) | 355 | if (!key_permission(keyring, KEY_SEARCH)) |
@@ -347,11 +365,10 @@ struct key *keyring_search_aux(struct key *keyring, | |||
347 | 365 | ||
348 | /* start processing a new keyring */ | 366 | /* start processing a new keyring */ |
349 | descend: | 367 | descend: |
350 | read_lock(&keyring->lock); | 368 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
351 | if (keyring->flags & KEY_FLAG_REVOKED) | ||
352 | goto not_this_keyring; | 369 | goto not_this_keyring; |
353 | 370 | ||
354 | keylist = keyring->payload.subscriptions; | 371 | keylist = rcu_dereference(keyring->payload.subscriptions); |
355 | if (!keylist) | 372 | if (!keylist) |
356 | goto not_this_keyring; | 373 | goto not_this_keyring; |
357 | 374 | ||
@@ -364,7 +381,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
364 | continue; | 381 | continue; |
365 | 382 | ||
366 | /* skip revoked keys and expired keys */ | 383 | /* skip revoked keys and expired keys */ |
367 | if (key->flags & KEY_FLAG_REVOKED) | 384 | if (test_bit(KEY_FLAG_REVOKED, &key->flags)) |
368 | continue; | 385 | continue; |
369 | 386 | ||
370 | if (key->expiry && now.tv_sec >= key->expiry) | 387 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -379,7 +396,7 @@ struct key *keyring_search_aux(struct key *keyring, | |||
379 | continue; | 396 | continue; |
380 | 397 | ||
381 | /* we set a different error code if we find a negative key */ | 398 | /* we set a different error code if we find a negative key */ |
382 | if (key->flags & KEY_FLAG_NEGATIVE) { | 399 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
383 | err = -ENOKEY; | 400 | err = -ENOKEY; |
384 | continue; | 401 | continue; |
385 | } | 402 | } |
@@ -390,48 +407,37 @@ struct key *keyring_search_aux(struct key *keyring, | |||
390 | /* search through the keyrings nested in this one */ | 407 | /* search through the keyrings nested in this one */ |
391 | kix = 0; | 408 | kix = 0; |
392 | ascend: | 409 | ascend: |
393 | while (kix < keylist->nkeys) { | 410 | for (; kix < keylist->nkeys; kix++) { |
394 | key = keylist->keys[kix]; | 411 | key = keylist->keys[kix]; |
395 | if (key->type != &key_type_keyring) | 412 | if (key->type != &key_type_keyring) |
396 | goto next; | 413 | continue; |
397 | 414 | ||
398 | /* recursively search nested keyrings | 415 | /* recursively search nested keyrings |
399 | * - only search keyrings for which we have search permission | 416 | * - only search keyrings for which we have search permission |
400 | */ | 417 | */ |
401 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) | 418 | if (sp >= KEYRING_SEARCH_MAX_DEPTH) |
402 | goto next; | 419 | continue; |
403 | 420 | ||
404 | if (!key_permission(key, KEY_SEARCH)) | 421 | if (!key_permission(key, KEY_SEARCH)) |
405 | goto next; | 422 | continue; |
406 | |||
407 | /* evade loops in the keyring tree */ | ||
408 | for (psp = 0; psp < sp; psp++) | ||
409 | if (stack[psp].keyring == keyring) | ||
410 | goto next; | ||
411 | 423 | ||
412 | /* stack the current position */ | 424 | /* stack the current position */ |
413 | stack[sp].keyring = keyring; | 425 | stack[sp].keylist = keylist; |
414 | stack[sp].kix = kix; | 426 | stack[sp].kix = kix; |
415 | sp++; | 427 | sp++; |
416 | 428 | ||
417 | /* begin again with the new keyring */ | 429 | /* begin again with the new keyring */ |
418 | keyring = key; | 430 | keyring = key; |
419 | goto descend; | 431 | goto descend; |
420 | |||
421 | next: | ||
422 | kix++; | ||
423 | } | 432 | } |
424 | 433 | ||
425 | /* the keyring we're looking at was disqualified or didn't contain a | 434 | /* the keyring we're looking at was disqualified or didn't contain a |
426 | * matching key */ | 435 | * matching key */ |
427 | not_this_keyring: | 436 | not_this_keyring: |
428 | read_unlock(&keyring->lock); | ||
429 | |||
430 | if (sp > 0) { | 437 | if (sp > 0) { |
431 | /* resume the processing of a keyring higher up in the tree */ | 438 | /* resume the processing of a keyring higher up in the tree */ |
432 | sp--; | 439 | sp--; |
433 | keyring = stack[sp].keyring; | 440 | keylist = stack[sp].keylist; |
434 | keylist = keyring->payload.subscriptions; | ||
435 | kix = stack[sp].kix + 1; | 441 | kix = stack[sp].kix + 1; |
436 | goto ascend; | 442 | goto ascend; |
437 | } | 443 | } |
@@ -442,16 +448,9 @@ struct key *keyring_search_aux(struct key *keyring, | |||
442 | /* we found a viable match */ | 448 | /* we found a viable match */ |
443 | found: | 449 | found: |
444 | atomic_inc(&key->usage); | 450 | atomic_inc(&key->usage); |
445 | read_unlock(&keyring->lock); | ||
446 | |||
447 | /* unwind the keyring stack */ | ||
448 | while (sp > 0) { | ||
449 | sp--; | ||
450 | read_unlock(&stack[sp].keyring->lock); | ||
451 | } | ||
452 | |||
453 | key_check(key); | 451 | key_check(key); |
454 | error: | 452 | error: |
453 | rcu_read_unlock(); | ||
455 | return key; | 454 | return key; |
456 | 455 | ||
457 | } /* end keyring_search_aux() */ | 456 | } /* end keyring_search_aux() */ |
@@ -489,7 +488,9 @@ struct key *__keyring_search_one(struct key *keyring, | |||
489 | struct key *key; | 488 | struct key *key; |
490 | int loop; | 489 | int loop; |
491 | 490 | ||
492 | klist = keyring->payload.subscriptions; | 491 | rcu_read_lock(); |
492 | |||
493 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
493 | if (klist) { | 494 | if (klist) { |
494 | for (loop = 0; loop < klist->nkeys; loop++) { | 495 | for (loop = 0; loop < klist->nkeys; loop++) { |
495 | key = klist->keys[loop]; | 496 | key = klist->keys[loop]; |
@@ -497,7 +498,7 @@ struct key *__keyring_search_one(struct key *keyring, | |||
497 | if (key->type == ktype && | 498 | if (key->type == ktype && |
498 | key->type->match(key, description) && | 499 | key->type->match(key, description) && |
499 | key_permission(key, perm) && | 500 | key_permission(key, perm) && |
500 | !(key->flags & KEY_FLAG_REVOKED) | 501 | !test_bit(KEY_FLAG_REVOKED, &key->flags) |
501 | ) | 502 | ) |
502 | goto found; | 503 | goto found; |
503 | } | 504 | } |
@@ -509,6 +510,7 @@ struct key *__keyring_search_one(struct key *keyring, | |||
509 | found: | 510 | found: |
510 | atomic_inc(&key->usage); | 511 | atomic_inc(&key->usage); |
511 | error: | 512 | error: |
513 | rcu_read_unlock(); | ||
512 | return key; | 514 | return key; |
513 | 515 | ||
514 | } /* end __keyring_search_one() */ | 516 | } /* end __keyring_search_one() */ |
@@ -540,7 +542,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
540 | &keyring_name_hash[bucket], | 542 | &keyring_name_hash[bucket], |
541 | type_data.link | 543 | type_data.link |
542 | ) { | 544 | ) { |
543 | if (keyring->flags & KEY_FLAG_REVOKED) | 545 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
544 | continue; | 546 | continue; |
545 | 547 | ||
546 | if (strcmp(keyring->description, name) != 0) | 548 | if (strcmp(keyring->description, name) != 0) |
@@ -579,7 +581,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound) | |||
579 | static int keyring_detect_cycle(struct key *A, struct key *B) | 581 | static int keyring_detect_cycle(struct key *A, struct key *B) |
580 | { | 582 | { |
581 | struct { | 583 | struct { |
582 | struct key *subtree; | 584 | struct keyring_list *keylist; |
583 | int kix; | 585 | int kix; |
584 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 586 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
585 | 587 | ||
@@ -587,20 +589,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
587 | struct key *subtree, *key; | 589 | struct key *subtree, *key; |
588 | int sp, kix, ret; | 590 | int sp, kix, ret; |
589 | 591 | ||
592 | rcu_read_lock(); | ||
593 | |||
590 | ret = -EDEADLK; | 594 | ret = -EDEADLK; |
591 | if (A == B) | 595 | if (A == B) |
592 | goto error; | 596 | goto cycle_detected; |
593 | 597 | ||
594 | subtree = B; | 598 | subtree = B; |
595 | sp = 0; | 599 | sp = 0; |
596 | 600 | ||
597 | /* start processing a new keyring */ | 601 | /* start processing a new keyring */ |
598 | descend: | 602 | descend: |
599 | read_lock(&subtree->lock); | 603 | if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) |
600 | if (subtree->flags & KEY_FLAG_REVOKED) | ||
601 | goto not_this_keyring; | 604 | goto not_this_keyring; |
602 | 605 | ||
603 | keylist = subtree->payload.subscriptions; | 606 | keylist = rcu_dereference(subtree->payload.subscriptions); |
604 | if (!keylist) | 607 | if (!keylist) |
605 | goto not_this_keyring; | 608 | goto not_this_keyring; |
606 | kix = 0; | 609 | kix = 0; |
@@ -619,7 +622,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
619 | goto too_deep; | 622 | goto too_deep; |
620 | 623 | ||
621 | /* stack the current position */ | 624 | /* stack the current position */ |
622 | stack[sp].subtree = subtree; | 625 | stack[sp].keylist = keylist; |
623 | stack[sp].kix = kix; | 626 | stack[sp].kix = kix; |
624 | sp++; | 627 | sp++; |
625 | 628 | ||
@@ -632,13 +635,10 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
632 | /* the keyring we're looking at was disqualified or didn't contain a | 635 | /* the keyring we're looking at was disqualified or didn't contain a |
633 | * matching key */ | 636 | * matching key */ |
634 | not_this_keyring: | 637 | not_this_keyring: |
635 | read_unlock(&subtree->lock); | ||
636 | |||
637 | if (sp > 0) { | 638 | if (sp > 0) { |
638 | /* resume the checking of a keyring higher up in the tree */ | 639 | /* resume the checking of a keyring higher up in the tree */ |
639 | sp--; | 640 | sp--; |
640 | subtree = stack[sp].subtree; | 641 | keylist = stack[sp].keylist; |
641 | keylist = subtree->payload.subscriptions; | ||
642 | kix = stack[sp].kix + 1; | 642 | kix = stack[sp].kix + 1; |
643 | goto ascend; | 643 | goto ascend; |
644 | } | 644 | } |
@@ -646,30 +646,36 @@ static int keyring_detect_cycle(struct key *A, struct key *B) | |||
646 | ret = 0; /* no cycles detected */ | 646 | ret = 0; /* no cycles detected */ |
647 | 647 | ||
648 | error: | 648 | error: |
649 | rcu_read_unlock(); | ||
649 | return ret; | 650 | return ret; |
650 | 651 | ||
651 | too_deep: | 652 | too_deep: |
652 | ret = -ELOOP; | 653 | ret = -ELOOP; |
653 | goto error_unwind; | 654 | goto error; |
655 | |||
654 | cycle_detected: | 656 | cycle_detected: |
655 | ret = -EDEADLK; | 657 | ret = -EDEADLK; |
656 | error_unwind: | ||
657 | read_unlock(&subtree->lock); | ||
658 | |||
659 | /* unwind the keyring stack */ | ||
660 | while (sp > 0) { | ||
661 | sp--; | ||
662 | read_unlock(&stack[sp].subtree->lock); | ||
663 | } | ||
664 | |||
665 | goto error; | 658 | goto error; |
666 | 659 | ||
667 | } /* end keyring_detect_cycle() */ | 660 | } /* end keyring_detect_cycle() */ |
668 | 661 | ||
669 | /*****************************************************************************/ | 662 | /*****************************************************************************/ |
670 | /* | 663 | /* |
664 | * dispose of a keyring list after the RCU grace period | ||
665 | */ | ||
666 | static void keyring_link_rcu_disposal(struct rcu_head *rcu) | ||
667 | { | ||
668 | struct keyring_list *klist = | ||
669 | container_of(rcu, struct keyring_list, rcu); | ||
670 | |||
671 | kfree(klist); | ||
672 | |||
673 | } /* end keyring_link_rcu_disposal() */ | ||
674 | |||
675 | /*****************************************************************************/ | ||
676 | /* | ||
671 | * link a key into to a keyring | 677 | * link a key into to a keyring |
672 | * - must be called with the keyring's semaphore held | 678 | * - must be called with the keyring's semaphore write-locked |
673 | */ | 679 | */ |
674 | int __key_link(struct key *keyring, struct key *key) | 680 | int __key_link(struct key *keyring, struct key *key) |
675 | { | 681 | { |
@@ -679,7 +685,7 @@ int __key_link(struct key *keyring, struct key *key) | |||
679 | int ret; | 685 | int ret; |
680 | 686 | ||
681 | ret = -EKEYREVOKED; | 687 | ret = -EKEYREVOKED; |
682 | if (keyring->flags & KEY_FLAG_REVOKED) | 688 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) |
683 | goto error; | 689 | goto error; |
684 | 690 | ||
685 | ret = -ENOTDIR; | 691 | ret = -ENOTDIR; |
@@ -710,9 +716,10 @@ int __key_link(struct key *keyring, struct key *key) | |||
710 | /* there's sufficient slack space to add directly */ | 716 | /* there's sufficient slack space to add directly */ |
711 | atomic_inc(&key->usage); | 717 | atomic_inc(&key->usage); |
712 | 718 | ||
713 | write_lock(&keyring->lock); | 719 | klist->keys[klist->nkeys] = key; |
714 | klist->keys[klist->nkeys++] = key; | 720 | smp_wmb(); |
715 | write_unlock(&keyring->lock); | 721 | klist->nkeys++; |
722 | smp_wmb(); | ||
716 | 723 | ||
717 | ret = 0; | 724 | ret = 0; |
718 | } | 725 | } |
@@ -723,6 +730,8 @@ int __key_link(struct key *keyring, struct key *key) | |||
723 | max += klist->maxkeys; | 730 | max += klist->maxkeys; |
724 | 731 | ||
725 | ret = -ENFILE; | 732 | ret = -ENFILE; |
733 | if (max > 65535) | ||
734 | goto error3; | ||
726 | size = sizeof(*klist) + sizeof(*key) * max; | 735 | size = sizeof(*klist) + sizeof(*key) * max; |
727 | if (size > PAGE_SIZE) | 736 | if (size > PAGE_SIZE) |
728 | goto error3; | 737 | goto error3; |
@@ -743,14 +752,13 @@ int __key_link(struct key *keyring, struct key *key) | |||
743 | 752 | ||
744 | /* add the key into the new space */ | 753 | /* add the key into the new space */ |
745 | atomic_inc(&key->usage); | 754 | atomic_inc(&key->usage); |
746 | |||
747 | write_lock(&keyring->lock); | ||
748 | keyring->payload.subscriptions = nklist; | ||
749 | nklist->keys[nklist->nkeys++] = key; | 755 | nklist->keys[nklist->nkeys++] = key; |
750 | write_unlock(&keyring->lock); | 756 | |
757 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | ||
751 | 758 | ||
752 | /* dispose of the old keyring list */ | 759 | /* dispose of the old keyring list */ |
753 | kfree(klist); | 760 | if (klist) |
761 | call_rcu(&klist->rcu, keyring_link_rcu_disposal); | ||
754 | 762 | ||
755 | ret = 0; | 763 | ret = 0; |
756 | } | 764 | } |
@@ -791,11 +799,26 @@ EXPORT_SYMBOL(key_link); | |||
791 | 799 | ||
792 | /*****************************************************************************/ | 800 | /*****************************************************************************/ |
793 | /* | 801 | /* |
802 | * dispose of a keyring list after the RCU grace period, freeing the unlinked | ||
803 | * key | ||
804 | */ | ||
805 | static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | ||
806 | { | ||
807 | struct keyring_list *klist = | ||
808 | container_of(rcu, struct keyring_list, rcu); | ||
809 | |||
810 | key_put(klist->keys[klist->delkey]); | ||
811 | kfree(klist); | ||
812 | |||
813 | } /* end keyring_unlink_rcu_disposal() */ | ||
814 | |||
815 | /*****************************************************************************/ | ||
816 | /* | ||
794 | * unlink the first link to a key from a keyring | 817 | * unlink the first link to a key from a keyring |
795 | */ | 818 | */ |
796 | int key_unlink(struct key *keyring, struct key *key) | 819 | int key_unlink(struct key *keyring, struct key *key) |
797 | { | 820 | { |
798 | struct keyring_list *klist; | 821 | struct keyring_list *klist, *nklist; |
799 | int loop, ret; | 822 | int loop, ret; |
800 | 823 | ||
801 | key_check(keyring); | 824 | key_check(keyring); |
@@ -819,31 +842,45 @@ int key_unlink(struct key *keyring, struct key *key) | |||
819 | ret = -ENOENT; | 842 | ret = -ENOENT; |
820 | goto error; | 843 | goto error; |
821 | 844 | ||
822 | key_is_present: | 845 | key_is_present: |
846 | /* we need to copy the key list for RCU purposes */ | ||
847 | nklist = kmalloc(sizeof(*klist) + sizeof(*key) * klist->maxkeys, | ||
848 | GFP_KERNEL); | ||
849 | if (!nklist) | ||
850 | goto nomem; | ||
851 | nklist->maxkeys = klist->maxkeys; | ||
852 | nklist->nkeys = klist->nkeys - 1; | ||
853 | |||
854 | if (loop > 0) | ||
855 | memcpy(&nklist->keys[0], | ||
856 | &klist->keys[0], | ||
857 | loop * sizeof(klist->keys[0])); | ||
858 | |||
859 | if (loop < nklist->nkeys) | ||
860 | memcpy(&nklist->keys[loop], | ||
861 | &klist->keys[loop + 1], | ||
862 | (nklist->nkeys - loop) * sizeof(klist->keys[0])); | ||
863 | |||
823 | /* adjust the user's quota */ | 864 | /* adjust the user's quota */ |
824 | key_payload_reserve(keyring, | 865 | key_payload_reserve(keyring, |
825 | keyring->datalen - KEYQUOTA_LINK_BYTES); | 866 | keyring->datalen - KEYQUOTA_LINK_BYTES); |
826 | 867 | ||
827 | /* shuffle down the key pointers | 868 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
828 | * - it might be worth shrinking the allocated memory, but that runs | ||
829 | * the risk of ENOMEM as we would have to copy | ||
830 | */ | ||
831 | write_lock(&keyring->lock); | ||
832 | 869 | ||
833 | klist->nkeys--; | 870 | up_write(&keyring->sem); |
834 | if (loop < klist->nkeys) | ||
835 | memcpy(&klist->keys[loop], | ||
836 | &klist->keys[loop + 1], | ||
837 | (klist->nkeys - loop) * sizeof(struct key *)); | ||
838 | 871 | ||
839 | write_unlock(&keyring->lock); | 872 | /* schedule for later cleanup */ |
873 | klist->delkey = loop; | ||
874 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | ||
840 | 875 | ||
841 | up_write(&keyring->sem); | ||
842 | key_put(key); | ||
843 | ret = 0; | 876 | ret = 0; |
844 | 877 | ||
845 | error: | 878 | error: |
846 | return ret; | 879 | return ret; |
880 | nomem: | ||
881 | ret = -ENOMEM; | ||
882 | up_write(&keyring->sem); | ||
883 | goto error; | ||
847 | 884 | ||
848 | } /* end key_unlink() */ | 885 | } /* end key_unlink() */ |
849 | 886 | ||
@@ -851,13 +888,32 @@ EXPORT_SYMBOL(key_unlink); | |||
851 | 888 | ||
852 | /*****************************************************************************/ | 889 | /*****************************************************************************/ |
853 | /* | 890 | /* |
891 | * dispose of a keyring list after the RCU grace period, releasing the keys it | ||
892 | * links to | ||
893 | */ | ||
894 | static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | ||
895 | { | ||
896 | struct keyring_list *klist; | ||
897 | int loop; | ||
898 | |||
899 | klist = container_of(rcu, struct keyring_list, rcu); | ||
900 | |||
901 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | ||
902 | key_put(klist->keys[loop]); | ||
903 | |||
904 | kfree(klist); | ||
905 | |||
906 | } /* end keyring_clear_rcu_disposal() */ | ||
907 | |||
908 | /*****************************************************************************/ | ||
909 | /* | ||
854 | * clear the specified process keyring | 910 | * clear the specified process keyring |
855 | * - implements keyctl(KEYCTL_CLEAR) | 911 | * - implements keyctl(KEYCTL_CLEAR) |
856 | */ | 912 | */ |
857 | int keyring_clear(struct key *keyring) | 913 | int keyring_clear(struct key *keyring) |
858 | { | 914 | { |
859 | struct keyring_list *klist; | 915 | struct keyring_list *klist; |
860 | int loop, ret; | 916 | int ret; |
861 | 917 | ||
862 | ret = -ENOTDIR; | 918 | ret = -ENOTDIR; |
863 | if (keyring->type == &key_type_keyring) { | 919 | if (keyring->type == &key_type_keyring) { |
@@ -870,20 +926,15 @@ int keyring_clear(struct key *keyring) | |||
870 | key_payload_reserve(keyring, | 926 | key_payload_reserve(keyring, |
871 | sizeof(struct keyring_list)); | 927 | sizeof(struct keyring_list)); |
872 | 928 | ||
873 | write_lock(&keyring->lock); | 929 | rcu_assign_pointer(keyring->payload.subscriptions, |
874 | keyring->payload.subscriptions = NULL; | 930 | NULL); |
875 | write_unlock(&keyring->lock); | ||
876 | } | 931 | } |
877 | 932 | ||
878 | up_write(&keyring->sem); | 933 | up_write(&keyring->sem); |
879 | 934 | ||
880 | /* free the keys after the locks have been dropped */ | 935 | /* free the keys after the locks have been dropped */ |
881 | if (klist) { | 936 | if (klist) |
882 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 937 | call_rcu(&klist->rcu, keyring_clear_rcu_disposal); |
883 | key_put(klist->keys[loop]); | ||
884 | |||
885 | kfree(klist); | ||
886 | } | ||
887 | 938 | ||
888 | ret = 0; | 939 | ret = 0; |
889 | } | 940 | } |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 91343b85c39c..c55cf1fd0826 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -140,7 +140,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
140 | 140 | ||
141 | now = current_kernel_time(); | 141 | now = current_kernel_time(); |
142 | 142 | ||
143 | read_lock(&key->lock); | 143 | rcu_read_lock(); |
144 | 144 | ||
145 | /* come up with a suitable timeout value */ | 145 | /* come up with a suitable timeout value */ |
146 | if (key->expiry == 0) { | 146 | if (key->expiry == 0) { |
@@ -164,14 +164,17 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
164 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); | 164 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); |
165 | } | 165 | } |
166 | 166 | ||
167 | #define showflag(KEY, LETTER, FLAG) \ | ||
168 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | ||
169 | |||
167 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ", | 170 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ", |
168 | key->serial, | 171 | key->serial, |
169 | key->flags & KEY_FLAG_INSTANTIATED ? 'I' : '-', | 172 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
170 | key->flags & KEY_FLAG_REVOKED ? 'R' : '-', | 173 | showflag(key, 'R', KEY_FLAG_REVOKED), |
171 | key->flags & KEY_FLAG_DEAD ? 'D' : '-', | 174 | showflag(key, 'D', KEY_FLAG_DEAD), |
172 | key->flags & KEY_FLAG_IN_QUOTA ? 'Q' : '-', | 175 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
173 | key->flags & KEY_FLAG_USER_CONSTRUCT ? 'U' : '-', | 176 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
174 | key->flags & KEY_FLAG_NEGATIVE ? 'N' : '-', | 177 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
175 | atomic_read(&key->usage), | 178 | atomic_read(&key->usage), |
176 | xbuf, | 179 | xbuf, |
177 | key->perm, | 180 | key->perm, |
@@ -179,11 +182,13 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
179 | key->gid, | 182 | key->gid, |
180 | key->type->name); | 183 | key->type->name); |
181 | 184 | ||
185 | #undef showflag | ||
186 | |||
182 | if (key->type->describe) | 187 | if (key->type->describe) |
183 | key->type->describe(key, m); | 188 | key->type->describe(key, m); |
184 | seq_putc(m, '\n'); | 189 | seq_putc(m, '\n'); |
185 | 190 | ||
186 | read_unlock(&key->lock); | 191 | rcu_read_unlock(); |
187 | 192 | ||
188 | return 0; | 193 | return 0; |
189 | 194 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 2eb0e471cd40..059c350cac46 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -38,10 +38,9 @@ struct key root_user_keyring = { | |||
38 | .serial = 2, | 38 | .serial = 2, |
39 | .type = &key_type_keyring, | 39 | .type = &key_type_keyring, |
40 | .user = &root_key_user, | 40 | .user = &root_key_user, |
41 | .lock = RW_LOCK_UNLOCKED, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | 41 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), |
43 | .perm = KEY_USR_ALL, | 42 | .perm = KEY_USR_ALL, |
44 | .flags = KEY_FLAG_INSTANTIATED, | 43 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
45 | .description = "_uid.0", | 44 | .description = "_uid.0", |
46 | #ifdef KEY_DEBUGGING | 45 | #ifdef KEY_DEBUGGING |
47 | .magic = KEY_DEBUG_MAGIC, | 46 | .magic = KEY_DEBUG_MAGIC, |
@@ -54,10 +53,9 @@ struct key root_session_keyring = { | |||
54 | .serial = 1, | 53 | .serial = 1, |
55 | .type = &key_type_keyring, | 54 | .type = &key_type_keyring, |
56 | .user = &root_key_user, | 55 | .user = &root_key_user, |
57 | .lock = RW_LOCK_UNLOCKED, | ||
58 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | 56 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), |
59 | .perm = KEY_USR_ALL, | 57 | .perm = KEY_USR_ALL, |
60 | .flags = KEY_FLAG_INSTANTIATED, | 58 | .flags = 1 << KEY_FLAG_INSTANTIATED, |
61 | .description = "_uid_ses.0", | 59 | .description = "_uid_ses.0", |
62 | #ifdef KEY_DEBUGGING | 60 | #ifdef KEY_DEBUGGING |
63 | .magic = KEY_DEBUG_MAGIC, | 61 | .magic = KEY_DEBUG_MAGIC, |
@@ -349,9 +347,7 @@ void key_fsuid_changed(struct task_struct *tsk) | |||
349 | /* update the ownership of the thread keyring */ | 347 | /* update the ownership of the thread keyring */ |
350 | if (tsk->thread_keyring) { | 348 | if (tsk->thread_keyring) { |
351 | down_write(&tsk->thread_keyring->sem); | 349 | down_write(&tsk->thread_keyring->sem); |
352 | write_lock(&tsk->thread_keyring->lock); | ||
353 | tsk->thread_keyring->uid = tsk->fsuid; | 350 | tsk->thread_keyring->uid = tsk->fsuid; |
354 | write_unlock(&tsk->thread_keyring->lock); | ||
355 | up_write(&tsk->thread_keyring->sem); | 351 | up_write(&tsk->thread_keyring->sem); |
356 | } | 352 | } |
357 | 353 | ||
@@ -366,9 +362,7 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
366 | /* update the ownership of the thread keyring */ | 362 | /* update the ownership of the thread keyring */ |
367 | if (tsk->thread_keyring) { | 363 | if (tsk->thread_keyring) { |
368 | down_write(&tsk->thread_keyring->sem); | 364 | down_write(&tsk->thread_keyring->sem); |
369 | write_lock(&tsk->thread_keyring->lock); | ||
370 | tsk->thread_keyring->gid = tsk->fsgid; | 365 | tsk->thread_keyring->gid = tsk->fsgid; |
371 | write_unlock(&tsk->thread_keyring->lock); | ||
372 | up_write(&tsk->thread_keyring->sem); | 366 | up_write(&tsk->thread_keyring->sem); |
373 | } | 367 | } |
374 | 368 | ||
@@ -588,7 +582,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial, | |||
588 | } | 582 | } |
589 | 583 | ||
590 | ret = -EIO; | 584 | ret = -EIO; |
591 | if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED)) | 585 | if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
592 | goto invalid_key; | 586 | goto invalid_key; |
593 | 587 | ||
594 | ret = -EACCES; | 588 | ret = -EACCES; |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 9705b1aeba5d..1f6c0940297f 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -105,7 +105,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
105 | struct key_construction cons; | 105 | struct key_construction cons; |
106 | struct timespec now; | 106 | struct timespec now; |
107 | struct key *key; | 107 | struct key *key; |
108 | int ret, negative; | 108 | int ret, negated; |
109 | 109 | ||
110 | /* create a key and add it to the queue */ | 110 | /* create a key and add it to the queue */ |
111 | key = key_alloc(type, description, | 111 | key = key_alloc(type, description, |
@@ -113,9 +113,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
113 | if (IS_ERR(key)) | 113 | if (IS_ERR(key)) |
114 | goto alloc_failed; | 114 | goto alloc_failed; |
115 | 115 | ||
116 | write_lock(&key->lock); | 116 | set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
117 | key->flags |= KEY_FLAG_USER_CONSTRUCT; | ||
118 | write_unlock(&key->lock); | ||
119 | 117 | ||
120 | cons.key = key; | 118 | cons.key = key; |
121 | list_add_tail(&cons.link, &key->user->consq); | 119 | list_add_tail(&cons.link, &key->user->consq); |
@@ -130,7 +128,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
130 | 128 | ||
131 | /* if the key wasn't instantiated, then we want to give an error */ | 129 | /* if the key wasn't instantiated, then we want to give an error */ |
132 | ret = -ENOKEY; | 130 | ret = -ENOKEY; |
133 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) | 131 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
134 | goto request_failed; | 132 | goto request_failed; |
135 | 133 | ||
136 | down_write(&key_construction_sem); | 134 | down_write(&key_construction_sem); |
@@ -139,7 +137,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
139 | 137 | ||
140 | /* also give an error if the key was negatively instantiated */ | 138 | /* also give an error if the key was negatively instantiated */ |
141 | check_not_negative: | 139 | check_not_negative: |
142 | if (key->flags & KEY_FLAG_NEGATIVE) { | 140 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
143 | key_put(key); | 141 | key_put(key); |
144 | key = ERR_PTR(-ENOKEY); | 142 | key = ERR_PTR(-ENOKEY); |
145 | } | 143 | } |
@@ -152,24 +150,23 @@ static struct key *__request_key_construction(struct key_type *type, | |||
152 | * - remove from construction queue | 150 | * - remove from construction queue |
153 | * - mark the key as dead | 151 | * - mark the key as dead |
154 | */ | 152 | */ |
155 | negative = 0; | 153 | negated = 0; |
156 | down_write(&key_construction_sem); | 154 | down_write(&key_construction_sem); |
157 | 155 | ||
158 | list_del(&cons.link); | 156 | list_del(&cons.link); |
159 | 157 | ||
160 | write_lock(&key->lock); | ||
161 | key->flags &= ~KEY_FLAG_USER_CONSTRUCT; | ||
162 | |||
163 | /* check it didn't get instantiated between the check and the down */ | 158 | /* check it didn't get instantiated between the check and the down */ |
164 | if (!(key->flags & KEY_FLAG_INSTANTIATED)) { | 159 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { |
165 | key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; | 160 | set_bit(KEY_FLAG_NEGATIVE, &key->flags); |
166 | negative = 1; | 161 | set_bit(KEY_FLAG_INSTANTIATED, &key->flags); |
162 | negated = 1; | ||
167 | } | 163 | } |
168 | 164 | ||
169 | write_unlock(&key->lock); | 165 | clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
166 | |||
170 | up_write(&key_construction_sem); | 167 | up_write(&key_construction_sem); |
171 | 168 | ||
172 | if (!negative) | 169 | if (!negated) |
173 | goto check_not_negative; /* surprisingly, the key got | 170 | goto check_not_negative; /* surprisingly, the key got |
174 | * instantiated */ | 171 | * instantiated */ |
175 | 172 | ||
@@ -250,7 +247,7 @@ static struct key *request_key_construction(struct key_type *type, | |||
250 | 247 | ||
251 | for (;;) { | 248 | for (;;) { |
252 | set_current_state(TASK_UNINTERRUPTIBLE); | 249 | set_current_state(TASK_UNINTERRUPTIBLE); |
253 | if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT)) | 250 | if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags)) |
254 | break; | 251 | break; |
255 | schedule(); | 252 | schedule(); |
256 | } | 253 | } |
@@ -339,7 +336,8 @@ int key_validate(struct key *key) | |||
339 | if (key) { | 336 | if (key) { |
340 | /* check it's still accessible */ | 337 | /* check it's still accessible */ |
341 | ret = -EKEYREVOKED; | 338 | ret = -EKEYREVOKED; |
342 | if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD)) | 339 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || |
340 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
343 | goto error; | 341 | goto error; |
344 | 342 | ||
345 | /* check it hasn't expired */ | 343 | /* check it hasn't expired */ |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 8d65b3a28129..c33d3614a0db 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
@@ -42,12 +42,19 @@ struct key_type key_type_user = { | |||
42 | .read = user_read, | 42 | .read = user_read, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | struct user_key_payload { | ||
46 | struct rcu_head rcu; /* RCU destructor */ | ||
47 | unsigned short datalen; /* length of this data */ | ||
48 | char data[0]; /* actual data */ | ||
49 | }; | ||
50 | |||
45 | /*****************************************************************************/ | 51 | /*****************************************************************************/ |
46 | /* | 52 | /* |
47 | * instantiate a user defined key | 53 | * instantiate a user defined key |
48 | */ | 54 | */ |
49 | static int user_instantiate(struct key *key, const void *data, size_t datalen) | 55 | static int user_instantiate(struct key *key, const void *data, size_t datalen) |
50 | { | 56 | { |
57 | struct user_key_payload *upayload; | ||
51 | int ret; | 58 | int ret; |
52 | 59 | ||
53 | ret = -EINVAL; | 60 | ret = -EINVAL; |
@@ -58,13 +65,15 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen) | |||
58 | if (ret < 0) | 65 | if (ret < 0) |
59 | goto error; | 66 | goto error; |
60 | 67 | ||
61 | /* attach the data */ | ||
62 | ret = -ENOMEM; | 68 | ret = -ENOMEM; |
63 | key->payload.data = kmalloc(datalen, GFP_KERNEL); | 69 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
64 | if (!key->payload.data) | 70 | if (!upayload) |
65 | goto error; | 71 | goto error; |
66 | 72 | ||
67 | memcpy(key->payload.data, data, datalen); | 73 | /* attach the data */ |
74 | upayload->datalen = datalen; | ||
75 | memcpy(upayload->data, data, datalen); | ||
76 | rcu_assign_pointer(key->payload.data, upayload); | ||
68 | ret = 0; | 77 | ret = 0; |
69 | 78 | ||
70 | error: | 79 | error: |
@@ -75,18 +84,25 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen) | |||
75 | /*****************************************************************************/ | 84 | /*****************************************************************************/ |
76 | /* | 85 | /* |
77 | * duplicate a user defined key | 86 | * duplicate a user defined key |
87 | * - both keys' semaphores are locked against further modification | ||
88 | * - the new key cannot yet be accessed | ||
78 | */ | 89 | */ |
79 | static int user_duplicate(struct key *key, const struct key *source) | 90 | static int user_duplicate(struct key *key, const struct key *source) |
80 | { | 91 | { |
92 | struct user_key_payload *upayload, *spayload; | ||
81 | int ret; | 93 | int ret; |
82 | 94 | ||
83 | /* just copy the payload */ | 95 | /* just copy the payload */ |
84 | ret = -ENOMEM; | 96 | ret = -ENOMEM; |
85 | key->payload.data = kmalloc(source->datalen, GFP_KERNEL); | 97 | upayload = kmalloc(sizeof(*upayload) + source->datalen, GFP_KERNEL); |
98 | if (upayload) { | ||
99 | spayload = rcu_dereference(source->payload.data); | ||
100 | BUG_ON(source->datalen != spayload->datalen); | ||
86 | 101 | ||
87 | if (key->payload.data) { | 102 | upayload->datalen = key->datalen = spayload->datalen; |
88 | key->datalen = source->datalen; | 103 | memcpy(upayload->data, spayload->data, key->datalen); |
89 | memcpy(key->payload.data, source->payload.data, source->datalen); | 104 | |
105 | key->payload.data = upayload; | ||
90 | ret = 0; | 106 | ret = 0; |
91 | } | 107 | } |
92 | 108 | ||
@@ -96,40 +112,54 @@ static int user_duplicate(struct key *key, const struct key *source) | |||
96 | 112 | ||
97 | /*****************************************************************************/ | 113 | /*****************************************************************************/ |
98 | /* | 114 | /* |
115 | * dispose of the old data from an updated user defined key | ||
116 | */ | ||
117 | static void user_update_rcu_disposal(struct rcu_head *rcu) | ||
118 | { | ||
119 | struct user_key_payload *upayload; | ||
120 | |||
121 | upayload = container_of(rcu, struct user_key_payload, rcu); | ||
122 | |||
123 | kfree(upayload); | ||
124 | |||
125 | } /* end user_update_rcu_disposal() */ | ||
126 | |||
127 | /*****************************************************************************/ | ||
128 | /* | ||
99 | * update a user defined key | 129 | * update a user defined key |
130 | * - the key's semaphore is write-locked | ||
100 | */ | 131 | */ |
101 | static int user_update(struct key *key, const void *data, size_t datalen) | 132 | static int user_update(struct key *key, const void *data, size_t datalen) |
102 | { | 133 | { |
103 | void *new, *zap; | 134 | struct user_key_payload *upayload, *zap; |
104 | int ret; | 135 | int ret; |
105 | 136 | ||
106 | ret = -EINVAL; | 137 | ret = -EINVAL; |
107 | if (datalen <= 0 || datalen > 32767 || !data) | 138 | if (datalen <= 0 || datalen > 32767 || !data) |
108 | goto error; | 139 | goto error; |
109 | 140 | ||
110 | /* copy the data */ | 141 | /* construct a replacement payload */ |
111 | ret = -ENOMEM; | 142 | ret = -ENOMEM; |
112 | new = kmalloc(datalen, GFP_KERNEL); | 143 | upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL); |
113 | if (!new) | 144 | if (!upayload) |
114 | goto error; | 145 | goto error; |
115 | 146 | ||
116 | memcpy(new, data, datalen); | 147 | upayload->datalen = datalen; |
148 | memcpy(upayload->data, data, datalen); | ||
117 | 149 | ||
118 | /* check the quota and attach the new data */ | 150 | /* check the quota and attach the new data */ |
119 | zap = new; | 151 | zap = upayload; |
120 | write_lock(&key->lock); | ||
121 | 152 | ||
122 | ret = key_payload_reserve(key, datalen); | 153 | ret = key_payload_reserve(key, datalen); |
123 | 154 | ||
124 | if (ret == 0) { | 155 | if (ret == 0) { |
125 | /* attach the new data, displacing the old */ | 156 | /* attach the new data, displacing the old */ |
126 | zap = key->payload.data; | 157 | zap = key->payload.data; |
127 | key->payload.data = new; | 158 | rcu_assign_pointer(key->payload.data, upayload); |
128 | key->expiry = 0; | 159 | key->expiry = 0; |
129 | } | 160 | } |
130 | 161 | ||
131 | write_unlock(&key->lock); | 162 | call_rcu(&zap->rcu, user_update_rcu_disposal); |
132 | kfree(zap); | ||
133 | 163 | ||
134 | error: | 164 | error: |
135 | return ret; | 165 | return ret; |
@@ -152,13 +182,15 @@ static int user_match(const struct key *key, const void *description) | |||
152 | */ | 182 | */ |
153 | static void user_destroy(struct key *key) | 183 | static void user_destroy(struct key *key) |
154 | { | 184 | { |
155 | kfree(key->payload.data); | 185 | struct user_key_payload *upayload = key->payload.data; |
186 | |||
187 | kfree(upayload); | ||
156 | 188 | ||
157 | } /* end user_destroy() */ | 189 | } /* end user_destroy() */ |
158 | 190 | ||
159 | /*****************************************************************************/ | 191 | /*****************************************************************************/ |
160 | /* | 192 | /* |
161 | * describe the user | 193 | * describe the user key |
162 | */ | 194 | */ |
163 | static void user_describe(const struct key *key, struct seq_file *m) | 195 | static void user_describe(const struct key *key, struct seq_file *m) |
164 | { | 196 | { |
@@ -171,18 +203,23 @@ static void user_describe(const struct key *key, struct seq_file *m) | |||
171 | /*****************************************************************************/ | 203 | /*****************************************************************************/ |
172 | /* | 204 | /* |
173 | * read the key data | 205 | * read the key data |
206 | * - the key's semaphore is read-locked | ||
174 | */ | 207 | */ |
175 | static long user_read(const struct key *key, | 208 | static long user_read(const struct key *key, |
176 | char __user *buffer, size_t buflen) | 209 | char __user *buffer, size_t buflen) |
177 | { | 210 | { |
178 | long ret = key->datalen; | 211 | struct user_key_payload *upayload; |
212 | long ret; | ||
213 | |||
214 | upayload = rcu_dereference(key->payload.data); | ||
215 | ret = upayload->datalen; | ||
179 | 216 | ||
180 | /* we can return the data as is */ | 217 | /* we can return the data as is */ |
181 | if (buffer && buflen > 0) { | 218 | if (buffer && buflen > 0) { |
182 | if (buflen > key->datalen) | 219 | if (buflen > upayload->datalen) |
183 | buflen = key->datalen; | 220 | buflen = upayload->datalen; |
184 | 221 | ||
185 | if (copy_to_user(buffer, key->payload.data, buflen) != 0) | 222 | if (copy_to_user(buffer, upayload->data, buflen) != 0) |
186 | ret = -EFAULT; | 223 | ret = -EFAULT; |
187 | } | 224 | } |
188 | 225 | ||