diff options
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 94 |
1 files changed, 39 insertions, 55 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 54339cfd6734..b58d93892740 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -46,9 +46,11 @@ int install_user_keyrings(void) | |||
46 | struct user_struct *user; | 46 | struct user_struct *user; |
47 | const struct cred *cred; | 47 | const struct cred *cred; |
48 | struct key *uid_keyring, *session_keyring; | 48 | struct key *uid_keyring, *session_keyring; |
49 | key_perm_t user_keyring_perm; | ||
49 | char buf[20]; | 50 | char buf[20]; |
50 | int ret; | 51 | int ret; |
51 | 52 | ||
53 | user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; | ||
52 | cred = current_cred(); | 54 | cred = current_cred(); |
53 | user = cred->user; | 55 | user = cred->user; |
54 | 56 | ||
@@ -72,8 +74,8 @@ int install_user_keyrings(void) | |||
72 | uid_keyring = find_keyring_by_name(buf, true); | 74 | uid_keyring = find_keyring_by_name(buf, true); |
73 | if (IS_ERR(uid_keyring)) { | 75 | if (IS_ERR(uid_keyring)) { |
74 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | 76 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, |
75 | cred, KEY_ALLOC_IN_QUOTA, | 77 | cred, user_keyring_perm, |
76 | NULL); | 78 | KEY_ALLOC_IN_QUOTA, NULL); |
77 | if (IS_ERR(uid_keyring)) { | 79 | if (IS_ERR(uid_keyring)) { |
78 | ret = PTR_ERR(uid_keyring); | 80 | ret = PTR_ERR(uid_keyring); |
79 | goto error; | 81 | goto error; |
@@ -88,7 +90,8 @@ int install_user_keyrings(void) | |||
88 | if (IS_ERR(session_keyring)) { | 90 | if (IS_ERR(session_keyring)) { |
89 | session_keyring = | 91 | session_keyring = |
90 | keyring_alloc(buf, user->uid, (gid_t) -1, | 92 | keyring_alloc(buf, user->uid, (gid_t) -1, |
91 | cred, KEY_ALLOC_IN_QUOTA, NULL); | 93 | cred, user_keyring_perm, |
94 | KEY_ALLOC_IN_QUOTA, NULL); | ||
92 | if (IS_ERR(session_keyring)) { | 95 | if (IS_ERR(session_keyring)) { |
93 | ret = PTR_ERR(session_keyring); | 96 | ret = PTR_ERR(session_keyring); |
94 | goto error_release; | 97 | goto error_release; |
@@ -129,6 +132,7 @@ int install_thread_keyring_to_cred(struct cred *new) | |||
129 | struct key *keyring; | 132 | struct key *keyring; |
130 | 133 | ||
131 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, | 134 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
135 | KEY_POS_ALL | KEY_USR_VIEW, | ||
132 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 136 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
133 | if (IS_ERR(keyring)) | 137 | if (IS_ERR(keyring)) |
134 | return PTR_ERR(keyring); | 138 | return PTR_ERR(keyring); |
@@ -169,27 +173,18 @@ static int install_thread_keyring(void) | |||
169 | int install_process_keyring_to_cred(struct cred *new) | 173 | int install_process_keyring_to_cred(struct cred *new) |
170 | { | 174 | { |
171 | struct key *keyring; | 175 | struct key *keyring; |
172 | int ret; | ||
173 | 176 | ||
174 | if (new->tgcred->process_keyring) | 177 | if (new->process_keyring) |
175 | return -EEXIST; | 178 | return -EEXIST; |
176 | 179 | ||
177 | keyring = keyring_alloc("_pid", new->uid, new->gid, | 180 | keyring = keyring_alloc("_pid", new->uid, new->gid, new, |
178 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | 181 | KEY_POS_ALL | KEY_USR_VIEW, |
182 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
179 | if (IS_ERR(keyring)) | 183 | if (IS_ERR(keyring)) |
180 | return PTR_ERR(keyring); | 184 | return PTR_ERR(keyring); |
181 | 185 | ||
182 | spin_lock_irq(&new->tgcred->lock); | 186 | new->process_keyring = keyring; |
183 | if (!new->tgcred->process_keyring) { | 187 | return 0; |
184 | new->tgcred->process_keyring = keyring; | ||
185 | keyring = NULL; | ||
186 | ret = 0; | ||
187 | } else { | ||
188 | ret = -EEXIST; | ||
189 | } | ||
190 | spin_unlock_irq(&new->tgcred->lock); | ||
191 | key_put(keyring); | ||
192 | return ret; | ||
193 | } | 188 | } |
194 | 189 | ||
195 | /* | 190 | /* |
@@ -230,11 +225,12 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
230 | /* create an empty session keyring */ | 225 | /* create an empty session keyring */ |
231 | if (!keyring) { | 226 | if (!keyring) { |
232 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 227 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
233 | if (cred->tgcred->session_keyring) | 228 | if (cred->session_keyring) |
234 | flags = KEY_ALLOC_IN_QUOTA; | 229 | flags = KEY_ALLOC_IN_QUOTA; |
235 | 230 | ||
236 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, | 231 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred, |
237 | cred, flags, NULL); | 232 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
233 | flags, NULL); | ||
238 | if (IS_ERR(keyring)) | 234 | if (IS_ERR(keyring)) |
239 | return PTR_ERR(keyring); | 235 | return PTR_ERR(keyring); |
240 | } else { | 236 | } else { |
@@ -242,17 +238,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | |||
242 | } | 238 | } |
243 | 239 | ||
244 | /* install the keyring */ | 240 | /* install the keyring */ |
245 | spin_lock_irq(&cred->tgcred->lock); | 241 | old = cred->session_keyring; |
246 | old = cred->tgcred->session_keyring; | 242 | rcu_assign_pointer(cred->session_keyring, keyring); |
247 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); | 243 | |
248 | spin_unlock_irq(&cred->tgcred->lock); | 244 | if (old) |
249 | |||
250 | /* we're using RCU on the pointer, but there's no point synchronising | ||
251 | * on it if it didn't previously point to anything */ | ||
252 | if (old) { | ||
253 | synchronize_rcu(); | ||
254 | key_put(old); | 245 | key_put(old); |
255 | } | ||
256 | 246 | ||
257 | return 0; | 247 | return 0; |
258 | } | 248 | } |
@@ -357,8 +347,6 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
357 | 347 | ||
358 | switch (PTR_ERR(key_ref)) { | 348 | switch (PTR_ERR(key_ref)) { |
359 | case -EAGAIN: /* no key */ | 349 | case -EAGAIN: /* no key */ |
360 | if (ret) | ||
361 | break; | ||
362 | case -ENOKEY: /* negative key */ | 350 | case -ENOKEY: /* negative key */ |
363 | ret = key_ref; | 351 | ret = key_ref; |
364 | break; | 352 | break; |
@@ -369,9 +357,9 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
369 | } | 357 | } |
370 | 358 | ||
371 | /* search the process keyring second */ | 359 | /* search the process keyring second */ |
372 | if (cred->tgcred->process_keyring) { | 360 | if (cred->process_keyring) { |
373 | key_ref = keyring_search_aux( | 361 | key_ref = keyring_search_aux( |
374 | make_key_ref(cred->tgcred->process_keyring, 1), | 362 | make_key_ref(cred->process_keyring, 1), |
375 | cred, type, description, match, no_state_check); | 363 | cred, type, description, match, no_state_check); |
376 | if (!IS_ERR(key_ref)) | 364 | if (!IS_ERR(key_ref)) |
377 | goto found; | 365 | goto found; |
@@ -390,12 +378,10 @@ key_ref_t search_my_process_keyrings(struct key_type *type, | |||
390 | } | 378 | } |
391 | 379 | ||
392 | /* search the session keyring */ | 380 | /* search the session keyring */ |
393 | if (cred->tgcred->session_keyring) { | 381 | if (cred->session_keyring) { |
394 | rcu_read_lock(); | 382 | rcu_read_lock(); |
395 | key_ref = keyring_search_aux( | 383 | key_ref = keyring_search_aux( |
396 | make_key_ref(rcu_dereference( | 384 | make_key_ref(rcu_dereference(cred->session_keyring), 1), |
397 | cred->tgcred->session_keyring), | ||
398 | 1), | ||
399 | cred, type, description, match, no_state_check); | 385 | cred, type, description, match, no_state_check); |
400 | rcu_read_unlock(); | 386 | rcu_read_unlock(); |
401 | 387 | ||
@@ -565,7 +551,7 @@ try_again: | |||
565 | break; | 551 | break; |
566 | 552 | ||
567 | case KEY_SPEC_PROCESS_KEYRING: | 553 | case KEY_SPEC_PROCESS_KEYRING: |
568 | if (!cred->tgcred->process_keyring) { | 554 | if (!cred->process_keyring) { |
569 | if (!(lflags & KEY_LOOKUP_CREATE)) | 555 | if (!(lflags & KEY_LOOKUP_CREATE)) |
570 | goto error; | 556 | goto error; |
571 | 557 | ||
@@ -577,13 +563,13 @@ try_again: | |||
577 | goto reget_creds; | 563 | goto reget_creds; |
578 | } | 564 | } |
579 | 565 | ||
580 | key = cred->tgcred->process_keyring; | 566 | key = cred->process_keyring; |
581 | atomic_inc(&key->usage); | 567 | atomic_inc(&key->usage); |
582 | key_ref = make_key_ref(key, 1); | 568 | key_ref = make_key_ref(key, 1); |
583 | break; | 569 | break; |
584 | 570 | ||
585 | case KEY_SPEC_SESSION_KEYRING: | 571 | case KEY_SPEC_SESSION_KEYRING: |
586 | if (!cred->tgcred->session_keyring) { | 572 | if (!cred->session_keyring) { |
587 | /* always install a session keyring upon access if one | 573 | /* always install a session keyring upon access if one |
588 | * doesn't exist yet */ | 574 | * doesn't exist yet */ |
589 | ret = install_user_keyrings(); | 575 | ret = install_user_keyrings(); |
@@ -598,7 +584,7 @@ try_again: | |||
598 | if (ret < 0) | 584 | if (ret < 0) |
599 | goto error; | 585 | goto error; |
600 | goto reget_creds; | 586 | goto reget_creds; |
601 | } else if (cred->tgcred->session_keyring == | 587 | } else if (cred->session_keyring == |
602 | cred->user->session_keyring && | 588 | cred->user->session_keyring && |
603 | lflags & KEY_LOOKUP_CREATE) { | 589 | lflags & KEY_LOOKUP_CREATE) { |
604 | ret = join_session_keyring(NULL); | 590 | ret = join_session_keyring(NULL); |
@@ -608,7 +594,7 @@ try_again: | |||
608 | } | 594 | } |
609 | 595 | ||
610 | rcu_read_lock(); | 596 | rcu_read_lock(); |
611 | key = rcu_dereference(cred->tgcred->session_keyring); | 597 | key = rcu_dereference(cred->session_keyring); |
612 | atomic_inc(&key->usage); | 598 | atomic_inc(&key->usage); |
613 | rcu_read_unlock(); | 599 | rcu_read_unlock(); |
614 | key_ref = make_key_ref(key, 1); | 600 | key_ref = make_key_ref(key, 1); |
@@ -768,12 +754,6 @@ long join_session_keyring(const char *name) | |||
768 | struct key *keyring; | 754 | struct key *keyring; |
769 | long ret, serial; | 755 | long ret, serial; |
770 | 756 | ||
771 | /* only permit this if there's a single thread in the thread group - | ||
772 | * this avoids us having to adjust the creds on all threads and risking | ||
773 | * ENOMEM */ | ||
774 | if (!current_is_single_threaded()) | ||
775 | return -EMLINK; | ||
776 | |||
777 | new = prepare_creds(); | 757 | new = prepare_creds(); |
778 | if (!new) | 758 | if (!new) |
779 | return -ENOMEM; | 759 | return -ENOMEM; |
@@ -785,7 +765,7 @@ long join_session_keyring(const char *name) | |||
785 | if (ret < 0) | 765 | if (ret < 0) |
786 | goto error; | 766 | goto error; |
787 | 767 | ||
788 | serial = new->tgcred->session_keyring->serial; | 768 | serial = new->session_keyring->serial; |
789 | ret = commit_creds(new); | 769 | ret = commit_creds(new); |
790 | if (ret == 0) | 770 | if (ret == 0) |
791 | ret = serial; | 771 | ret = serial; |
@@ -799,8 +779,10 @@ long join_session_keyring(const char *name) | |||
799 | keyring = find_keyring_by_name(name, false); | 779 | keyring = find_keyring_by_name(name, false); |
800 | if (PTR_ERR(keyring) == -ENOKEY) { | 780 | if (PTR_ERR(keyring) == -ENOKEY) { |
801 | /* not found - try and create a new one */ | 781 | /* not found - try and create a new one */ |
802 | keyring = keyring_alloc(name, old->uid, old->gid, old, | 782 | keyring = keyring_alloc( |
803 | KEY_ALLOC_IN_QUOTA, NULL); | 783 | name, old->uid, old->gid, old, |
784 | KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK, | ||
785 | KEY_ALLOC_IN_QUOTA, NULL); | ||
804 | if (IS_ERR(keyring)) { | 786 | if (IS_ERR(keyring)) { |
805 | ret = PTR_ERR(keyring); | 787 | ret = PTR_ERR(keyring); |
806 | goto error2; | 788 | goto error2; |
@@ -808,6 +790,9 @@ long join_session_keyring(const char *name) | |||
808 | } else if (IS_ERR(keyring)) { | 790 | } else if (IS_ERR(keyring)) { |
809 | ret = PTR_ERR(keyring); | 791 | ret = PTR_ERR(keyring); |
810 | goto error2; | 792 | goto error2; |
793 | } else if (keyring == new->session_keyring) { | ||
794 | ret = 0; | ||
795 | goto error2; | ||
811 | } | 796 | } |
812 | 797 | ||
813 | /* we've got a keyring - now to install it */ | 798 | /* we've got a keyring - now to install it */ |
@@ -864,8 +849,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
864 | 849 | ||
865 | new->jit_keyring = old->jit_keyring; | 850 | new->jit_keyring = old->jit_keyring; |
866 | new->thread_keyring = key_get(old->thread_keyring); | 851 | new->thread_keyring = key_get(old->thread_keyring); |
867 | new->tgcred->tgid = old->tgcred->tgid; | 852 | new->process_keyring = key_get(old->process_keyring); |
868 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | ||
869 | 853 | ||
870 | security_transfer_creds(new, old); | 854 | security_transfer_creds(new, old); |
871 | 855 | ||