diff options
author | David Howells <dhowells@redhat.com> | 2019-06-26 16:02:32 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-06-26 16:02:32 -0400 |
commit | 0f44e4d976f96c6439da0d6717238efa4b91196e (patch) | |
tree | 3cec4bc4ef3faa4e61058e3aff066a7bec1c9d37 | |
parent | b206f281d0ee14969878469816a69db22d5838e8 (diff) |
keys: Move the user and user-session keyrings to the user_namespace
Move the user and user-session keyrings to the user_namespace struct rather
than pinning them from the user_struct struct. This prevents these
keyrings from propagating across user-namespaces boundaries with regard to
the KEY_SPEC_* flags, thereby making them more useful in a containerised
environment.
The issue is that a single user_struct may be represent UIDs in several
different namespaces.
The way the patch does this is by attaching a 'register keyring' in each
user_namespace and then sticking the user and user-session keyrings into
that. It can then be searched to retrieve them.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Jann Horn <jannh@google.com>
-rw-r--r-- | include/linux/sched/user.h | 14 | ||||
-rw-r--r-- | include/linux/user_namespace.h | 9 | ||||
-rw-r--r-- | kernel/user.c | 7 | ||||
-rw-r--r-- | kernel/user_namespace.c | 4 | ||||
-rw-r--r-- | security/keys/internal.h | 3 | ||||
-rw-r--r-- | security/keys/keyring.c | 1 | ||||
-rw-r--r-- | security/keys/persistent.c | 8 | ||||
-rw-r--r-- | security/keys/process_keys.c | 259 | ||||
-rw-r--r-- | security/keys/request_key.c | 20 |
9 files changed, 196 insertions, 129 deletions
diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h index 468d2565a9fe..917d88edb7b9 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h | |||
@@ -7,8 +7,6 @@ | |||
7 | #include <linux/refcount.h> | 7 | #include <linux/refcount.h> |
8 | #include <linux/ratelimit.h> | 8 | #include <linux/ratelimit.h> |
9 | 9 | ||
10 | struct key; | ||
11 | |||
12 | /* | 10 | /* |
13 | * Some day this will be a full-fledged user tracking system.. | 11 | * Some day this will be a full-fledged user tracking system.. |
14 | */ | 12 | */ |
@@ -30,18 +28,6 @@ struct user_struct { | |||
30 | unsigned long unix_inflight; /* How many files in flight in unix sockets */ | 28 | unsigned long unix_inflight; /* How many files in flight in unix sockets */ |
31 | atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ | 29 | atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ |
32 | 30 | ||
33 | #ifdef CONFIG_KEYS | ||
34 | /* | ||
35 | * These pointers can only change from NULL to a non-NULL value once. | ||
36 | * Writes are protected by key_user_keyring_mutex. | ||
37 | * Unlocked readers should use READ_ONCE() unless they know that | ||
38 | * install_user_keyrings() has been called successfully (which sets | ||
39 | * these members to non-NULL values, preventing further modifications). | ||
40 | */ | ||
41 | struct key *uid_keyring; /* UID specific keyring */ | ||
42 | struct key *session_keyring; /* UID's default session keyring */ | ||
43 | #endif | ||
44 | |||
45 | /* Hash table maintenance information */ | 31 | /* Hash table maintenance information */ |
46 | struct hlist_node uidhash_node; | 32 | struct hlist_node uidhash_node; |
47 | kuid_t uid; | 33 | kuid_t uid; |
diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 90457015fa3f..fb9f4f799554 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h | |||
@@ -65,14 +65,19 @@ struct user_namespace { | |||
65 | unsigned long flags; | 65 | unsigned long flags; |
66 | 66 | ||
67 | #ifdef CONFIG_KEYS | 67 | #ifdef CONFIG_KEYS |
68 | /* List of joinable keyrings in this namespace */ | 68 | /* List of joinable keyrings in this namespace. Modification access of |
69 | * these pointers is controlled by keyring_sem. Once | ||
70 | * user_keyring_register is set, it won't be changed, so it can be | ||
71 | * accessed directly with READ_ONCE(). | ||
72 | */ | ||
69 | struct list_head keyring_name_list; | 73 | struct list_head keyring_name_list; |
74 | struct key *user_keyring_register; | ||
75 | struct rw_semaphore keyring_sem; | ||
70 | #endif | 76 | #endif |
71 | 77 | ||
72 | /* Register of per-UID persistent keyrings for this namespace */ | 78 | /* Register of per-UID persistent keyrings for this namespace */ |
73 | #ifdef CONFIG_PERSISTENT_KEYRINGS | 79 | #ifdef CONFIG_PERSISTENT_KEYRINGS |
74 | struct key *persistent_keyring_register; | 80 | struct key *persistent_keyring_register; |
75 | struct rw_semaphore persistent_keyring_register_sem; | ||
76 | #endif | 81 | #endif |
77 | struct work_struct work; | 82 | struct work_struct work; |
78 | #ifdef CONFIG_SYSCTL | 83 | #ifdef CONFIG_SYSCTL |
diff --git a/kernel/user.c b/kernel/user.c index 50979fd1b7aa..f8519b62cf9a 100644 --- a/kernel/user.c +++ b/kernel/user.c | |||
@@ -64,10 +64,7 @@ struct user_namespace init_user_ns = { | |||
64 | .flags = USERNS_INIT_FLAGS, | 64 | .flags = USERNS_INIT_FLAGS, |
65 | #ifdef CONFIG_KEYS | 65 | #ifdef CONFIG_KEYS |
66 | .keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list), | 66 | .keyring_name_list = LIST_HEAD_INIT(init_user_ns.keyring_name_list), |
67 | #endif | 67 | .keyring_sem = __RWSEM_INITIALIZER(init_user_ns.keyring_sem), |
68 | #ifdef CONFIG_PERSISTENT_KEYRINGS | ||
69 | .persistent_keyring_register_sem = | ||
70 | __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), | ||
71 | #endif | 68 | #endif |
72 | }; | 69 | }; |
73 | EXPORT_SYMBOL_GPL(init_user_ns); | 70 | EXPORT_SYMBOL_GPL(init_user_ns); |
@@ -143,8 +140,6 @@ static void free_user(struct user_struct *up, unsigned long flags) | |||
143 | { | 140 | { |
144 | uid_hash_remove(up); | 141 | uid_hash_remove(up); |
145 | spin_unlock_irqrestore(&uidhash_lock, flags); | 142 | spin_unlock_irqrestore(&uidhash_lock, flags); |
146 | key_put(up->uid_keyring); | ||
147 | key_put(up->session_keyring); | ||
148 | kmem_cache_free(uid_cachep, up); | 143 | kmem_cache_free(uid_cachep, up); |
149 | } | 144 | } |
150 | 145 | ||
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index bda6e890ad88..c87c2ecc7085 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -135,9 +135,7 @@ int create_user_ns(struct cred *new) | |||
135 | 135 | ||
136 | #ifdef CONFIG_KEYS | 136 | #ifdef CONFIG_KEYS |
137 | INIT_LIST_HEAD(&ns->keyring_name_list); | 137 | INIT_LIST_HEAD(&ns->keyring_name_list); |
138 | #endif | 138 | init_rwsem(&ns->keyring_sem); |
139 | #ifdef CONFIG_PERSISTENT_KEYRINGS | ||
140 | init_rwsem(&ns->persistent_keyring_register_sem); | ||
141 | #endif | 139 | #endif |
142 | ret = -ENOMEM; | 140 | ret = -ENOMEM; |
143 | if (!setup_userns_sysctls(ns)) | 141 | if (!setup_userns_sysctls(ns)) |
diff --git a/security/keys/internal.h b/security/keys/internal.h index aa361299a3ec..d3a9439e2386 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -148,7 +148,8 @@ extern key_ref_t search_process_keyrings_rcu(struct keyring_search_context *ctx) | |||
148 | 148 | ||
149 | extern struct key *find_keyring_by_name(const char *name, bool uid_keyring); | 149 | extern struct key *find_keyring_by_name(const char *name, bool uid_keyring); |
150 | 150 | ||
151 | extern int install_user_keyrings(void); | 151 | extern int look_up_user_keyrings(struct key **, struct key **); |
152 | extern struct key *get_user_session_keyring_rcu(const struct cred *); | ||
152 | extern int install_thread_keyring_to_cred(struct cred *); | 153 | extern int install_thread_keyring_to_cred(struct cred *); |
153 | extern int install_process_keyring_to_cred(struct cred *); | 154 | extern int install_process_keyring_to_cred(struct cred *); |
154 | extern int install_session_keyring_to_cred(struct cred *, struct key *); | 155 | extern int install_session_keyring_to_cred(struct cred *, struct key *); |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index fe851292509e..3663e5168583 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -62,6 +62,7 @@ void key_free_user_ns(struct user_namespace *ns) | |||
62 | list_del_init(&ns->keyring_name_list); | 62 | list_del_init(&ns->keyring_name_list); |
63 | write_unlock(&keyring_name_lock); | 63 | write_unlock(&keyring_name_lock); |
64 | 64 | ||
65 | key_put(ns->user_keyring_register); | ||
65 | #ifdef CONFIG_PERSISTENT_KEYRINGS | 66 | #ifdef CONFIG_PERSISTENT_KEYRINGS |
66 | key_put(ns->persistent_keyring_register); | 67 | key_put(ns->persistent_keyring_register); |
67 | #endif | 68 | #endif |
diff --git a/security/keys/persistent.c b/security/keys/persistent.c index fc29ec59efa7..90303fe4a394 100644 --- a/security/keys/persistent.c +++ b/security/keys/persistent.c | |||
@@ -91,9 +91,9 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, | |||
91 | 91 | ||
92 | if (ns->persistent_keyring_register) { | 92 | if (ns->persistent_keyring_register) { |
93 | reg_ref = make_key_ref(ns->persistent_keyring_register, true); | 93 | reg_ref = make_key_ref(ns->persistent_keyring_register, true); |
94 | down_read(&ns->persistent_keyring_register_sem); | 94 | down_read(&ns->keyring_sem); |
95 | persistent_ref = find_key_to_update(reg_ref, &index_key); | 95 | persistent_ref = find_key_to_update(reg_ref, &index_key); |
96 | up_read(&ns->persistent_keyring_register_sem); | 96 | up_read(&ns->keyring_sem); |
97 | 97 | ||
98 | if (persistent_ref) | 98 | if (persistent_ref) |
99 | goto found; | 99 | goto found; |
@@ -102,9 +102,9 @@ static long key_get_persistent(struct user_namespace *ns, kuid_t uid, | |||
102 | /* It wasn't in the register, so we'll need to create it. We might | 102 | /* It wasn't in the register, so we'll need to create it. We might |
103 | * also need to create the register. | 103 | * also need to create the register. |
104 | */ | 104 | */ |
105 | down_write(&ns->persistent_keyring_register_sem); | 105 | down_write(&ns->keyring_sem); |
106 | persistent_ref = key_create_persistent(ns, uid, &index_key); | 106 | persistent_ref = key_create_persistent(ns, uid, &index_key); |
107 | up_write(&ns->persistent_keyring_register_sem); | 107 | up_write(&ns->keyring_sem); |
108 | if (!IS_ERR(persistent_ref)) | 108 | if (!IS_ERR(persistent_ref)) |
109 | goto found; | 109 | goto found; |
110 | 110 | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index b07f768d23dc..f74d64215942 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -19,15 +19,13 @@ | |||
19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
20 | #include <linux/user_namespace.h> | 20 | #include <linux/user_namespace.h> |
21 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
22 | #include <linux/init_task.h> | ||
22 | #include <keys/request_key_auth-type.h> | 23 | #include <keys/request_key_auth-type.h> |
23 | #include "internal.h" | 24 | #include "internal.h" |
24 | 25 | ||
25 | /* Session keyring create vs join semaphore */ | 26 | /* Session keyring create vs join semaphore */ |
26 | static DEFINE_MUTEX(key_session_mutex); | 27 | static DEFINE_MUTEX(key_session_mutex); |
27 | 28 | ||
28 | /* User keyring creation semaphore */ | ||
29 | static DEFINE_MUTEX(key_user_keyring_mutex); | ||
30 | |||
31 | /* The root user's tracking struct */ | 29 | /* The root user's tracking struct */ |
32 | struct key_user root_key_user = { | 30 | struct key_user root_key_user = { |
33 | .usage = REFCOUNT_INIT(3), | 31 | .usage = REFCOUNT_INIT(3), |
@@ -39,99 +37,186 @@ struct key_user root_key_user = { | |||
39 | }; | 37 | }; |
40 | 38 | ||
41 | /* | 39 | /* |
42 | * Install the user and user session keyrings for the current process's UID. | 40 | * Get or create a user register keyring. |
41 | */ | ||
42 | static struct key *get_user_register(struct user_namespace *user_ns) | ||
43 | { | ||
44 | struct key *reg_keyring = READ_ONCE(user_ns->user_keyring_register); | ||
45 | |||
46 | if (reg_keyring) | ||
47 | return reg_keyring; | ||
48 | |||
49 | down_write(&user_ns->keyring_sem); | ||
50 | |||
51 | /* Make sure there's a register keyring. It gets owned by the | ||
52 | * user_namespace's owner. | ||
53 | */ | ||
54 | reg_keyring = user_ns->user_keyring_register; | ||
55 | if (!reg_keyring) { | ||
56 | reg_keyring = keyring_alloc(".user_reg", | ||
57 | user_ns->owner, INVALID_GID, | ||
58 | &init_cred, | ||
59 | KEY_POS_WRITE | KEY_POS_SEARCH | | ||
60 | KEY_USR_VIEW | KEY_USR_READ, | ||
61 | 0, | ||
62 | NULL, NULL); | ||
63 | if (!IS_ERR(reg_keyring)) | ||
64 | smp_store_release(&user_ns->user_keyring_register, | ||
65 | reg_keyring); | ||
66 | } | ||
67 | |||
68 | up_write(&user_ns->keyring_sem); | ||
69 | |||
70 | /* We don't return a ref since the keyring is pinned by the user_ns */ | ||
71 | return reg_keyring; | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * Look up the user and user session keyrings for the current process's UID, | ||
76 | * creating them if they don't exist. | ||
43 | */ | 77 | */ |
44 | int install_user_keyrings(void) | 78 | int look_up_user_keyrings(struct key **_user_keyring, |
79 | struct key **_user_session_keyring) | ||
45 | { | 80 | { |
46 | struct user_struct *user; | 81 | const struct cred *cred = current_cred(); |
47 | const struct cred *cred; | 82 | struct user_namespace *user_ns = current_user_ns(); |
48 | struct key *uid_keyring, *session_keyring; | 83 | struct key *reg_keyring, *uid_keyring, *session_keyring; |
49 | key_perm_t user_keyring_perm; | 84 | key_perm_t user_keyring_perm; |
85 | key_ref_t uid_keyring_r, session_keyring_r; | ||
86 | uid_t uid = from_kuid(user_ns, cred->user->uid); | ||
50 | char buf[20]; | 87 | char buf[20]; |
51 | int ret; | 88 | int ret; |
52 | uid_t uid; | ||
53 | 89 | ||
54 | user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; | 90 | user_keyring_perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL; |
55 | cred = current_cred(); | ||
56 | user = cred->user; | ||
57 | uid = from_kuid(cred->user_ns, user->uid); | ||
58 | 91 | ||
59 | kenter("%p{%u}", user, uid); | 92 | kenter("%u", uid); |
60 | 93 | ||
61 | if (READ_ONCE(user->uid_keyring) && READ_ONCE(user->session_keyring)) { | 94 | reg_keyring = get_user_register(user_ns); |
62 | kleave(" = 0 [exist]"); | 95 | if (IS_ERR(reg_keyring)) |
63 | return 0; | 96 | return PTR_ERR(reg_keyring); |
64 | } | ||
65 | 97 | ||
66 | mutex_lock(&key_user_keyring_mutex); | 98 | down_write(&user_ns->keyring_sem); |
67 | ret = 0; | 99 | ret = 0; |
68 | 100 | ||
69 | if (!user->uid_keyring) { | 101 | /* Get the user keyring. Note that there may be one in existence |
70 | /* get the UID-specific keyring | 102 | * already as it may have been pinned by a session, but the user_struct |
71 | * - there may be one in existence already as it may have been | 103 | * pointing to it may have been destroyed by setuid. |
72 | * pinned by a session, but the user_struct pointing to it | 104 | */ |
73 | * may have been destroyed by setuid */ | 105 | snprintf(buf, sizeof(buf), "_uid.%u", uid); |
74 | sprintf(buf, "_uid.%u", uid); | 106 | uid_keyring_r = keyring_search(make_key_ref(reg_keyring, true), |
75 | 107 | &key_type_keyring, buf, false); | |
76 | uid_keyring = find_keyring_by_name(buf, true); | 108 | kdebug("_uid %p", uid_keyring_r); |
109 | if (uid_keyring_r == ERR_PTR(-EAGAIN)) { | ||
110 | uid_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, | ||
111 | cred, user_keyring_perm, | ||
112 | KEY_ALLOC_UID_KEYRING | | ||
113 | KEY_ALLOC_IN_QUOTA, | ||
114 | NULL, reg_keyring); | ||
77 | if (IS_ERR(uid_keyring)) { | 115 | if (IS_ERR(uid_keyring)) { |
78 | uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID, | 116 | ret = PTR_ERR(uid_keyring); |
79 | cred, user_keyring_perm, | 117 | goto error; |
80 | KEY_ALLOC_UID_KEYRING | | ||
81 | KEY_ALLOC_IN_QUOTA, | ||
82 | NULL, NULL); | ||
83 | if (IS_ERR(uid_keyring)) { | ||
84 | ret = PTR_ERR(uid_keyring); | ||
85 | goto error; | ||
86 | } | ||
87 | } | 118 | } |
119 | } else if (IS_ERR(uid_keyring_r)) { | ||
120 | ret = PTR_ERR(uid_keyring_r); | ||
121 | goto error; | ||
122 | } else { | ||
123 | uid_keyring = key_ref_to_ptr(uid_keyring_r); | ||
124 | } | ||
88 | 125 | ||
89 | /* get a default session keyring (which might also exist | 126 | /* Get a default session keyring (which might also exist already) */ |
90 | * already) */ | 127 | snprintf(buf, sizeof(buf), "_uid_ses.%u", uid); |
91 | sprintf(buf, "_uid_ses.%u", uid); | 128 | session_keyring_r = keyring_search(make_key_ref(reg_keyring, true), |
92 | 129 | &key_type_keyring, buf, false); | |
93 | session_keyring = find_keyring_by_name(buf, true); | 130 | kdebug("_uid_ses %p", session_keyring_r); |
131 | if (session_keyring_r == ERR_PTR(-EAGAIN)) { | ||
132 | session_keyring = keyring_alloc(buf, cred->user->uid, INVALID_GID, | ||
133 | cred, user_keyring_perm, | ||
134 | KEY_ALLOC_UID_KEYRING | | ||
135 | KEY_ALLOC_IN_QUOTA, | ||
136 | NULL, NULL); | ||
94 | if (IS_ERR(session_keyring)) { | 137 | if (IS_ERR(session_keyring)) { |
95 | session_keyring = | 138 | ret = PTR_ERR(session_keyring); |
96 | keyring_alloc(buf, user->uid, INVALID_GID, | 139 | goto error_release; |
97 | cred, user_keyring_perm, | ||
98 | KEY_ALLOC_UID_KEYRING | | ||
99 | KEY_ALLOC_IN_QUOTA, | ||
100 | NULL, NULL); | ||
101 | if (IS_ERR(session_keyring)) { | ||
102 | ret = PTR_ERR(session_keyring); | ||
103 | goto error_release; | ||
104 | } | ||
105 | |||
106 | /* we install a link from the user session keyring to | ||
107 | * the user keyring */ | ||
108 | ret = key_link(session_keyring, uid_keyring); | ||
109 | if (ret < 0) | ||
110 | goto error_release_both; | ||
111 | } | 140 | } |
112 | 141 | ||
113 | /* install the keyrings */ | 142 | /* We install a link from the user session keyring to |
114 | /* paired with READ_ONCE() */ | 143 | * the user keyring. |
115 | smp_store_release(&user->uid_keyring, uid_keyring); | 144 | */ |
116 | /* paired with READ_ONCE() */ | 145 | ret = key_link(session_keyring, uid_keyring); |
117 | smp_store_release(&user->session_keyring, session_keyring); | 146 | if (ret < 0) |
147 | goto error_release_session; | ||
148 | |||
149 | /* And only then link the user-session keyring to the | ||
150 | * register. | ||
151 | */ | ||
152 | ret = key_link(reg_keyring, session_keyring); | ||
153 | if (ret < 0) | ||
154 | goto error_release_session; | ||
155 | } else if (IS_ERR(session_keyring_r)) { | ||
156 | ret = PTR_ERR(session_keyring_r); | ||
157 | goto error_release; | ||
158 | } else { | ||
159 | session_keyring = key_ref_to_ptr(session_keyring_r); | ||
118 | } | 160 | } |
119 | 161 | ||
120 | mutex_unlock(&key_user_keyring_mutex); | 162 | up_write(&user_ns->keyring_sem); |
163 | |||
164 | if (_user_session_keyring) | ||
165 | *_user_session_keyring = session_keyring; | ||
166 | else | ||
167 | key_put(session_keyring); | ||
168 | if (_user_keyring) | ||
169 | *_user_keyring = uid_keyring; | ||
170 | else | ||
171 | key_put(uid_keyring); | ||
121 | kleave(" = 0"); | 172 | kleave(" = 0"); |
122 | return 0; | 173 | return 0; |
123 | 174 | ||
124 | error_release_both: | 175 | error_release_session: |
125 | key_put(session_keyring); | 176 | key_put(session_keyring); |
126 | error_release: | 177 | error_release: |
127 | key_put(uid_keyring); | 178 | key_put(uid_keyring); |
128 | error: | 179 | error: |
129 | mutex_unlock(&key_user_keyring_mutex); | 180 | up_write(&user_ns->keyring_sem); |
130 | kleave(" = %d", ret); | 181 | kleave(" = %d", ret); |
131 | return ret; | 182 | return ret; |
132 | } | 183 | } |
133 | 184 | ||
134 | /* | 185 | /* |
186 | * Get the user session keyring if it exists, but don't create it if it | ||
187 | * doesn't. | ||
188 | */ | ||
189 | struct key *get_user_session_keyring_rcu(const struct cred *cred) | ||
190 | { | ||
191 | struct key *reg_keyring = READ_ONCE(cred->user_ns->user_keyring_register); | ||
192 | key_ref_t session_keyring_r; | ||
193 | char buf[20]; | ||
194 | |||
195 | struct keyring_search_context ctx = { | ||
196 | .index_key.type = &key_type_keyring, | ||
197 | .index_key.description = buf, | ||
198 | .cred = cred, | ||
199 | .match_data.cmp = key_default_cmp, | ||
200 | .match_data.raw_data = buf, | ||
201 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | ||
202 | .flags = KEYRING_SEARCH_DO_STATE_CHECK, | ||
203 | }; | ||
204 | |||
205 | if (!reg_keyring) | ||
206 | return NULL; | ||
207 | |||
208 | ctx.index_key.desc_len = snprintf(buf, sizeof(buf), "_uid_ses.%u", | ||
209 | from_kuid(cred->user_ns, | ||
210 | cred->user->uid)); | ||
211 | |||
212 | session_keyring_r = keyring_search_rcu(make_key_ref(reg_keyring, true), | ||
213 | &ctx); | ||
214 | if (IS_ERR(session_keyring_r)) | ||
215 | return NULL; | ||
216 | return key_ref_to_ptr(session_keyring_r); | ||
217 | } | ||
218 | |||
219 | /* | ||
135 | * Install a thread keyring to the given credentials struct if it didn't have | 220 | * Install a thread keyring to the given credentials struct if it didn't have |
136 | * one already. This is allowed to overrun the quota. | 221 | * one already. This is allowed to overrun the quota. |
137 | * | 222 | * |
@@ -340,6 +425,7 @@ void key_fsgid_changed(struct cred *new_cred) | |||
340 | */ | 425 | */ |
341 | key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx) | 426 | key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx) |
342 | { | 427 | { |
428 | struct key *user_session; | ||
343 | key_ref_t key_ref, ret, err; | 429 | key_ref_t key_ref, ret, err; |
344 | const struct cred *cred = ctx->cred; | 430 | const struct cred *cred = ctx->cred; |
345 | 431 | ||
@@ -415,10 +501,11 @@ key_ref_t search_cred_keyrings_rcu(struct keyring_search_context *ctx) | |||
415 | } | 501 | } |
416 | } | 502 | } |
417 | /* or search the user-session keyring */ | 503 | /* or search the user-session keyring */ |
418 | else if (READ_ONCE(cred->user->session_keyring)) { | 504 | else if ((user_session = get_user_session_keyring_rcu(cred))) { |
419 | key_ref = keyring_search_rcu( | 505 | key_ref = keyring_search_rcu(make_key_ref(user_session, 1), |
420 | make_key_ref(READ_ONCE(cred->user->session_keyring), 1), | 506 | ctx); |
421 | ctx); | 507 | key_put(user_session); |
508 | |||
422 | if (!IS_ERR(key_ref)) | 509 | if (!IS_ERR(key_ref)) |
423 | goto found; | 510 | goto found; |
424 | 511 | ||
@@ -535,7 +622,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, | |||
535 | KEYRING_SEARCH_RECURSE), | 622 | KEYRING_SEARCH_RECURSE), |
536 | }; | 623 | }; |
537 | struct request_key_auth *rka; | 624 | struct request_key_auth *rka; |
538 | struct key *key; | 625 | struct key *key, *user_session; |
539 | key_ref_t key_ref, skey_ref; | 626 | key_ref_t key_ref, skey_ref; |
540 | int ret; | 627 | int ret; |
541 | 628 | ||
@@ -584,20 +671,20 @@ try_again: | |||
584 | if (!ctx.cred->session_keyring) { | 671 | if (!ctx.cred->session_keyring) { |
585 | /* always install a session keyring upon access if one | 672 | /* always install a session keyring upon access if one |
586 | * doesn't exist yet */ | 673 | * doesn't exist yet */ |
587 | ret = install_user_keyrings(); | 674 | ret = look_up_user_keyrings(NULL, &user_session); |
588 | if (ret < 0) | 675 | if (ret < 0) |
589 | goto error; | 676 | goto error; |
590 | if (lflags & KEY_LOOKUP_CREATE) | 677 | if (lflags & KEY_LOOKUP_CREATE) |
591 | ret = join_session_keyring(NULL); | 678 | ret = join_session_keyring(NULL); |
592 | else | 679 | else |
593 | ret = install_session_keyring( | 680 | ret = install_session_keyring(user_session); |
594 | ctx.cred->user->session_keyring); | ||
595 | 681 | ||
682 | key_put(user_session); | ||
596 | if (ret < 0) | 683 | if (ret < 0) |
597 | goto error; | 684 | goto error; |
598 | goto reget_creds; | 685 | goto reget_creds; |
599 | } else if (ctx.cred->session_keyring == | 686 | } else if (test_bit(KEY_FLAG_UID_KEYRING, |
600 | READ_ONCE(ctx.cred->user->session_keyring) && | 687 | &ctx.cred->session_keyring->flags) && |
601 | lflags & KEY_LOOKUP_CREATE) { | 688 | lflags & KEY_LOOKUP_CREATE) { |
602 | ret = join_session_keyring(NULL); | 689 | ret = join_session_keyring(NULL); |
603 | if (ret < 0) | 690 | if (ret < 0) |
@@ -611,26 +698,16 @@ try_again: | |||
611 | break; | 698 | break; |
612 | 699 | ||
613 | case KEY_SPEC_USER_KEYRING: | 700 | case KEY_SPEC_USER_KEYRING: |
614 | if (!READ_ONCE(ctx.cred->user->uid_keyring)) { | 701 | ret = look_up_user_keyrings(&key, NULL); |
615 | ret = install_user_keyrings(); | 702 | if (ret < 0) |
616 | if (ret < 0) | 703 | goto error; |
617 | goto error; | ||
618 | } | ||
619 | |||
620 | key = ctx.cred->user->uid_keyring; | ||
621 | __key_get(key); | ||
622 | key_ref = make_key_ref(key, 1); | 704 | key_ref = make_key_ref(key, 1); |
623 | break; | 705 | break; |
624 | 706 | ||
625 | case KEY_SPEC_USER_SESSION_KEYRING: | 707 | case KEY_SPEC_USER_SESSION_KEYRING: |
626 | if (!READ_ONCE(ctx.cred->user->session_keyring)) { | 708 | ret = look_up_user_keyrings(NULL, &key); |
627 | ret = install_user_keyrings(); | 709 | if (ret < 0) |
628 | if (ret < 0) | 710 | goto error; |
629 | goto error; | ||
630 | } | ||
631 | |||
632 | key = ctx.cred->user->session_keyring; | ||
633 | __key_get(key); | ||
634 | key_ref = make_key_ref(key, 1); | 711 | key_ref = make_key_ref(key, 1); |
635 | break; | 712 | break; |
636 | 713 | ||
@@ -879,7 +956,7 @@ void key_change_session_keyring(struct callback_head *twork) | |||
879 | */ | 956 | */ |
880 | static int __init init_root_keyring(void) | 957 | static int __init init_root_keyring(void) |
881 | { | 958 | { |
882 | return install_user_keyrings(); | 959 | return look_up_user_keyrings(NULL, NULL); |
883 | } | 960 | } |
884 | 961 | ||
885 | late_initcall(init_root_keyring); | 962 | late_initcall(init_root_keyring); |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 1ffd3803ce29..9201ca96c4df 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -121,7 +121,7 @@ static int call_sbin_request_key(struct key *authkey, void *aux) | |||
121 | struct request_key_auth *rka = get_request_key_auth(authkey); | 121 | struct request_key_auth *rka = get_request_key_auth(authkey); |
122 | const struct cred *cred = current_cred(); | 122 | const struct cred *cred = current_cred(); |
123 | key_serial_t prkey, sskey; | 123 | key_serial_t prkey, sskey; |
124 | struct key *key = rka->target_key, *keyring, *session; | 124 | struct key *key = rka->target_key, *keyring, *session, *user_session; |
125 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; | 125 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
126 | char key_str[12], keyring_str[3][12]; | 126 | char key_str[12], keyring_str[3][12]; |
127 | char desc[20]; | 127 | char desc[20]; |
@@ -129,9 +129,9 @@ static int call_sbin_request_key(struct key *authkey, void *aux) | |||
129 | 129 | ||
130 | kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op); | 130 | kenter("{%d},{%d},%s", key->serial, authkey->serial, rka->op); |
131 | 131 | ||
132 | ret = install_user_keyrings(); | 132 | ret = look_up_user_keyrings(NULL, &user_session); |
133 | if (ret < 0) | 133 | if (ret < 0) |
134 | goto error_alloc; | 134 | goto error_us; |
135 | 135 | ||
136 | /* allocate a new session keyring */ | 136 | /* allocate a new session keyring */ |
137 | sprintf(desc, "_req.%u", key->serial); | 137 | sprintf(desc, "_req.%u", key->serial); |
@@ -169,7 +169,7 @@ static int call_sbin_request_key(struct key *authkey, void *aux) | |||
169 | 169 | ||
170 | session = cred->session_keyring; | 170 | session = cred->session_keyring; |
171 | if (!session) | 171 | if (!session) |
172 | session = cred->user->session_keyring; | 172 | session = user_session; |
173 | sskey = session->serial; | 173 | sskey = session->serial; |
174 | 174 | ||
175 | sprintf(keyring_str[2], "%d", sskey); | 175 | sprintf(keyring_str[2], "%d", sskey); |
@@ -211,6 +211,8 @@ error_link: | |||
211 | key_put(keyring); | 211 | key_put(keyring); |
212 | 212 | ||
213 | error_alloc: | 213 | error_alloc: |
214 | key_put(user_session); | ||
215 | error_us: | ||
214 | complete_request_key(authkey, ret); | 216 | complete_request_key(authkey, ret); |
215 | kleave(" = %d", ret); | 217 | kleave(" = %d", ret); |
216 | return ret; | 218 | return ret; |
@@ -317,13 +319,15 @@ static int construct_get_dest_keyring(struct key **_dest_keyring) | |||
317 | 319 | ||
318 | /* fall through */ | 320 | /* fall through */ |
319 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | 321 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
320 | dest_keyring = | 322 | ret = look_up_user_keyrings(NULL, &dest_keyring); |
321 | key_get(READ_ONCE(cred->user->session_keyring)); | 323 | if (ret < 0) |
324 | return ret; | ||
322 | break; | 325 | break; |
323 | 326 | ||
324 | case KEY_REQKEY_DEFL_USER_KEYRING: | 327 | case KEY_REQKEY_DEFL_USER_KEYRING: |
325 | dest_keyring = | 328 | ret = look_up_user_keyrings(&dest_keyring, NULL); |
326 | key_get(READ_ONCE(cred->user->uid_keyring)); | 329 | if (ret < 0) |
330 | return ret; | ||
327 | break; | 331 | break; |
328 | 332 | ||
329 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | 333 | case KEY_REQKEY_DEFL_GROUP_KEYRING: |