summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJann Horn <jannh@google.com>2019-03-27 11:55:08 -0400
committerJames Morris <james.morris@microsoft.com>2019-04-10 13:29:50 -0400
commit0b9dc6c9f01c4a726558b82a3b6082a89d264eb5 (patch)
tree1acfa81de568fa53ee14fac6219a140cd6560778 /security
parent5c7e372caa35d303e414caeb64ee2243fd3cac3d (diff)
keys: safe concurrent user->{session,uid}_keyring access
The current code can perform concurrent updates and reads on user->session_keyring and user->uid_keyring. Add a comment to struct user_struct to document the nontrivial locking semantics, and use READ_ONCE() for unlocked readers and smp_store_release() for writers to prevent memory ordering issues. Fixes: 69664cf16af4 ("keys: don't generate user and user session keyrings unless they're accessed") Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: James Morris <james.morris@microsoft.com>
Diffstat (limited to 'security')
-rw-r--r--security/keys/process_keys.c31
-rw-r--r--security/keys/request_key.c5
2 files changed, 20 insertions, 16 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index bd7243cb4c85..f05f7125a7d5 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -58,7 +58,7 @@ int install_user_keyrings(void)
58 58
59 kenter("%p{%u}", user, uid); 59 kenter("%p{%u}", user, uid);
60 60
61 if (user->uid_keyring && user->session_keyring) { 61 if (READ_ONCE(user->uid_keyring) && READ_ONCE(user->session_keyring)) {
62 kleave(" = 0 [exist]"); 62 kleave(" = 0 [exist]");
63 return 0; 63 return 0;
64 } 64 }
@@ -111,8 +111,10 @@ int install_user_keyrings(void)
111 } 111 }
112 112
113 /* install the keyrings */ 113 /* install the keyrings */
114 user->uid_keyring = uid_keyring; 114 /* paired with READ_ONCE() */
115 user->session_keyring = session_keyring; 115 smp_store_release(&user->uid_keyring, uid_keyring);
116 /* paired with READ_ONCE() */
117 smp_store_release(&user->session_keyring, session_keyring);
116 } 118 }
117 119
118 mutex_unlock(&key_user_keyring_mutex); 120 mutex_unlock(&key_user_keyring_mutex);
@@ -340,6 +342,7 @@ void key_fsgid_changed(struct task_struct *tsk)
340key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx) 342key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
341{ 343{
342 key_ref_t key_ref, ret, err; 344 key_ref_t key_ref, ret, err;
345 const struct cred *cred = ctx->cred;
343 346
344 /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were 347 /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
345 * searchable, but we failed to find a key or we found a negative key; 348 * searchable, but we failed to find a key or we found a negative key;
@@ -353,9 +356,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
353 err = ERR_PTR(-EAGAIN); 356 err = ERR_PTR(-EAGAIN);
354 357
355 /* search the thread keyring first */ 358 /* search the thread keyring first */
356 if (ctx->cred->thread_keyring) { 359 if (cred->thread_keyring) {
357 key_ref = keyring_search_aux( 360 key_ref = keyring_search_aux(
358 make_key_ref(ctx->cred->thread_keyring, 1), ctx); 361 make_key_ref(cred->thread_keyring, 1), ctx);
359 if (!IS_ERR(key_ref)) 362 if (!IS_ERR(key_ref))
360 goto found; 363 goto found;
361 364
@@ -371,9 +374,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
371 } 374 }
372 375
373 /* search the process keyring second */ 376 /* search the process keyring second */
374 if (ctx->cred->process_keyring) { 377 if (cred->process_keyring) {
375 key_ref = keyring_search_aux( 378 key_ref = keyring_search_aux(
376 make_key_ref(ctx->cred->process_keyring, 1), ctx); 379 make_key_ref(cred->process_keyring, 1), ctx);
377 if (!IS_ERR(key_ref)) 380 if (!IS_ERR(key_ref))
378 goto found; 381 goto found;
379 382
@@ -392,9 +395,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
392 } 395 }
393 396
394 /* search the session keyring */ 397 /* search the session keyring */
395 if (ctx->cred->session_keyring) { 398 if (cred->session_keyring) {
396 key_ref = keyring_search_aux( 399 key_ref = keyring_search_aux(
397 make_key_ref(ctx->cred->session_keyring, 1), ctx); 400 make_key_ref(cred->session_keyring, 1), ctx);
398 401
399 if (!IS_ERR(key_ref)) 402 if (!IS_ERR(key_ref))
400 goto found; 403 goto found;
@@ -413,9 +416,9 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
413 } 416 }
414 } 417 }
415 /* or search the user-session keyring */ 418 /* or search the user-session keyring */
416 else if (ctx->cred->user->session_keyring) { 419 else if (READ_ONCE(cred->user->session_keyring)) {
417 key_ref = keyring_search_aux( 420 key_ref = keyring_search_aux(
418 make_key_ref(ctx->cred->user->session_keyring, 1), 421 make_key_ref(READ_ONCE(cred->user->session_keyring), 1),
419 ctx); 422 ctx);
420 if (!IS_ERR(key_ref)) 423 if (!IS_ERR(key_ref))
421 goto found; 424 goto found;
@@ -602,7 +605,7 @@ try_again:
602 goto error; 605 goto error;
603 goto reget_creds; 606 goto reget_creds;
604 } else if (ctx.cred->session_keyring == 607 } else if (ctx.cred->session_keyring ==
605 ctx.cred->user->session_keyring && 608 READ_ONCE(ctx.cred->user->session_keyring) &&
606 lflags & KEY_LOOKUP_CREATE) { 609 lflags & KEY_LOOKUP_CREATE) {
607 ret = join_session_keyring(NULL); 610 ret = join_session_keyring(NULL);
608 if (ret < 0) 611 if (ret < 0)
@@ -616,7 +619,7 @@ try_again:
616 break; 619 break;
617 620
618 case KEY_SPEC_USER_KEYRING: 621 case KEY_SPEC_USER_KEYRING:
619 if (!ctx.cred->user->uid_keyring) { 622 if (!READ_ONCE(ctx.cred->user->uid_keyring)) {
620 ret = install_user_keyrings(); 623 ret = install_user_keyrings();
621 if (ret < 0) 624 if (ret < 0)
622 goto error; 625 goto error;
@@ -628,7 +631,7 @@ try_again:
628 break; 631 break;
629 632
630 case KEY_SPEC_USER_SESSION_KEYRING: 633 case KEY_SPEC_USER_SESSION_KEYRING:
631 if (!ctx.cred->user->session_keyring) { 634 if (!READ_ONCE(ctx.cred->user->session_keyring)) {
632 ret = install_user_keyrings(); 635 ret = install_user_keyrings();
633 if (ret < 0) 636 if (ret < 0)
634 goto error; 637 goto error;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index db72dc4d7639..75d87f9e0f49 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -293,11 +293,12 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
293 /* fall through */ 293 /* fall through */
294 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: 294 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
295 dest_keyring = 295 dest_keyring =
296 key_get(cred->user->session_keyring); 296 key_get(READ_ONCE(cred->user->session_keyring));
297 break; 297 break;
298 298
299 case KEY_REQKEY_DEFL_USER_KEYRING: 299 case KEY_REQKEY_DEFL_USER_KEYRING:
300 dest_keyring = key_get(cred->user->uid_keyring); 300 dest_keyring =
301 key_get(READ_ONCE(cred->user->uid_keyring));
301 break; 302 break;
302 303
303 case KEY_REQKEY_DEFL_GROUP_KEYRING: 304 case KEY_REQKEY_DEFL_GROUP_KEYRING: