Commit 27d6379894be4a81984da4d48002196a83939ca9
Committed by
Linus Torvalds
1 parent
765aaafe38
Exists in
master
and in
20 other branches
Fix install_process_keyring error handling
Fix an incorrect error check that returns 1 for error instead of the expected error code. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
security/keys/process_keys.c
1 | /* Management of a process's keyrings | 1 | /* Management of a process's keyrings |
2 | * | 2 | * |
3 | * Copyright (C) 2004-2005, 2008 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 |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/keyctl.h> | 15 | #include <linux/keyctl.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/err.h> | 17 | #include <linux/err.h> |
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | #include <linux/security.h> | 19 | #include <linux/security.h> |
20 | #include <linux/user_namespace.h> | 20 | #include <linux/user_namespace.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | #include "internal.h" | 22 | #include "internal.h" |
23 | 23 | ||
24 | /* session keyring create vs join semaphore */ | 24 | /* session keyring create vs join semaphore */ |
25 | static DEFINE_MUTEX(key_session_mutex); | 25 | static DEFINE_MUTEX(key_session_mutex); |
26 | 26 | ||
27 | /* user keyring creation semaphore */ | 27 | /* user keyring creation semaphore */ |
28 | static DEFINE_MUTEX(key_user_keyring_mutex); | 28 | static DEFINE_MUTEX(key_user_keyring_mutex); |
29 | 29 | ||
30 | /* the root user's tracking struct */ | 30 | /* the root user's tracking struct */ |
31 | struct key_user root_key_user = { | 31 | struct key_user root_key_user = { |
32 | .usage = ATOMIC_INIT(3), | 32 | .usage = ATOMIC_INIT(3), |
33 | .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), | 33 | .cons_lock = __MUTEX_INITIALIZER(root_key_user.cons_lock), |
34 | .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), | 34 | .lock = __SPIN_LOCK_UNLOCKED(root_key_user.lock), |
35 | .nkeys = ATOMIC_INIT(2), | 35 | .nkeys = ATOMIC_INIT(2), |
36 | .nikeys = ATOMIC_INIT(2), | 36 | .nikeys = ATOMIC_INIT(2), |
37 | .uid = 0, | 37 | .uid = 0, |
38 | .user_ns = &init_user_ns, | 38 | .user_ns = &init_user_ns, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | /*****************************************************************************/ | 41 | /*****************************************************************************/ |
42 | /* | 42 | /* |
43 | * install user and user session keyrings for a particular UID | 43 | * install user and user session keyrings for a particular UID |
44 | */ | 44 | */ |
45 | int install_user_keyrings(void) | 45 | int install_user_keyrings(void) |
46 | { | 46 | { |
47 | struct user_struct *user; | 47 | struct user_struct *user; |
48 | const struct cred *cred; | 48 | const struct cred *cred; |
49 | struct key *uid_keyring, *session_keyring; | 49 | struct key *uid_keyring, *session_keyring; |
50 | char buf[20]; | 50 | char buf[20]; |
51 | int ret; | 51 | int ret; |
52 | 52 | ||
53 | cred = current_cred(); | 53 | cred = current_cred(); |
54 | user = cred->user; | 54 | user = cred->user; |
55 | 55 | ||
56 | kenter("%p{%u}", user, user->uid); | 56 | kenter("%p{%u}", user, user->uid); |
57 | 57 | ||
58 | if (user->uid_keyring) { | 58 | if (user->uid_keyring) { |
59 | kleave(" = 0 [exist]"); | 59 | kleave(" = 0 [exist]"); |
60 | return 0; | 60 | return 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | mutex_lock(&key_user_keyring_mutex); | 63 | mutex_lock(&key_user_keyring_mutex); |
64 | ret = 0; | 64 | ret = 0; |
65 | 65 | ||
66 | if (!user->uid_keyring) { | 66 | if (!user->uid_keyring) { |
67 | /* get the UID-specific keyring | 67 | /* get the UID-specific keyring |
68 | * - there may be one in existence already as it may have been | 68 | * - there may be one in existence already as it may have been |
69 | * pinned by a session, but the user_struct pointing to it | 69 | * pinned by a session, but the user_struct pointing to it |
70 | * may have been destroyed by setuid */ | 70 | * may have been destroyed by setuid */ |
71 | sprintf(buf, "_uid.%u", user->uid); | 71 | sprintf(buf, "_uid.%u", user->uid); |
72 | 72 | ||
73 | uid_keyring = find_keyring_by_name(buf, true); | 73 | uid_keyring = find_keyring_by_name(buf, true); |
74 | if (IS_ERR(uid_keyring)) { | 74 | if (IS_ERR(uid_keyring)) { |
75 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | 75 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, |
76 | cred, KEY_ALLOC_IN_QUOTA, | 76 | cred, KEY_ALLOC_IN_QUOTA, |
77 | NULL); | 77 | NULL); |
78 | if (IS_ERR(uid_keyring)) { | 78 | if (IS_ERR(uid_keyring)) { |
79 | ret = PTR_ERR(uid_keyring); | 79 | ret = PTR_ERR(uid_keyring); |
80 | goto error; | 80 | goto error; |
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | /* get a default session keyring (which might also exist | 84 | /* get a default session keyring (which might also exist |
85 | * already) */ | 85 | * already) */ |
86 | sprintf(buf, "_uid_ses.%u", user->uid); | 86 | sprintf(buf, "_uid_ses.%u", user->uid); |
87 | 87 | ||
88 | session_keyring = find_keyring_by_name(buf, true); | 88 | session_keyring = find_keyring_by_name(buf, true); |
89 | if (IS_ERR(session_keyring)) { | 89 | if (IS_ERR(session_keyring)) { |
90 | session_keyring = | 90 | session_keyring = |
91 | keyring_alloc(buf, user->uid, (gid_t) -1, | 91 | keyring_alloc(buf, user->uid, (gid_t) -1, |
92 | cred, KEY_ALLOC_IN_QUOTA, NULL); | 92 | cred, KEY_ALLOC_IN_QUOTA, NULL); |
93 | if (IS_ERR(session_keyring)) { | 93 | if (IS_ERR(session_keyring)) { |
94 | ret = PTR_ERR(session_keyring); | 94 | ret = PTR_ERR(session_keyring); |
95 | goto error_release; | 95 | goto error_release; |
96 | } | 96 | } |
97 | 97 | ||
98 | /* we install a link from the user session keyring to | 98 | /* we install a link from the user session keyring to |
99 | * the user keyring */ | 99 | * the user keyring */ |
100 | ret = key_link(session_keyring, uid_keyring); | 100 | ret = key_link(session_keyring, uid_keyring); |
101 | if (ret < 0) | 101 | if (ret < 0) |
102 | goto error_release_both; | 102 | goto error_release_both; |
103 | } | 103 | } |
104 | 104 | ||
105 | /* install the keyrings */ | 105 | /* install the keyrings */ |
106 | user->uid_keyring = uid_keyring; | 106 | user->uid_keyring = uid_keyring; |
107 | user->session_keyring = session_keyring; | 107 | user->session_keyring = session_keyring; |
108 | } | 108 | } |
109 | 109 | ||
110 | mutex_unlock(&key_user_keyring_mutex); | 110 | mutex_unlock(&key_user_keyring_mutex); |
111 | kleave(" = 0"); | 111 | kleave(" = 0"); |
112 | return 0; | 112 | return 0; |
113 | 113 | ||
114 | error_release_both: | 114 | error_release_both: |
115 | key_put(session_keyring); | 115 | key_put(session_keyring); |
116 | error_release: | 116 | error_release: |
117 | key_put(uid_keyring); | 117 | key_put(uid_keyring); |
118 | error: | 118 | error: |
119 | mutex_unlock(&key_user_keyring_mutex); | 119 | mutex_unlock(&key_user_keyring_mutex); |
120 | kleave(" = %d", ret); | 120 | kleave(" = %d", ret); |
121 | return ret; | 121 | return ret; |
122 | } | 122 | } |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * install a fresh thread keyring directly to new credentials | 125 | * install a fresh thread keyring directly to new credentials |
126 | */ | 126 | */ |
127 | int install_thread_keyring_to_cred(struct cred *new) | 127 | int install_thread_keyring_to_cred(struct cred *new) |
128 | { | 128 | { |
129 | struct key *keyring; | 129 | struct key *keyring; |
130 | 130 | ||
131 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, | 131 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
132 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 132 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
133 | if (IS_ERR(keyring)) | 133 | if (IS_ERR(keyring)) |
134 | return PTR_ERR(keyring); | 134 | return PTR_ERR(keyring); |
135 | 135 | ||
136 | new->thread_keyring = keyring; | 136 | new->thread_keyring = keyring; |
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
139 | 139 | ||
140 | /* | 140 | /* |
141 | * install a fresh thread keyring, discarding the old one | 141 | * install a fresh thread keyring, discarding the old one |
142 | */ | 142 | */ |
143 | static int install_thread_keyring(void) | 143 | static int install_thread_keyring(void) |
144 | { | 144 | { |
145 | struct cred *new; | 145 | struct cred *new; |
146 | int ret; | 146 | int ret; |
147 | 147 | ||
148 | new = prepare_creds(); | 148 | new = prepare_creds(); |
149 | if (!new) | 149 | if (!new) |
150 | return -ENOMEM; | 150 | return -ENOMEM; |
151 | 151 | ||
152 | BUG_ON(new->thread_keyring); | 152 | BUG_ON(new->thread_keyring); |
153 | 153 | ||
154 | ret = install_thread_keyring_to_cred(new); | 154 | ret = install_thread_keyring_to_cred(new); |
155 | if (ret < 0) { | 155 | if (ret < 0) { |
156 | abort_creds(new); | 156 | abort_creds(new); |
157 | return ret; | 157 | return ret; |
158 | } | 158 | } |
159 | 159 | ||
160 | return commit_creds(new); | 160 | return commit_creds(new); |
161 | } | 161 | } |
162 | 162 | ||
163 | /* | 163 | /* |
164 | * install a process keyring directly to a credentials struct | 164 | * install a process keyring directly to a credentials struct |
165 | * - returns -EEXIST if there was already a process keyring, 0 if one installed, | 165 | * - returns -EEXIST if there was already a process keyring, 0 if one installed, |
166 | * and other -ve on any other error | 166 | * and other -ve on any other error |
167 | */ | 167 | */ |
168 | int install_process_keyring_to_cred(struct cred *new) | 168 | int install_process_keyring_to_cred(struct cred *new) |
169 | { | 169 | { |
170 | struct key *keyring; | 170 | struct key *keyring; |
171 | int ret; | 171 | int ret; |
172 | 172 | ||
173 | if (new->tgcred->process_keyring) | 173 | if (new->tgcred->process_keyring) |
174 | return -EEXIST; | 174 | return -EEXIST; |
175 | 175 | ||
176 | keyring = keyring_alloc("_pid", new->uid, new->gid, | 176 | keyring = keyring_alloc("_pid", new->uid, new->gid, |
177 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | 177 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); |
178 | if (IS_ERR(keyring)) | 178 | if (IS_ERR(keyring)) |
179 | return PTR_ERR(keyring); | 179 | return PTR_ERR(keyring); |
180 | 180 | ||
181 | spin_lock_irq(&new->tgcred->lock); | 181 | spin_lock_irq(&new->tgcred->lock); |
182 | if (!new->tgcred->process_keyring) { | 182 | if (!new->tgcred->process_keyring) { |
183 | new->tgcred->process_keyring = keyring; | 183 | new->tgcred->process_keyring = keyring; |
184 | keyring = NULL; | 184 | keyring = NULL; |
185 | ret = 0; | 185 | ret = 0; |
186 | } else { | 186 | } else { |
187 | ret = -EEXIST; | 187 | ret = -EEXIST; |
188 | } | 188 | } |
189 | spin_unlock_irq(&new->tgcred->lock); | 189 | spin_unlock_irq(&new->tgcred->lock); |
190 | key_put(keyring); | 190 | key_put(keyring); |
191 | return ret; | 191 | return ret; |
192 | } | 192 | } |
193 | 193 | ||
194 | /* | 194 | /* |
195 | * make sure a process keyring is installed | 195 | * make sure a process keyring is installed |
196 | * - we | 196 | * - we |
197 | */ | 197 | */ |
198 | static int install_process_keyring(void) | 198 | static int install_process_keyring(void) |
199 | { | 199 | { |
200 | struct cred *new; | 200 | struct cred *new; |
201 | int ret; | 201 | int ret; |
202 | 202 | ||
203 | new = prepare_creds(); | 203 | new = prepare_creds(); |
204 | if (!new) | 204 | if (!new) |
205 | return -ENOMEM; | 205 | return -ENOMEM; |
206 | 206 | ||
207 | ret = install_process_keyring_to_cred(new); | 207 | ret = install_process_keyring_to_cred(new); |
208 | if (ret < 0) { | 208 | if (ret < 0) { |
209 | abort_creds(new); | 209 | abort_creds(new); |
210 | return ret != -EEXIST ?: 0; | 210 | return ret != -EEXIST ? ret : 0; |
211 | } | 211 | } |
212 | 212 | ||
213 | return commit_creds(new); | 213 | return commit_creds(new); |
214 | } | 214 | } |
215 | 215 | ||
216 | /* | 216 | /* |
217 | * install a session keyring directly to a credentials struct | 217 | * install a session keyring directly to a credentials struct |
218 | */ | 218 | */ |
219 | int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) | 219 | int install_session_keyring_to_cred(struct cred *cred, struct key *keyring) |
220 | { | 220 | { |
221 | unsigned long flags; | 221 | unsigned long flags; |
222 | struct key *old; | 222 | struct key *old; |
223 | 223 | ||
224 | might_sleep(); | 224 | might_sleep(); |
225 | 225 | ||
226 | /* create an empty session keyring */ | 226 | /* create an empty session keyring */ |
227 | if (!keyring) { | 227 | if (!keyring) { |
228 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 228 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
229 | if (cred->tgcred->session_keyring) | 229 | if (cred->tgcred->session_keyring) |
230 | flags = KEY_ALLOC_IN_QUOTA; | 230 | flags = KEY_ALLOC_IN_QUOTA; |
231 | 231 | ||
232 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, | 232 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, |
233 | cred, flags, NULL); | 233 | cred, flags, NULL); |
234 | if (IS_ERR(keyring)) | 234 | if (IS_ERR(keyring)) |
235 | return PTR_ERR(keyring); | 235 | return PTR_ERR(keyring); |
236 | } else { | 236 | } else { |
237 | atomic_inc(&keyring->usage); | 237 | atomic_inc(&keyring->usage); |
238 | } | 238 | } |
239 | 239 | ||
240 | /* install the keyring */ | 240 | /* install the keyring */ |
241 | spin_lock_irq(&cred->tgcred->lock); | 241 | spin_lock_irq(&cred->tgcred->lock); |
242 | old = cred->tgcred->session_keyring; | 242 | old = cred->tgcred->session_keyring; |
243 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); | 243 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); |
244 | spin_unlock_irq(&cred->tgcred->lock); | 244 | spin_unlock_irq(&cred->tgcred->lock); |
245 | 245 | ||
246 | /* we're using RCU on the pointer, but there's no point synchronising | 246 | /* we're using RCU on the pointer, but there's no point synchronising |
247 | * on it if it didn't previously point to anything */ | 247 | * on it if it didn't previously point to anything */ |
248 | if (old) { | 248 | if (old) { |
249 | synchronize_rcu(); | 249 | synchronize_rcu(); |
250 | key_put(old); | 250 | key_put(old); |
251 | } | 251 | } |
252 | 252 | ||
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * install a session keyring, discarding the old one | 257 | * install a session keyring, discarding the old one |
258 | * - if a keyring is not supplied, an empty one is invented | 258 | * - if a keyring is not supplied, an empty one is invented |
259 | */ | 259 | */ |
260 | static int install_session_keyring(struct key *keyring) | 260 | static int install_session_keyring(struct key *keyring) |
261 | { | 261 | { |
262 | struct cred *new; | 262 | struct cred *new; |
263 | int ret; | 263 | int ret; |
264 | 264 | ||
265 | new = prepare_creds(); | 265 | new = prepare_creds(); |
266 | if (!new) | 266 | if (!new) |
267 | return -ENOMEM; | 267 | return -ENOMEM; |
268 | 268 | ||
269 | ret = install_session_keyring_to_cred(new, NULL); | 269 | ret = install_session_keyring_to_cred(new, NULL); |
270 | if (ret < 0) { | 270 | if (ret < 0) { |
271 | abort_creds(new); | 271 | abort_creds(new); |
272 | return ret; | 272 | return ret; |
273 | } | 273 | } |
274 | 274 | ||
275 | return commit_creds(new); | 275 | return commit_creds(new); |
276 | } | 276 | } |
277 | 277 | ||
278 | /*****************************************************************************/ | 278 | /*****************************************************************************/ |
279 | /* | 279 | /* |
280 | * the filesystem user ID changed | 280 | * the filesystem user ID changed |
281 | */ | 281 | */ |
282 | void key_fsuid_changed(struct task_struct *tsk) | 282 | void key_fsuid_changed(struct task_struct *tsk) |
283 | { | 283 | { |
284 | /* update the ownership of the thread keyring */ | 284 | /* update the ownership of the thread keyring */ |
285 | BUG_ON(!tsk->cred); | 285 | BUG_ON(!tsk->cred); |
286 | if (tsk->cred->thread_keyring) { | 286 | if (tsk->cred->thread_keyring) { |
287 | down_write(&tsk->cred->thread_keyring->sem); | 287 | down_write(&tsk->cred->thread_keyring->sem); |
288 | tsk->cred->thread_keyring->uid = tsk->cred->fsuid; | 288 | tsk->cred->thread_keyring->uid = tsk->cred->fsuid; |
289 | up_write(&tsk->cred->thread_keyring->sem); | 289 | up_write(&tsk->cred->thread_keyring->sem); |
290 | } | 290 | } |
291 | 291 | ||
292 | } /* end key_fsuid_changed() */ | 292 | } /* end key_fsuid_changed() */ |
293 | 293 | ||
294 | /*****************************************************************************/ | 294 | /*****************************************************************************/ |
295 | /* | 295 | /* |
296 | * the filesystem group ID changed | 296 | * the filesystem group ID changed |
297 | */ | 297 | */ |
298 | void key_fsgid_changed(struct task_struct *tsk) | 298 | void key_fsgid_changed(struct task_struct *tsk) |
299 | { | 299 | { |
300 | /* update the ownership of the thread keyring */ | 300 | /* update the ownership of the thread keyring */ |
301 | BUG_ON(!tsk->cred); | 301 | BUG_ON(!tsk->cred); |
302 | if (tsk->cred->thread_keyring) { | 302 | if (tsk->cred->thread_keyring) { |
303 | down_write(&tsk->cred->thread_keyring->sem); | 303 | down_write(&tsk->cred->thread_keyring->sem); |
304 | tsk->cred->thread_keyring->gid = tsk->cred->fsgid; | 304 | tsk->cred->thread_keyring->gid = tsk->cred->fsgid; |
305 | up_write(&tsk->cred->thread_keyring->sem); | 305 | up_write(&tsk->cred->thread_keyring->sem); |
306 | } | 306 | } |
307 | 307 | ||
308 | } /* end key_fsgid_changed() */ | 308 | } /* end key_fsgid_changed() */ |
309 | 309 | ||
310 | /*****************************************************************************/ | 310 | /*****************************************************************************/ |
311 | /* | 311 | /* |
312 | * search only my process keyrings for the first matching key | 312 | * search only my process keyrings for the first matching key |
313 | * - we use the supplied match function to see if the description (or other | 313 | * - we use the supplied match function to see if the description (or other |
314 | * feature of interest) matches | 314 | * feature of interest) matches |
315 | * - we return -EAGAIN if we didn't find any matching key | 315 | * - we return -EAGAIN if we didn't find any matching key |
316 | * - we return -ENOKEY if we found only negative matching keys | 316 | * - we return -ENOKEY if we found only negative matching keys |
317 | */ | 317 | */ |
318 | key_ref_t search_my_process_keyrings(struct key_type *type, | 318 | key_ref_t search_my_process_keyrings(struct key_type *type, |
319 | const void *description, | 319 | const void *description, |
320 | key_match_func_t match, | 320 | key_match_func_t match, |
321 | const struct cred *cred) | 321 | const struct cred *cred) |
322 | { | 322 | { |
323 | key_ref_t key_ref, ret, err; | 323 | key_ref_t key_ref, ret, err; |
324 | 324 | ||
325 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 325 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
326 | * searchable, but we failed to find a key or we found a negative key; | 326 | * searchable, but we failed to find a key or we found a negative key; |
327 | * otherwise we want to return a sample error (probably -EACCES) if | 327 | * otherwise we want to return a sample error (probably -EACCES) if |
328 | * none of the keyrings were searchable | 328 | * none of the keyrings were searchable |
329 | * | 329 | * |
330 | * in terms of priority: success > -ENOKEY > -EAGAIN > other error | 330 | * in terms of priority: success > -ENOKEY > -EAGAIN > other error |
331 | */ | 331 | */ |
332 | key_ref = NULL; | 332 | key_ref = NULL; |
333 | ret = NULL; | 333 | ret = NULL; |
334 | err = ERR_PTR(-EAGAIN); | 334 | err = ERR_PTR(-EAGAIN); |
335 | 335 | ||
336 | /* search the thread keyring first */ | 336 | /* search the thread keyring first */ |
337 | if (cred->thread_keyring) { | 337 | if (cred->thread_keyring) { |
338 | key_ref = keyring_search_aux( | 338 | key_ref = keyring_search_aux( |
339 | make_key_ref(cred->thread_keyring, 1), | 339 | make_key_ref(cred->thread_keyring, 1), |
340 | cred, type, description, match); | 340 | cred, type, description, match); |
341 | if (!IS_ERR(key_ref)) | 341 | if (!IS_ERR(key_ref)) |
342 | goto found; | 342 | goto found; |
343 | 343 | ||
344 | switch (PTR_ERR(key_ref)) { | 344 | switch (PTR_ERR(key_ref)) { |
345 | case -EAGAIN: /* no key */ | 345 | case -EAGAIN: /* no key */ |
346 | if (ret) | 346 | if (ret) |
347 | break; | 347 | break; |
348 | case -ENOKEY: /* negative key */ | 348 | case -ENOKEY: /* negative key */ |
349 | ret = key_ref; | 349 | ret = key_ref; |
350 | break; | 350 | break; |
351 | default: | 351 | default: |
352 | err = key_ref; | 352 | err = key_ref; |
353 | break; | 353 | break; |
354 | } | 354 | } |
355 | } | 355 | } |
356 | 356 | ||
357 | /* search the process keyring second */ | 357 | /* search the process keyring second */ |
358 | if (cred->tgcred->process_keyring) { | 358 | if (cred->tgcred->process_keyring) { |
359 | key_ref = keyring_search_aux( | 359 | key_ref = keyring_search_aux( |
360 | make_key_ref(cred->tgcred->process_keyring, 1), | 360 | make_key_ref(cred->tgcred->process_keyring, 1), |
361 | cred, type, description, match); | 361 | cred, type, description, match); |
362 | if (!IS_ERR(key_ref)) | 362 | if (!IS_ERR(key_ref)) |
363 | goto found; | 363 | goto found; |
364 | 364 | ||
365 | switch (PTR_ERR(key_ref)) { | 365 | switch (PTR_ERR(key_ref)) { |
366 | case -EAGAIN: /* no key */ | 366 | case -EAGAIN: /* no key */ |
367 | if (ret) | 367 | if (ret) |
368 | break; | 368 | break; |
369 | case -ENOKEY: /* negative key */ | 369 | case -ENOKEY: /* negative key */ |
370 | ret = key_ref; | 370 | ret = key_ref; |
371 | break; | 371 | break; |
372 | default: | 372 | default: |
373 | err = key_ref; | 373 | err = key_ref; |
374 | break; | 374 | break; |
375 | } | 375 | } |
376 | } | 376 | } |
377 | 377 | ||
378 | /* search the session keyring */ | 378 | /* search the session keyring */ |
379 | if (cred->tgcred->session_keyring) { | 379 | if (cred->tgcred->session_keyring) { |
380 | rcu_read_lock(); | 380 | rcu_read_lock(); |
381 | key_ref = keyring_search_aux( | 381 | key_ref = keyring_search_aux( |
382 | make_key_ref(rcu_dereference( | 382 | make_key_ref(rcu_dereference( |
383 | cred->tgcred->session_keyring), | 383 | cred->tgcred->session_keyring), |
384 | 1), | 384 | 1), |
385 | cred, type, description, match); | 385 | cred, type, description, match); |
386 | rcu_read_unlock(); | 386 | rcu_read_unlock(); |
387 | 387 | ||
388 | if (!IS_ERR(key_ref)) | 388 | if (!IS_ERR(key_ref)) |
389 | goto found; | 389 | goto found; |
390 | 390 | ||
391 | switch (PTR_ERR(key_ref)) { | 391 | switch (PTR_ERR(key_ref)) { |
392 | case -EAGAIN: /* no key */ | 392 | case -EAGAIN: /* no key */ |
393 | if (ret) | 393 | if (ret) |
394 | break; | 394 | break; |
395 | case -ENOKEY: /* negative key */ | 395 | case -ENOKEY: /* negative key */ |
396 | ret = key_ref; | 396 | ret = key_ref; |
397 | break; | 397 | break; |
398 | default: | 398 | default: |
399 | err = key_ref; | 399 | err = key_ref; |
400 | break; | 400 | break; |
401 | } | 401 | } |
402 | } | 402 | } |
403 | /* or search the user-session keyring */ | 403 | /* or search the user-session keyring */ |
404 | else if (cred->user->session_keyring) { | 404 | else if (cred->user->session_keyring) { |
405 | key_ref = keyring_search_aux( | 405 | key_ref = keyring_search_aux( |
406 | make_key_ref(cred->user->session_keyring, 1), | 406 | make_key_ref(cred->user->session_keyring, 1), |
407 | cred, type, description, match); | 407 | cred, type, description, match); |
408 | if (!IS_ERR(key_ref)) | 408 | if (!IS_ERR(key_ref)) |
409 | goto found; | 409 | goto found; |
410 | 410 | ||
411 | switch (PTR_ERR(key_ref)) { | 411 | switch (PTR_ERR(key_ref)) { |
412 | case -EAGAIN: /* no key */ | 412 | case -EAGAIN: /* no key */ |
413 | if (ret) | 413 | if (ret) |
414 | break; | 414 | break; |
415 | case -ENOKEY: /* negative key */ | 415 | case -ENOKEY: /* negative key */ |
416 | ret = key_ref; | 416 | ret = key_ref; |
417 | break; | 417 | break; |
418 | default: | 418 | default: |
419 | err = key_ref; | 419 | err = key_ref; |
420 | break; | 420 | break; |
421 | } | 421 | } |
422 | } | 422 | } |
423 | 423 | ||
424 | /* no key - decide on the error we're going to go for */ | 424 | /* no key - decide on the error we're going to go for */ |
425 | key_ref = ret ? ret : err; | 425 | key_ref = ret ? ret : err; |
426 | 426 | ||
427 | found: | 427 | found: |
428 | return key_ref; | 428 | return key_ref; |
429 | } | 429 | } |
430 | 430 | ||
431 | /*****************************************************************************/ | 431 | /*****************************************************************************/ |
432 | /* | 432 | /* |
433 | * search the process keyrings for the first matching key | 433 | * search the process keyrings for the first matching key |
434 | * - we use the supplied match function to see if the description (or other | 434 | * - we use the supplied match function to see if the description (or other |
435 | * feature of interest) matches | 435 | * feature of interest) matches |
436 | * - we return -EAGAIN if we didn't find any matching key | 436 | * - we return -EAGAIN if we didn't find any matching key |
437 | * - we return -ENOKEY if we found only negative matching keys | 437 | * - we return -ENOKEY if we found only negative matching keys |
438 | */ | 438 | */ |
439 | key_ref_t search_process_keyrings(struct key_type *type, | 439 | key_ref_t search_process_keyrings(struct key_type *type, |
440 | const void *description, | 440 | const void *description, |
441 | key_match_func_t match, | 441 | key_match_func_t match, |
442 | const struct cred *cred) | 442 | const struct cred *cred) |
443 | { | 443 | { |
444 | struct request_key_auth *rka; | 444 | struct request_key_auth *rka; |
445 | key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; | 445 | key_ref_t key_ref, ret = ERR_PTR(-EACCES), err; |
446 | 446 | ||
447 | might_sleep(); | 447 | might_sleep(); |
448 | 448 | ||
449 | key_ref = search_my_process_keyrings(type, description, match, cred); | 449 | key_ref = search_my_process_keyrings(type, description, match, cred); |
450 | if (!IS_ERR(key_ref)) | 450 | if (!IS_ERR(key_ref)) |
451 | goto found; | 451 | goto found; |
452 | err = key_ref; | 452 | err = key_ref; |
453 | 453 | ||
454 | /* if this process has an instantiation authorisation key, then we also | 454 | /* if this process has an instantiation authorisation key, then we also |
455 | * search the keyrings of the process mentioned there | 455 | * search the keyrings of the process mentioned there |
456 | * - we don't permit access to request_key auth keys via this method | 456 | * - we don't permit access to request_key auth keys via this method |
457 | */ | 457 | */ |
458 | if (cred->request_key_auth && | 458 | if (cred->request_key_auth && |
459 | cred == current_cred() && | 459 | cred == current_cred() && |
460 | type != &key_type_request_key_auth | 460 | type != &key_type_request_key_auth |
461 | ) { | 461 | ) { |
462 | /* defend against the auth key being revoked */ | 462 | /* defend against the auth key being revoked */ |
463 | down_read(&cred->request_key_auth->sem); | 463 | down_read(&cred->request_key_auth->sem); |
464 | 464 | ||
465 | if (key_validate(cred->request_key_auth) == 0) { | 465 | if (key_validate(cred->request_key_auth) == 0) { |
466 | rka = cred->request_key_auth->payload.data; | 466 | rka = cred->request_key_auth->payload.data; |
467 | 467 | ||
468 | key_ref = search_process_keyrings(type, description, | 468 | key_ref = search_process_keyrings(type, description, |
469 | match, rka->cred); | 469 | match, rka->cred); |
470 | 470 | ||
471 | up_read(&cred->request_key_auth->sem); | 471 | up_read(&cred->request_key_auth->sem); |
472 | 472 | ||
473 | if (!IS_ERR(key_ref)) | 473 | if (!IS_ERR(key_ref)) |
474 | goto found; | 474 | goto found; |
475 | 475 | ||
476 | ret = key_ref; | 476 | ret = key_ref; |
477 | } else { | 477 | } else { |
478 | up_read(&cred->request_key_auth->sem); | 478 | up_read(&cred->request_key_auth->sem); |
479 | } | 479 | } |
480 | } | 480 | } |
481 | 481 | ||
482 | /* no key - decide on the error we're going to go for */ | 482 | /* no key - decide on the error we're going to go for */ |
483 | if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) | 483 | if (err == ERR_PTR(-ENOKEY) || ret == ERR_PTR(-ENOKEY)) |
484 | key_ref = ERR_PTR(-ENOKEY); | 484 | key_ref = ERR_PTR(-ENOKEY); |
485 | else if (err == ERR_PTR(-EACCES)) | 485 | else if (err == ERR_PTR(-EACCES)) |
486 | key_ref = ret; | 486 | key_ref = ret; |
487 | else | 487 | else |
488 | key_ref = err; | 488 | key_ref = err; |
489 | 489 | ||
490 | found: | 490 | found: |
491 | return key_ref; | 491 | return key_ref; |
492 | 492 | ||
493 | } /* end search_process_keyrings() */ | 493 | } /* end search_process_keyrings() */ |
494 | 494 | ||
495 | /*****************************************************************************/ | 495 | /*****************************************************************************/ |
496 | /* | 496 | /* |
497 | * see if the key we're looking at is the target key | 497 | * see if the key we're looking at is the target key |
498 | */ | 498 | */ |
499 | int lookup_user_key_possessed(const struct key *key, const void *target) | 499 | int lookup_user_key_possessed(const struct key *key, const void *target) |
500 | { | 500 | { |
501 | return key == target; | 501 | return key == target; |
502 | 502 | ||
503 | } /* end lookup_user_key_possessed() */ | 503 | } /* end lookup_user_key_possessed() */ |
504 | 504 | ||
505 | /*****************************************************************************/ | 505 | /*****************************************************************************/ |
506 | /* | 506 | /* |
507 | * lookup a key given a key ID from userspace with a given permissions mask | 507 | * lookup a key given a key ID from userspace with a given permissions mask |
508 | * - don't create special keyrings unless so requested | 508 | * - don't create special keyrings unless so requested |
509 | * - partially constructed keys aren't found unless requested | 509 | * - partially constructed keys aren't found unless requested |
510 | */ | 510 | */ |
511 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, | 511 | key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, |
512 | key_perm_t perm) | 512 | key_perm_t perm) |
513 | { | 513 | { |
514 | struct request_key_auth *rka; | 514 | struct request_key_auth *rka; |
515 | const struct cred *cred; | 515 | const struct cred *cred; |
516 | struct key *key; | 516 | struct key *key; |
517 | key_ref_t key_ref, skey_ref; | 517 | key_ref_t key_ref, skey_ref; |
518 | int ret; | 518 | int ret; |
519 | 519 | ||
520 | try_again: | 520 | try_again: |
521 | cred = get_current_cred(); | 521 | cred = get_current_cred(); |
522 | key_ref = ERR_PTR(-ENOKEY); | 522 | key_ref = ERR_PTR(-ENOKEY); |
523 | 523 | ||
524 | switch (id) { | 524 | switch (id) { |
525 | case KEY_SPEC_THREAD_KEYRING: | 525 | case KEY_SPEC_THREAD_KEYRING: |
526 | if (!cred->thread_keyring) { | 526 | if (!cred->thread_keyring) { |
527 | if (!(lflags & KEY_LOOKUP_CREATE)) | 527 | if (!(lflags & KEY_LOOKUP_CREATE)) |
528 | goto error; | 528 | goto error; |
529 | 529 | ||
530 | ret = install_thread_keyring(); | 530 | ret = install_thread_keyring(); |
531 | if (ret < 0) { | 531 | if (ret < 0) { |
532 | key_ref = ERR_PTR(ret); | 532 | key_ref = ERR_PTR(ret); |
533 | goto error; | 533 | goto error; |
534 | } | 534 | } |
535 | goto reget_creds; | 535 | goto reget_creds; |
536 | } | 536 | } |
537 | 537 | ||
538 | key = cred->thread_keyring; | 538 | key = cred->thread_keyring; |
539 | atomic_inc(&key->usage); | 539 | atomic_inc(&key->usage); |
540 | key_ref = make_key_ref(key, 1); | 540 | key_ref = make_key_ref(key, 1); |
541 | break; | 541 | break; |
542 | 542 | ||
543 | case KEY_SPEC_PROCESS_KEYRING: | 543 | case KEY_SPEC_PROCESS_KEYRING: |
544 | if (!cred->tgcred->process_keyring) { | 544 | if (!cred->tgcred->process_keyring) { |
545 | if (!(lflags & KEY_LOOKUP_CREATE)) | 545 | if (!(lflags & KEY_LOOKUP_CREATE)) |
546 | goto error; | 546 | goto error; |
547 | 547 | ||
548 | ret = install_process_keyring(); | 548 | ret = install_process_keyring(); |
549 | if (ret < 0) { | 549 | if (ret < 0) { |
550 | key_ref = ERR_PTR(ret); | 550 | key_ref = ERR_PTR(ret); |
551 | goto error; | 551 | goto error; |
552 | } | 552 | } |
553 | goto reget_creds; | 553 | goto reget_creds; |
554 | } | 554 | } |
555 | 555 | ||
556 | key = cred->tgcred->process_keyring; | 556 | key = cred->tgcred->process_keyring; |
557 | atomic_inc(&key->usage); | 557 | atomic_inc(&key->usage); |
558 | key_ref = make_key_ref(key, 1); | 558 | key_ref = make_key_ref(key, 1); |
559 | break; | 559 | break; |
560 | 560 | ||
561 | case KEY_SPEC_SESSION_KEYRING: | 561 | case KEY_SPEC_SESSION_KEYRING: |
562 | if (!cred->tgcred->session_keyring) { | 562 | if (!cred->tgcred->session_keyring) { |
563 | /* always install a session keyring upon access if one | 563 | /* always install a session keyring upon access if one |
564 | * doesn't exist yet */ | 564 | * doesn't exist yet */ |
565 | ret = install_user_keyrings(); | 565 | ret = install_user_keyrings(); |
566 | if (ret < 0) | 566 | if (ret < 0) |
567 | goto error; | 567 | goto error; |
568 | ret = install_session_keyring( | 568 | ret = install_session_keyring( |
569 | cred->user->session_keyring); | 569 | cred->user->session_keyring); |
570 | 570 | ||
571 | if (ret < 0) | 571 | if (ret < 0) |
572 | goto error; | 572 | goto error; |
573 | goto reget_creds; | 573 | goto reget_creds; |
574 | } | 574 | } |
575 | 575 | ||
576 | rcu_read_lock(); | 576 | rcu_read_lock(); |
577 | key = rcu_dereference(cred->tgcred->session_keyring); | 577 | key = rcu_dereference(cred->tgcred->session_keyring); |
578 | atomic_inc(&key->usage); | 578 | atomic_inc(&key->usage); |
579 | rcu_read_unlock(); | 579 | rcu_read_unlock(); |
580 | key_ref = make_key_ref(key, 1); | 580 | key_ref = make_key_ref(key, 1); |
581 | break; | 581 | break; |
582 | 582 | ||
583 | case KEY_SPEC_USER_KEYRING: | 583 | case KEY_SPEC_USER_KEYRING: |
584 | if (!cred->user->uid_keyring) { | 584 | if (!cred->user->uid_keyring) { |
585 | ret = install_user_keyrings(); | 585 | ret = install_user_keyrings(); |
586 | if (ret < 0) | 586 | if (ret < 0) |
587 | goto error; | 587 | goto error; |
588 | } | 588 | } |
589 | 589 | ||
590 | key = cred->user->uid_keyring; | 590 | key = cred->user->uid_keyring; |
591 | atomic_inc(&key->usage); | 591 | atomic_inc(&key->usage); |
592 | key_ref = make_key_ref(key, 1); | 592 | key_ref = make_key_ref(key, 1); |
593 | break; | 593 | break; |
594 | 594 | ||
595 | case KEY_SPEC_USER_SESSION_KEYRING: | 595 | case KEY_SPEC_USER_SESSION_KEYRING: |
596 | if (!cred->user->session_keyring) { | 596 | if (!cred->user->session_keyring) { |
597 | ret = install_user_keyrings(); | 597 | ret = install_user_keyrings(); |
598 | if (ret < 0) | 598 | if (ret < 0) |
599 | goto error; | 599 | goto error; |
600 | } | 600 | } |
601 | 601 | ||
602 | key = cred->user->session_keyring; | 602 | key = cred->user->session_keyring; |
603 | atomic_inc(&key->usage); | 603 | atomic_inc(&key->usage); |
604 | key_ref = make_key_ref(key, 1); | 604 | key_ref = make_key_ref(key, 1); |
605 | break; | 605 | break; |
606 | 606 | ||
607 | case KEY_SPEC_GROUP_KEYRING: | 607 | case KEY_SPEC_GROUP_KEYRING: |
608 | /* group keyrings are not yet supported */ | 608 | /* group keyrings are not yet supported */ |
609 | key_ref = ERR_PTR(-EINVAL); | 609 | key_ref = ERR_PTR(-EINVAL); |
610 | goto error; | 610 | goto error; |
611 | 611 | ||
612 | case KEY_SPEC_REQKEY_AUTH_KEY: | 612 | case KEY_SPEC_REQKEY_AUTH_KEY: |
613 | key = cred->request_key_auth; | 613 | key = cred->request_key_auth; |
614 | if (!key) | 614 | if (!key) |
615 | goto error; | 615 | goto error; |
616 | 616 | ||
617 | atomic_inc(&key->usage); | 617 | atomic_inc(&key->usage); |
618 | key_ref = make_key_ref(key, 1); | 618 | key_ref = make_key_ref(key, 1); |
619 | break; | 619 | break; |
620 | 620 | ||
621 | case KEY_SPEC_REQUESTOR_KEYRING: | 621 | case KEY_SPEC_REQUESTOR_KEYRING: |
622 | if (!cred->request_key_auth) | 622 | if (!cred->request_key_auth) |
623 | goto error; | 623 | goto error; |
624 | 624 | ||
625 | down_read(&cred->request_key_auth->sem); | 625 | down_read(&cred->request_key_auth->sem); |
626 | if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { | 626 | if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { |
627 | key_ref = ERR_PTR(-EKEYREVOKED); | 627 | key_ref = ERR_PTR(-EKEYREVOKED); |
628 | key = NULL; | 628 | key = NULL; |
629 | } else { | 629 | } else { |
630 | rka = cred->request_key_auth->payload.data; | 630 | rka = cred->request_key_auth->payload.data; |
631 | key = rka->dest_keyring; | 631 | key = rka->dest_keyring; |
632 | atomic_inc(&key->usage); | 632 | atomic_inc(&key->usage); |
633 | } | 633 | } |
634 | up_read(&cred->request_key_auth->sem); | 634 | up_read(&cred->request_key_auth->sem); |
635 | if (!key) | 635 | if (!key) |
636 | goto error; | 636 | goto error; |
637 | key_ref = make_key_ref(key, 1); | 637 | key_ref = make_key_ref(key, 1); |
638 | break; | 638 | break; |
639 | 639 | ||
640 | default: | 640 | default: |
641 | key_ref = ERR_PTR(-EINVAL); | 641 | key_ref = ERR_PTR(-EINVAL); |
642 | if (id < 1) | 642 | if (id < 1) |
643 | goto error; | 643 | goto error; |
644 | 644 | ||
645 | key = key_lookup(id); | 645 | key = key_lookup(id); |
646 | if (IS_ERR(key)) { | 646 | if (IS_ERR(key)) { |
647 | key_ref = ERR_CAST(key); | 647 | key_ref = ERR_CAST(key); |
648 | goto error; | 648 | goto error; |
649 | } | 649 | } |
650 | 650 | ||
651 | key_ref = make_key_ref(key, 0); | 651 | key_ref = make_key_ref(key, 0); |
652 | 652 | ||
653 | /* check to see if we possess the key */ | 653 | /* check to see if we possess the key */ |
654 | skey_ref = search_process_keyrings(key->type, key, | 654 | skey_ref = search_process_keyrings(key->type, key, |
655 | lookup_user_key_possessed, | 655 | lookup_user_key_possessed, |
656 | cred); | 656 | cred); |
657 | 657 | ||
658 | if (!IS_ERR(skey_ref)) { | 658 | if (!IS_ERR(skey_ref)) { |
659 | key_put(key); | 659 | key_put(key); |
660 | key_ref = skey_ref; | 660 | key_ref = skey_ref; |
661 | } | 661 | } |
662 | 662 | ||
663 | break; | 663 | break; |
664 | } | 664 | } |
665 | 665 | ||
666 | /* unlink does not use the nominated key in any way, so can skip all | 666 | /* unlink does not use the nominated key in any way, so can skip all |
667 | * the permission checks as it is only concerned with the keyring */ | 667 | * the permission checks as it is only concerned with the keyring */ |
668 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { | 668 | if (lflags & KEY_LOOKUP_FOR_UNLINK) { |
669 | ret = 0; | 669 | ret = 0; |
670 | goto error; | 670 | goto error; |
671 | } | 671 | } |
672 | 672 | ||
673 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { | 673 | if (!(lflags & KEY_LOOKUP_PARTIAL)) { |
674 | ret = wait_for_key_construction(key, true); | 674 | ret = wait_for_key_construction(key, true); |
675 | switch (ret) { | 675 | switch (ret) { |
676 | case -ERESTARTSYS: | 676 | case -ERESTARTSYS: |
677 | goto invalid_key; | 677 | goto invalid_key; |
678 | default: | 678 | default: |
679 | if (perm) | 679 | if (perm) |
680 | goto invalid_key; | 680 | goto invalid_key; |
681 | case 0: | 681 | case 0: |
682 | break; | 682 | break; |
683 | } | 683 | } |
684 | } else if (perm) { | 684 | } else if (perm) { |
685 | ret = key_validate(key); | 685 | ret = key_validate(key); |
686 | if (ret < 0) | 686 | if (ret < 0) |
687 | goto invalid_key; | 687 | goto invalid_key; |
688 | } | 688 | } |
689 | 689 | ||
690 | ret = -EIO; | 690 | ret = -EIO; |
691 | if (!(lflags & KEY_LOOKUP_PARTIAL) && | 691 | if (!(lflags & KEY_LOOKUP_PARTIAL) && |
692 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 692 | !test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
693 | goto invalid_key; | 693 | goto invalid_key; |
694 | 694 | ||
695 | /* check the permissions */ | 695 | /* check the permissions */ |
696 | ret = key_task_permission(key_ref, cred, perm); | 696 | ret = key_task_permission(key_ref, cred, perm); |
697 | if (ret < 0) | 697 | if (ret < 0) |
698 | goto invalid_key; | 698 | goto invalid_key; |
699 | 699 | ||
700 | error: | 700 | error: |
701 | put_cred(cred); | 701 | put_cred(cred); |
702 | return key_ref; | 702 | return key_ref; |
703 | 703 | ||
704 | invalid_key: | 704 | invalid_key: |
705 | key_ref_put(key_ref); | 705 | key_ref_put(key_ref); |
706 | key_ref = ERR_PTR(ret); | 706 | key_ref = ERR_PTR(ret); |
707 | goto error; | 707 | goto error; |
708 | 708 | ||
709 | /* if we attempted to install a keyring, then it may have caused new | 709 | /* if we attempted to install a keyring, then it may have caused new |
710 | * creds to be installed */ | 710 | * creds to be installed */ |
711 | reget_creds: | 711 | reget_creds: |
712 | put_cred(cred); | 712 | put_cred(cred); |
713 | goto try_again; | 713 | goto try_again; |
714 | 714 | ||
715 | } /* end lookup_user_key() */ | 715 | } /* end lookup_user_key() */ |
716 | 716 | ||
717 | /*****************************************************************************/ | 717 | /*****************************************************************************/ |
718 | /* | 718 | /* |
719 | * join the named keyring as the session keyring if possible, or attempt to | 719 | * join the named keyring as the session keyring if possible, or attempt to |
720 | * create a new one of that name if not | 720 | * create a new one of that name if not |
721 | * - if the name is NULL, an empty anonymous keyring is installed instead | 721 | * - if the name is NULL, an empty anonymous keyring is installed instead |
722 | * - named session keyring joining is done with a semaphore held | 722 | * - named session keyring joining is done with a semaphore held |
723 | */ | 723 | */ |
724 | long join_session_keyring(const char *name) | 724 | long join_session_keyring(const char *name) |
725 | { | 725 | { |
726 | const struct cred *old; | 726 | const struct cred *old; |
727 | struct cred *new; | 727 | struct cred *new; |
728 | struct key *keyring; | 728 | struct key *keyring; |
729 | long ret, serial; | 729 | long ret, serial; |
730 | 730 | ||
731 | /* only permit this if there's a single thread in the thread group - | 731 | /* only permit this if there's a single thread in the thread group - |
732 | * this avoids us having to adjust the creds on all threads and risking | 732 | * this avoids us having to adjust the creds on all threads and risking |
733 | * ENOMEM */ | 733 | * ENOMEM */ |
734 | if (!current_is_single_threaded()) | 734 | if (!current_is_single_threaded()) |
735 | return -EMLINK; | 735 | return -EMLINK; |
736 | 736 | ||
737 | new = prepare_creds(); | 737 | new = prepare_creds(); |
738 | if (!new) | 738 | if (!new) |
739 | return -ENOMEM; | 739 | return -ENOMEM; |
740 | old = current_cred(); | 740 | old = current_cred(); |
741 | 741 | ||
742 | /* if no name is provided, install an anonymous keyring */ | 742 | /* if no name is provided, install an anonymous keyring */ |
743 | if (!name) { | 743 | if (!name) { |
744 | ret = install_session_keyring_to_cred(new, NULL); | 744 | ret = install_session_keyring_to_cred(new, NULL); |
745 | if (ret < 0) | 745 | if (ret < 0) |
746 | goto error; | 746 | goto error; |
747 | 747 | ||
748 | serial = new->tgcred->session_keyring->serial; | 748 | serial = new->tgcred->session_keyring->serial; |
749 | ret = commit_creds(new); | 749 | ret = commit_creds(new); |
750 | if (ret == 0) | 750 | if (ret == 0) |
751 | ret = serial; | 751 | ret = serial; |
752 | goto okay; | 752 | goto okay; |
753 | } | 753 | } |
754 | 754 | ||
755 | /* allow the user to join or create a named keyring */ | 755 | /* allow the user to join or create a named keyring */ |
756 | mutex_lock(&key_session_mutex); | 756 | mutex_lock(&key_session_mutex); |
757 | 757 | ||
758 | /* look for an existing keyring of this name */ | 758 | /* look for an existing keyring of this name */ |
759 | keyring = find_keyring_by_name(name, false); | 759 | keyring = find_keyring_by_name(name, false); |
760 | if (PTR_ERR(keyring) == -ENOKEY) { | 760 | if (PTR_ERR(keyring) == -ENOKEY) { |
761 | /* not found - try and create a new one */ | 761 | /* not found - try and create a new one */ |
762 | keyring = keyring_alloc(name, old->uid, old->gid, old, | 762 | keyring = keyring_alloc(name, old->uid, old->gid, old, |
763 | KEY_ALLOC_IN_QUOTA, NULL); | 763 | KEY_ALLOC_IN_QUOTA, NULL); |
764 | if (IS_ERR(keyring)) { | 764 | if (IS_ERR(keyring)) { |
765 | ret = PTR_ERR(keyring); | 765 | ret = PTR_ERR(keyring); |
766 | goto error2; | 766 | goto error2; |
767 | } | 767 | } |
768 | } else if (IS_ERR(keyring)) { | 768 | } else if (IS_ERR(keyring)) { |
769 | ret = PTR_ERR(keyring); | 769 | ret = PTR_ERR(keyring); |
770 | goto error2; | 770 | goto error2; |
771 | } | 771 | } |
772 | 772 | ||
773 | /* we've got a keyring - now to install it */ | 773 | /* we've got a keyring - now to install it */ |
774 | ret = install_session_keyring_to_cred(new, keyring); | 774 | ret = install_session_keyring_to_cred(new, keyring); |
775 | if (ret < 0) | 775 | if (ret < 0) |
776 | goto error2; | 776 | goto error2; |
777 | 777 | ||
778 | commit_creds(new); | 778 | commit_creds(new); |
779 | mutex_unlock(&key_session_mutex); | 779 | mutex_unlock(&key_session_mutex); |
780 | 780 | ||
781 | ret = keyring->serial; | 781 | ret = keyring->serial; |
782 | key_put(keyring); | 782 | key_put(keyring); |
783 | okay: | 783 | okay: |
784 | return ret; | 784 | return ret; |
785 | 785 | ||
786 | error2: | 786 | error2: |
787 | mutex_unlock(&key_session_mutex); | 787 | mutex_unlock(&key_session_mutex); |
788 | error: | 788 | error: |
789 | abort_creds(new); | 789 | abort_creds(new); |
790 | return ret; | 790 | return ret; |
791 | } | 791 | } |
792 | 792 | ||
793 | /* | 793 | /* |
794 | * Replace a process's session keyring when that process resumes userspace on | 794 | * Replace a process's session keyring when that process resumes userspace on |
795 | * behalf of one of its children | 795 | * behalf of one of its children |
796 | */ | 796 | */ |
797 | void key_replace_session_keyring(void) | 797 | void key_replace_session_keyring(void) |
798 | { | 798 | { |
799 | const struct cred *old; | 799 | const struct cred *old; |
800 | struct cred *new; | 800 | struct cred *new; |
801 | 801 | ||
802 | if (!current->replacement_session_keyring) | 802 | if (!current->replacement_session_keyring) |
803 | return; | 803 | return; |
804 | 804 | ||
805 | write_lock_irq(&tasklist_lock); | 805 | write_lock_irq(&tasklist_lock); |
806 | new = current->replacement_session_keyring; | 806 | new = current->replacement_session_keyring; |
807 | current->replacement_session_keyring = NULL; | 807 | current->replacement_session_keyring = NULL; |
808 | write_unlock_irq(&tasklist_lock); | 808 | write_unlock_irq(&tasklist_lock); |
809 | 809 | ||
810 | if (!new) | 810 | if (!new) |
811 | return; | 811 | return; |
812 | 812 | ||
813 | old = current_cred(); | 813 | old = current_cred(); |
814 | new-> uid = old-> uid; | 814 | new-> uid = old-> uid; |
815 | new-> euid = old-> euid; | 815 | new-> euid = old-> euid; |
816 | new-> suid = old-> suid; | 816 | new-> suid = old-> suid; |
817 | new->fsuid = old->fsuid; | 817 | new->fsuid = old->fsuid; |
818 | new-> gid = old-> gid; | 818 | new-> gid = old-> gid; |
819 | new-> egid = old-> egid; | 819 | new-> egid = old-> egid; |
820 | new-> sgid = old-> sgid; | 820 | new-> sgid = old-> sgid; |
821 | new->fsgid = old->fsgid; | 821 | new->fsgid = old->fsgid; |
822 | new->user = get_uid(old->user); | 822 | new->user = get_uid(old->user); |
823 | new->group_info = get_group_info(old->group_info); | 823 | new->group_info = get_group_info(old->group_info); |
824 | 824 | ||
825 | new->securebits = old->securebits; | 825 | new->securebits = old->securebits; |
826 | new->cap_inheritable = old->cap_inheritable; | 826 | new->cap_inheritable = old->cap_inheritable; |
827 | new->cap_permitted = old->cap_permitted; | 827 | new->cap_permitted = old->cap_permitted; |
828 | new->cap_effective = old->cap_effective; | 828 | new->cap_effective = old->cap_effective; |
829 | new->cap_bset = old->cap_bset; | 829 | new->cap_bset = old->cap_bset; |
830 | 830 | ||
831 | new->jit_keyring = old->jit_keyring; | 831 | new->jit_keyring = old->jit_keyring; |
832 | new->thread_keyring = key_get(old->thread_keyring); | 832 | new->thread_keyring = key_get(old->thread_keyring); |
833 | new->tgcred->tgid = old->tgcred->tgid; | 833 | new->tgcred->tgid = old->tgcred->tgid; |
834 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); | 834 | new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); |
835 | 835 | ||
836 | security_transfer_creds(new, old); | 836 | security_transfer_creds(new, old); |
837 | 837 | ||
838 | commit_creds(new); | 838 | commit_creds(new); |
839 | } | 839 | } |
840 | 840 |