diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/inode.c | 4 | ||||
| -rw-r--r-- | security/keys/gc.c | 9 | ||||
| -rw-r--r-- | security/keys/keyring.c | 41 | ||||
| -rw-r--r-- | security/keys/request_key.c | 24 | ||||
| -rw-r--r-- | security/keys/user_defined.c | 3 |
5 files changed, 49 insertions, 32 deletions
diff --git a/security/inode.c b/security/inode.c index c3a793881d04..1c812e874504 100644 --- a/security/inode.c +++ b/security/inode.c | |||
| @@ -161,13 +161,13 @@ static int create_by_name(const char *name, mode_t mode, | |||
| 161 | 161 | ||
| 162 | mutex_lock(&parent->d_inode->i_mutex); | 162 | mutex_lock(&parent->d_inode->i_mutex); |
| 163 | *dentry = lookup_one_len(name, parent, strlen(name)); | 163 | *dentry = lookup_one_len(name, parent, strlen(name)); |
| 164 | if (!IS_ERR(dentry)) { | 164 | if (!IS_ERR(*dentry)) { |
| 165 | if ((mode & S_IFMT) == S_IFDIR) | 165 | if ((mode & S_IFMT) == S_IFDIR) |
| 166 | error = mkdir(parent->d_inode, *dentry, mode); | 166 | error = mkdir(parent->d_inode, *dentry, mode); |
| 167 | else | 167 | else |
| 168 | error = create(parent->d_inode, *dentry, mode); | 168 | error = create(parent->d_inode, *dentry, mode); |
| 169 | } else | 169 | } else |
| 170 | error = PTR_ERR(dentry); | 170 | error = PTR_ERR(*dentry); |
| 171 | mutex_unlock(&parent->d_inode->i_mutex); | 171 | mutex_unlock(&parent->d_inode->i_mutex); |
| 172 | 172 | ||
| 173 | return error; | 173 | return error; |
diff --git a/security/keys/gc.c b/security/keys/gc.c index 19902319d097..a46e825cbf02 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
| @@ -77,10 +77,10 @@ static bool key_gc_keyring(struct key *keyring, time_t limit) | |||
| 77 | goto dont_gc; | 77 | goto dont_gc; |
| 78 | 78 | ||
| 79 | /* scan the keyring looking for dead keys */ | 79 | /* scan the keyring looking for dead keys */ |
| 80 | klist = rcu_dereference_check(keyring->payload.subscriptions, | 80 | rcu_read_lock(); |
| 81 | lockdep_is_held(&key_serial_lock)); | 81 | klist = rcu_dereference(keyring->payload.subscriptions); |
| 82 | if (!klist) | 82 | if (!klist) |
| 83 | goto dont_gc; | 83 | goto unlock_dont_gc; |
| 84 | 84 | ||
| 85 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 85 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
| 86 | key = klist->keys[loop]; | 86 | key = klist->keys[loop]; |
| @@ -89,11 +89,14 @@ static bool key_gc_keyring(struct key *keyring, time_t limit) | |||
| 89 | goto do_gc; | 89 | goto do_gc; |
| 90 | } | 90 | } |
| 91 | 91 | ||
| 92 | unlock_dont_gc: | ||
| 93 | rcu_read_unlock(); | ||
| 92 | dont_gc: | 94 | dont_gc: |
| 93 | kleave(" = false"); | 95 | kleave(" = false"); |
| 94 | return false; | 96 | return false; |
| 95 | 97 | ||
| 96 | do_gc: | 98 | do_gc: |
| 99 | rcu_read_unlock(); | ||
| 97 | key_gc_cursor = keyring->serial; | 100 | key_gc_cursor = keyring->serial; |
| 98 | key_get(keyring); | 101 | key_get(keyring); |
| 99 | spin_unlock(&key_serial_lock); | 102 | spin_unlock(&key_serial_lock); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e814d2109f8e..1e4b0037935c 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
| @@ -20,6 +20,11 @@ | |||
| 20 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
| 21 | #include "internal.h" | 21 | #include "internal.h" |
| 22 | 22 | ||
| 23 | #define rcu_dereference_locked_keyring(keyring) \ | ||
| 24 | (rcu_dereference_protected( \ | ||
| 25 | (keyring)->payload.subscriptions, \ | ||
| 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
| 27 | |||
| 23 | /* | 28 | /* |
| 24 | * when plumbing the depths of the key tree, this sets a hard limit set on how | 29 | * when plumbing the depths of the key tree, this sets a hard limit set on how |
| 25 | * deep we're willing to go | 30 | * deep we're willing to go |
| @@ -201,8 +206,7 @@ static long keyring_read(const struct key *keyring, | |||
| 201 | int loop, ret; | 206 | int loop, ret; |
| 202 | 207 | ||
| 203 | ret = 0; | 208 | ret = 0; |
| 204 | klist = rcu_dereference(keyring->payload.subscriptions); | 209 | klist = rcu_dereference_locked_keyring(keyring); |
| 205 | |||
| 206 | if (klist) { | 210 | if (klist) { |
| 207 | /* calculate how much data we could return */ | 211 | /* calculate how much data we could return */ |
| 208 | qty = klist->nkeys * sizeof(key_serial_t); | 212 | qty = klist->nkeys * sizeof(key_serial_t); |
| @@ -526,9 +530,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
| 526 | struct key *keyring; | 530 | struct key *keyring; |
| 527 | int bucket; | 531 | int bucket; |
| 528 | 532 | ||
| 529 | keyring = ERR_PTR(-EINVAL); | ||
| 530 | if (!name) | 533 | if (!name) |
| 531 | goto error; | 534 | return ERR_PTR(-EINVAL); |
| 532 | 535 | ||
| 533 | bucket = keyring_hash(name); | 536 | bucket = keyring_hash(name); |
| 534 | 537 | ||
| @@ -555,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
| 555 | KEY_SEARCH) < 0) | 558 | KEY_SEARCH) < 0) |
| 556 | continue; | 559 | continue; |
| 557 | 560 | ||
| 558 | /* we've got a match */ | 561 | /* we've got a match but we might end up racing with |
| 559 | atomic_inc(&keyring->usage); | 562 | * key_cleanup() if the keyring is currently 'dead' |
| 560 | read_unlock(&keyring_name_lock); | 563 | * (ie. it has a zero usage count) */ |
| 561 | goto error; | 564 | if (!atomic_inc_not_zero(&keyring->usage)) |
| 565 | continue; | ||
| 566 | goto out; | ||
| 562 | } | 567 | } |
| 563 | } | 568 | } |
| 564 | 569 | ||
| 565 | read_unlock(&keyring_name_lock); | ||
| 566 | keyring = ERR_PTR(-ENOKEY); | 570 | keyring = ERR_PTR(-ENOKEY); |
| 567 | 571 | out: | |
| 568 | error: | 572 | read_unlock(&keyring_name_lock); |
| 569 | return keyring; | 573 | return keyring; |
| 570 | 574 | ||
| 571 | } /* end find_keyring_by_name() */ | 575 | } /* end find_keyring_by_name() */ |
| @@ -720,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key) | |||
| 720 | } | 724 | } |
| 721 | 725 | ||
| 722 | /* see if there's a matching key we can displace */ | 726 | /* see if there's a matching key we can displace */ |
| 723 | klist = keyring->payload.subscriptions; | 727 | klist = rcu_dereference_locked_keyring(keyring); |
| 724 | |||
| 725 | if (klist && klist->nkeys > 0) { | 728 | if (klist && klist->nkeys > 0) { |
| 726 | struct key_type *type = key->type; | 729 | struct key_type *type = key->type; |
| 727 | 730 | ||
| @@ -765,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key) | |||
| 765 | if (ret < 0) | 768 | if (ret < 0) |
| 766 | goto error2; | 769 | goto error2; |
| 767 | 770 | ||
| 768 | klist = keyring->payload.subscriptions; | ||
| 769 | |||
| 770 | if (klist && klist->nkeys < klist->maxkeys) { | 771 | if (klist && klist->nkeys < klist->maxkeys) { |
| 771 | /* there's sufficient slack space to add directly */ | 772 | /* there's sufficient slack space to add directly */ |
| 772 | atomic_inc(&key->usage); | 773 | atomic_inc(&key->usage); |
| @@ -868,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
| 868 | 869 | ||
| 869 | down_write(&keyring->sem); | 870 | down_write(&keyring->sem); |
| 870 | 871 | ||
| 871 | klist = keyring->payload.subscriptions; | 872 | klist = rcu_dereference_locked_keyring(keyring); |
| 872 | if (klist) { | 873 | if (klist) { |
| 873 | /* search the keyring for the key */ | 874 | /* search the keyring for the key */ |
| 874 | for (loop = 0; loop < klist->nkeys; loop++) | 875 | for (loop = 0; loop < klist->nkeys; loop++) |
| @@ -959,7 +960,7 @@ int keyring_clear(struct key *keyring) | |||
| 959 | /* detach the pointer block with the locks held */ | 960 | /* detach the pointer block with the locks held */ |
| 960 | down_write(&keyring->sem); | 961 | down_write(&keyring->sem); |
| 961 | 962 | ||
| 962 | klist = keyring->payload.subscriptions; | 963 | klist = rcu_dereference_locked_keyring(keyring); |
| 963 | if (klist) { | 964 | if (klist) { |
| 964 | /* adjust the quota */ | 965 | /* adjust the quota */ |
| 965 | key_payload_reserve(keyring, | 966 | key_payload_reserve(keyring, |
| @@ -991,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear); | |||
| 991 | */ | 992 | */ |
| 992 | static void keyring_revoke(struct key *keyring) | 993 | static void keyring_revoke(struct key *keyring) |
| 993 | { | 994 | { |
| 994 | struct keyring_list *klist = keyring->payload.subscriptions; | 995 | struct keyring_list *klist; |
| 996 | |||
| 997 | klist = rcu_dereference_locked_keyring(keyring); | ||
| 995 | 998 | ||
| 996 | /* adjust the quota */ | 999 | /* adjust the quota */ |
| 997 | key_payload_reserve(keyring, 0); | 1000 | key_payload_reserve(keyring, 0); |
| @@ -1025,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
| 1025 | 1028 | ||
| 1026 | down_write(&keyring->sem); | 1029 | down_write(&keyring->sem); |
| 1027 | 1030 | ||
| 1028 | klist = keyring->payload.subscriptions; | 1031 | klist = rcu_dereference_locked_keyring(keyring); |
| 1029 | if (!klist) | 1032 | if (!klist) |
| 1030 | goto no_klist; | 1033 | goto no_klist; |
| 1031 | 1034 | ||
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 03fe63ed55bd..d8c1a6a0fb08 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
| @@ -68,7 +68,8 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
| 68 | { | 68 | { |
| 69 | const struct cred *cred = current_cred(); | 69 | const struct cred *cred = current_cred(); |
| 70 | key_serial_t prkey, sskey; | 70 | key_serial_t prkey, sskey; |
| 71 | struct key *key = cons->key, *authkey = cons->authkey, *keyring; | 71 | struct key *key = cons->key, *authkey = cons->authkey, *keyring, |
| 72 | *session; | ||
| 72 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; | 73 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
| 73 | char key_str[12], keyring_str[3][12]; | 74 | char key_str[12], keyring_str[3][12]; |
| 74 | char desc[20]; | 75 | char desc[20]; |
| @@ -93,7 +94,7 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
| 93 | } | 94 | } |
| 94 | 95 | ||
| 95 | /* attach the auth key to the session keyring */ | 96 | /* attach the auth key to the session keyring */ |
| 96 | ret = __key_link(keyring, authkey); | 97 | ret = key_link(keyring, authkey); |
| 97 | if (ret < 0) | 98 | if (ret < 0) |
| 98 | goto error_link; | 99 | goto error_link; |
| 99 | 100 | ||
| @@ -112,10 +113,12 @@ static int call_sbin_request_key(struct key_construction *cons, | |||
| 112 | if (cred->tgcred->process_keyring) | 113 | if (cred->tgcred->process_keyring) |
| 113 | prkey = cred->tgcred->process_keyring->serial; | 114 | prkey = cred->tgcred->process_keyring->serial; |
| 114 | 115 | ||
| 115 | if (cred->tgcred->session_keyring) | 116 | rcu_read_lock(); |
| 116 | sskey = rcu_dereference(cred->tgcred->session_keyring)->serial; | 117 | session = rcu_dereference(cred->tgcred->session_keyring); |
| 117 | else | 118 | if (!session) |
| 118 | sskey = cred->user->session_keyring->serial; | 119 | session = cred->user->session_keyring; |
| 120 | sskey = session->serial; | ||
| 121 | rcu_read_unlock(); | ||
| 119 | 122 | ||
| 120 | sprintf(keyring_str[2], "%d", sskey); | 123 | sprintf(keyring_str[2], "%d", sskey); |
| 121 | 124 | ||
| @@ -336,8 +339,10 @@ static int construct_alloc_key(struct key_type *type, | |||
| 336 | 339 | ||
| 337 | key_already_present: | 340 | key_already_present: |
| 338 | mutex_unlock(&key_construction_mutex); | 341 | mutex_unlock(&key_construction_mutex); |
| 339 | if (dest_keyring) | 342 | if (dest_keyring) { |
| 343 | __key_link(dest_keyring, key_ref_to_ptr(key_ref)); | ||
| 340 | up_write(&dest_keyring->sem); | 344 | up_write(&dest_keyring->sem); |
| 345 | } | ||
| 341 | mutex_unlock(&user->cons_lock); | 346 | mutex_unlock(&user->cons_lock); |
| 342 | key_put(key); | 347 | key_put(key); |
| 343 | *_key = key = key_ref_to_ptr(key_ref); | 348 | *_key = key = key_ref_to_ptr(key_ref); |
| @@ -428,6 +433,11 @@ struct key *request_key_and_link(struct key_type *type, | |||
| 428 | 433 | ||
| 429 | if (!IS_ERR(key_ref)) { | 434 | if (!IS_ERR(key_ref)) { |
| 430 | key = key_ref_to_ptr(key_ref); | 435 | key = key_ref_to_ptr(key_ref); |
| 436 | if (dest_keyring) { | ||
| 437 | construct_get_dest_keyring(&dest_keyring); | ||
| 438 | key_link(dest_keyring, key); | ||
| 439 | key_put(dest_keyring); | ||
| 440 | } | ||
| 431 | } else if (PTR_ERR(key_ref) != -EAGAIN) { | 441 | } else if (PTR_ERR(key_ref) != -EAGAIN) { |
| 432 | key = ERR_CAST(key_ref); | 442 | key = ERR_CAST(key_ref); |
| 433 | } else { | 443 | } else { |
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 7c687d568221..e9aa07929656 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c | |||
| @@ -199,7 +199,8 @@ long user_read(const struct key *key, char __user *buffer, size_t buflen) | |||
| 199 | struct user_key_payload *upayload; | 199 | struct user_key_payload *upayload; |
| 200 | long ret; | 200 | long ret; |
| 201 | 201 | ||
| 202 | upayload = rcu_dereference(key->payload.data); | 202 | upayload = rcu_dereference_protected( |
| 203 | key->payload.data, rwsem_is_locked(&((struct key *)key)->sem)); | ||
| 203 | ret = upayload->datalen; | 204 | ret = upayload->datalen; |
| 204 | 205 | ||
| 205 | /* we can return the data as is */ | 206 | /* we can return the data as is */ |
