diff options
author | David Howells <dhowells@redhat.com> | 2008-04-29 04:01:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:17 -0400 |
commit | 69664cf16af4f31cd54d77948a4baf9c7e0ca7b9 (patch) | |
tree | 3ff4ecae21c140a2beed25cfa9e55b788f9814ac /security/keys/process_keys.c | |
parent | 6b79ccb5144f9ffb4d4596c23e7570238dd12abc (diff) |
keys: don't generate user and user session keyrings unless they're accessed
Don't generate the per-UID user and user session keyrings unless they're
explicitly accessed. This solves a problem during a login process whereby
set*uid() is called before the SELinux PAM module, resulting in the per-UID
keyrings having the wrong security labels.
This also cures the problem of multiple per-UID keyrings sometimes appearing
due to PAM modules (including pam_keyinit) setuiding and causing user_structs
to come into and go out of existence whilst the session keyring pins the user
keyring. This is achieved by first searching for extant per-UID keyrings
before inventing new ones.
The serial bound argument is also dropped from find_keyring_by_name() as it's
not currently made use of (setting it to 0 disables the feature).
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: <kwc@citi.umich.edu>
Cc: <arunsr@cse.iitk.ac.in>
Cc: <dwalsh@redhat.com>
Cc: Stephen Smalley <sds@tycho.nsa.gov>
Cc: James Morris <jmorris@namei.org>
Cc: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 142 |
1 files changed, 83 insertions, 59 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index c886a2bb792a..5be6d018759a 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | 1 | /* Management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -23,6 +23,9 @@ | |||
23 | /* session keyring create vs join semaphore */ | 23 | /* session keyring create vs join semaphore */ |
24 | static DEFINE_MUTEX(key_session_mutex); | 24 | static DEFINE_MUTEX(key_session_mutex); |
25 | 25 | ||
26 | /* user keyring creation semaphore */ | ||
27 | static DEFINE_MUTEX(key_user_keyring_mutex); | ||
28 | |||
26 | /* the root user's tracking struct */ | 29 | /* the root user's tracking struct */ |
27 | struct key_user root_key_user = { | 30 | struct key_user root_key_user = { |
28 | .usage = ATOMIC_INIT(3), | 31 | .usage = ATOMIC_INIT(3), |
@@ -33,78 +36,84 @@ struct key_user root_key_user = { | |||
33 | .uid = 0, | 36 | .uid = 0, |
34 | }; | 37 | }; |
35 | 38 | ||
36 | /* the root user's UID keyring */ | ||
37 | struct key root_user_keyring = { | ||
38 | .usage = ATOMIC_INIT(1), | ||
39 | .serial = 2, | ||
40 | .type = &key_type_keyring, | ||
41 | .user = &root_key_user, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | ||
43 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
44 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
45 | .description = "_uid.0", | ||
46 | #ifdef KEY_DEBUGGING | ||
47 | .magic = KEY_DEBUG_MAGIC, | ||
48 | #endif | ||
49 | }; | ||
50 | |||
51 | /* the root user's default session keyring */ | ||
52 | struct key root_session_keyring = { | ||
53 | .usage = ATOMIC_INIT(1), | ||
54 | .serial = 1, | ||
55 | .type = &key_type_keyring, | ||
56 | .user = &root_key_user, | ||
57 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | ||
58 | .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL, | ||
59 | .flags = 1 << KEY_FLAG_INSTANTIATED, | ||
60 | .description = "_uid_ses.0", | ||
61 | #ifdef KEY_DEBUGGING | ||
62 | .magic = KEY_DEBUG_MAGIC, | ||
63 | #endif | ||
64 | }; | ||
65 | |||
66 | /*****************************************************************************/ | 39 | /*****************************************************************************/ |
67 | /* | 40 | /* |
68 | * allocate the keyrings to be associated with a UID | 41 | * install user and user session keyrings for a particular UID |
69 | */ | 42 | */ |
70 | int alloc_uid_keyring(struct user_struct *user, | 43 | static int install_user_keyrings(struct task_struct *tsk) |
71 | struct task_struct *ctx) | ||
72 | { | 44 | { |
45 | struct user_struct *user = tsk->user; | ||
73 | struct key *uid_keyring, *session_keyring; | 46 | struct key *uid_keyring, *session_keyring; |
74 | char buf[20]; | 47 | char buf[20]; |
75 | int ret; | 48 | int ret; |
76 | 49 | ||
77 | /* concoct a default session keyring */ | 50 | kenter("%p{%u}", user, user->uid); |
78 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
79 | 51 | ||
80 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 52 | if (user->uid_keyring) { |
81 | KEY_ALLOC_IN_QUOTA, NULL); | 53 | kleave(" = 0 [exist]"); |
82 | if (IS_ERR(session_keyring)) { | 54 | return 0; |
83 | ret = PTR_ERR(session_keyring); | ||
84 | goto error; | ||
85 | } | 55 | } |
86 | 56 | ||
87 | /* and a UID specific keyring, pointed to by the default session | 57 | mutex_lock(&key_user_keyring_mutex); |
88 | * keyring */ | 58 | ret = 0; |
89 | sprintf(buf, "_uid.%u", user->uid); | ||
90 | 59 | ||
91 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, | 60 | if (!user->uid_keyring) { |
92 | KEY_ALLOC_IN_QUOTA, session_keyring); | 61 | /* get the UID-specific keyring |
93 | if (IS_ERR(uid_keyring)) { | 62 | * - there may be one in existence already as it may have been |
94 | key_put(session_keyring); | 63 | * pinned by a session, but the user_struct pointing to it |
95 | ret = PTR_ERR(uid_keyring); | 64 | * may have been destroyed by setuid */ |
96 | goto error; | 65 | sprintf(buf, "_uid.%u", user->uid); |
66 | |||
67 | uid_keyring = find_keyring_by_name(buf, true); | ||
68 | if (IS_ERR(uid_keyring)) { | ||
69 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | ||
70 | tsk, KEY_ALLOC_IN_QUOTA, | ||
71 | NULL); | ||
72 | if (IS_ERR(uid_keyring)) { | ||
73 | ret = PTR_ERR(uid_keyring); | ||
74 | goto error; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* get a default session keyring (which might also exist | ||
79 | * already) */ | ||
80 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
81 | |||
82 | session_keyring = find_keyring_by_name(buf, true); | ||
83 | if (IS_ERR(session_keyring)) { | ||
84 | session_keyring = | ||
85 | keyring_alloc(buf, user->uid, (gid_t) -1, | ||
86 | tsk, KEY_ALLOC_IN_QUOTA, NULL); | ||
87 | if (IS_ERR(session_keyring)) { | ||
88 | ret = PTR_ERR(session_keyring); | ||
89 | goto error_release; | ||
90 | } | ||
91 | |||
92 | /* we install a link from the user session keyring to | ||
93 | * the user keyring */ | ||
94 | ret = key_link(session_keyring, uid_keyring); | ||
95 | if (ret < 0) | ||
96 | goto error_release_both; | ||
97 | } | ||
98 | |||
99 | /* install the keyrings */ | ||
100 | user->uid_keyring = uid_keyring; | ||
101 | user->session_keyring = session_keyring; | ||
97 | } | 102 | } |
98 | 103 | ||
99 | /* install the keyrings */ | 104 | mutex_unlock(&key_user_keyring_mutex); |
100 | user->uid_keyring = uid_keyring; | 105 | kleave(" = 0"); |
101 | user->session_keyring = session_keyring; | 106 | return 0; |
102 | ret = 0; | ||
103 | 107 | ||
108 | error_release_both: | ||
109 | key_put(session_keyring); | ||
110 | error_release: | ||
111 | key_put(uid_keyring); | ||
104 | error: | 112 | error: |
113 | mutex_unlock(&key_user_keyring_mutex); | ||
114 | kleave(" = %d", ret); | ||
105 | return ret; | 115 | return ret; |
106 | 116 | } | |
107 | } /* end alloc_uid_keyring() */ | ||
108 | 117 | ||
109 | /*****************************************************************************/ | 118 | /*****************************************************************************/ |
110 | /* | 119 | /* |
@@ -481,7 +490,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
481 | } | 490 | } |
482 | } | 491 | } |
483 | /* or search the user-session keyring */ | 492 | /* or search the user-session keyring */ |
484 | else { | 493 | else if (context->user->session_keyring) { |
485 | key_ref = keyring_search_aux( | 494 | key_ref = keyring_search_aux( |
486 | make_key_ref(context->user->session_keyring, 1), | 495 | make_key_ref(context->user->session_keyring, 1), |
487 | context, type, description, match); | 496 | context, type, description, match); |
@@ -614,6 +623,9 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
614 | if (!context->signal->session_keyring) { | 623 | if (!context->signal->session_keyring) { |
615 | /* always install a session keyring upon access if one | 624 | /* always install a session keyring upon access if one |
616 | * doesn't exist yet */ | 625 | * doesn't exist yet */ |
626 | ret = install_user_keyrings(context); | ||
627 | if (ret < 0) | ||
628 | goto error; | ||
617 | ret = install_session_keyring( | 629 | ret = install_session_keyring( |
618 | context, context->user->session_keyring); | 630 | context, context->user->session_keyring); |
619 | if (ret < 0) | 631 | if (ret < 0) |
@@ -628,12 +640,24 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
628 | break; | 640 | break; |
629 | 641 | ||
630 | case KEY_SPEC_USER_KEYRING: | 642 | case KEY_SPEC_USER_KEYRING: |
643 | if (!context->user->uid_keyring) { | ||
644 | ret = install_user_keyrings(context); | ||
645 | if (ret < 0) | ||
646 | goto error; | ||
647 | } | ||
648 | |||
631 | key = context->user->uid_keyring; | 649 | key = context->user->uid_keyring; |
632 | atomic_inc(&key->usage); | 650 | atomic_inc(&key->usage); |
633 | key_ref = make_key_ref(key, 1); | 651 | key_ref = make_key_ref(key, 1); |
634 | break; | 652 | break; |
635 | 653 | ||
636 | case KEY_SPEC_USER_SESSION_KEYRING: | 654 | case KEY_SPEC_USER_SESSION_KEYRING: |
655 | if (!context->user->session_keyring) { | ||
656 | ret = install_user_keyrings(context); | ||
657 | if (ret < 0) | ||
658 | goto error; | ||
659 | } | ||
660 | |||
637 | key = context->user->session_keyring; | 661 | key = context->user->session_keyring; |
638 | atomic_inc(&key->usage); | 662 | atomic_inc(&key->usage); |
639 | key_ref = make_key_ref(key, 1); | 663 | key_ref = make_key_ref(key, 1); |
@@ -744,7 +768,7 @@ long join_session_keyring(const char *name) | |||
744 | mutex_lock(&key_session_mutex); | 768 | mutex_lock(&key_session_mutex); |
745 | 769 | ||
746 | /* look for an existing keyring of this name */ | 770 | /* look for an existing keyring of this name */ |
747 | keyring = find_keyring_by_name(name, 0); | 771 | keyring = find_keyring_by_name(name, false); |
748 | if (PTR_ERR(keyring) == -ENOKEY) { | 772 | if (PTR_ERR(keyring) == -ENOKEY) { |
749 | /* not found - try and create a new one */ | 773 | /* not found - try and create a new one */ |
750 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, | 774 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, |