diff options
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 333 |
1 files changed, 164 insertions, 169 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 70ee93406f30..df329f684a65 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -42,11 +42,15 @@ struct key_user root_key_user = { | |||
42 | */ | 42 | */ |
43 | int install_user_keyrings(void) | 43 | int install_user_keyrings(void) |
44 | { | 44 | { |
45 | struct user_struct *user = current->cred->user; | 45 | struct user_struct *user; |
46 | const struct cred *cred; | ||
46 | struct key *uid_keyring, *session_keyring; | 47 | struct key *uid_keyring, *session_keyring; |
47 | char buf[20]; | 48 | char buf[20]; |
48 | int ret; | 49 | int ret; |
49 | 50 | ||
51 | cred = current_cred(); | ||
52 | user = cred->user; | ||
53 | |||
50 | kenter("%p{%u}", user, user->uid); | 54 | kenter("%p{%u}", user, user->uid); |
51 | 55 | ||
52 | if (user->uid_keyring) { | 56 | if (user->uid_keyring) { |
@@ -67,7 +71,7 @@ int install_user_keyrings(void) | |||
67 | uid_keyring = find_keyring_by_name(buf, true); | 71 | uid_keyring = find_keyring_by_name(buf, true); |
68 | if (IS_ERR(uid_keyring)) { | 72 | if (IS_ERR(uid_keyring)) { |
69 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, | 73 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, |
70 | current, KEY_ALLOC_IN_QUOTA, | 74 | cred, KEY_ALLOC_IN_QUOTA, |
71 | NULL); | 75 | NULL); |
72 | if (IS_ERR(uid_keyring)) { | 76 | if (IS_ERR(uid_keyring)) { |
73 | ret = PTR_ERR(uid_keyring); | 77 | ret = PTR_ERR(uid_keyring); |
@@ -83,8 +87,7 @@ int install_user_keyrings(void) | |||
83 | if (IS_ERR(session_keyring)) { | 87 | if (IS_ERR(session_keyring)) { |
84 | session_keyring = | 88 | session_keyring = |
85 | keyring_alloc(buf, user->uid, (gid_t) -1, | 89 | keyring_alloc(buf, user->uid, (gid_t) -1, |
86 | current, KEY_ALLOC_IN_QUOTA, | 90 | cred, KEY_ALLOC_IN_QUOTA, NULL); |
87 | NULL); | ||
88 | if (IS_ERR(session_keyring)) { | 91 | if (IS_ERR(session_keyring)) { |
89 | ret = PTR_ERR(session_keyring); | 92 | ret = PTR_ERR(session_keyring); |
90 | goto error_release; | 93 | goto error_release; |
@@ -116,142 +119,128 @@ error: | |||
116 | return ret; | 119 | return ret; |
117 | } | 120 | } |
118 | 121 | ||
119 | /*****************************************************************************/ | ||
120 | /* | 122 | /* |
121 | * deal with the UID changing | 123 | * install a fresh thread keyring directly to new credentials |
122 | */ | 124 | */ |
123 | void switch_uid_keyring(struct user_struct *new_user) | 125 | int install_thread_keyring_to_cred(struct cred *new) |
124 | { | 126 | { |
125 | #if 0 /* do nothing for now */ | 127 | struct key *keyring; |
126 | struct key *old; | ||
127 | |||
128 | /* switch to the new user's session keyring if we were running under | ||
129 | * root's default session keyring */ | ||
130 | if (new_user->uid != 0 && | ||
131 | current->session_keyring == &root_session_keyring | ||
132 | ) { | ||
133 | atomic_inc(&new_user->session_keyring->usage); | ||
134 | |||
135 | task_lock(current); | ||
136 | old = current->session_keyring; | ||
137 | current->session_keyring = new_user->session_keyring; | ||
138 | task_unlock(current); | ||
139 | 128 | ||
140 | key_put(old); | 129 | keyring = keyring_alloc("_tid", new->uid, new->gid, new, |
141 | } | 130 | KEY_ALLOC_QUOTA_OVERRUN, NULL); |
142 | #endif | 131 | if (IS_ERR(keyring)) |
132 | return PTR_ERR(keyring); | ||
143 | 133 | ||
144 | } /* end switch_uid_keyring() */ | 134 | new->thread_keyring = keyring; |
135 | return 0; | ||
136 | } | ||
145 | 137 | ||
146 | /*****************************************************************************/ | ||
147 | /* | 138 | /* |
148 | * install a fresh thread keyring, discarding the old one | 139 | * install a fresh thread keyring, discarding the old one |
149 | */ | 140 | */ |
150 | int install_thread_keyring(void) | 141 | static int install_thread_keyring(void) |
151 | { | 142 | { |
152 | struct task_struct *tsk = current; | 143 | struct cred *new; |
153 | struct key *keyring, *old; | ||
154 | char buf[20]; | ||
155 | int ret; | 144 | int ret; |
156 | 145 | ||
157 | sprintf(buf, "_tid.%u", tsk->pid); | 146 | new = prepare_creds(); |
147 | if (!new) | ||
148 | return -ENOMEM; | ||
158 | 149 | ||
159 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | 150 | BUG_ON(new->thread_keyring); |
160 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | 151 | |
161 | if (IS_ERR(keyring)) { | 152 | ret = install_thread_keyring_to_cred(new); |
162 | ret = PTR_ERR(keyring); | 153 | if (ret < 0) { |
163 | goto error; | 154 | abort_creds(new); |
155 | return ret; | ||
164 | } | 156 | } |
165 | 157 | ||
166 | task_lock(tsk); | 158 | return commit_creds(new); |
167 | old = tsk->cred->thread_keyring; | 159 | } |
168 | tsk->cred->thread_keyring = keyring; | ||
169 | task_unlock(tsk); | ||
170 | 160 | ||
171 | ret = 0; | 161 | /* |
162 | * install a process keyring directly to a credentials struct | ||
163 | * - returns -EEXIST if there was already a process keyring, 0 if one installed, | ||
164 | * and other -ve on any other error | ||
165 | */ | ||
166 | int install_process_keyring_to_cred(struct cred *new) | ||
167 | { | ||
168 | struct key *keyring; | ||
169 | int ret; | ||
172 | 170 | ||
173 | key_put(old); | 171 | if (new->tgcred->process_keyring) |
174 | error: | 172 | return -EEXIST; |
173 | |||
174 | keyring = keyring_alloc("_pid", new->uid, new->gid, | ||
175 | new, KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
176 | if (IS_ERR(keyring)) | ||
177 | return PTR_ERR(keyring); | ||
178 | |||
179 | spin_lock_irq(&new->tgcred->lock); | ||
180 | if (!new->tgcred->process_keyring) { | ||
181 | new->tgcred->process_keyring = keyring; | ||
182 | keyring = NULL; | ||
183 | ret = 0; | ||
184 | } else { | ||
185 | ret = -EEXIST; | ||
186 | } | ||
187 | spin_unlock_irq(&new->tgcred->lock); | ||
188 | key_put(keyring); | ||
175 | return ret; | 189 | return ret; |
190 | } | ||
176 | 191 | ||
177 | } /* end install_thread_keyring() */ | ||
178 | |||
179 | /*****************************************************************************/ | ||
180 | /* | 192 | /* |
181 | * make sure a process keyring is installed | 193 | * make sure a process keyring is installed |
194 | * - we | ||
182 | */ | 195 | */ |
183 | int install_process_keyring(void) | 196 | static int install_process_keyring(void) |
184 | { | 197 | { |
185 | struct task_struct *tsk = current; | 198 | struct cred *new; |
186 | struct key *keyring; | ||
187 | char buf[20]; | ||
188 | int ret; | 199 | int ret; |
189 | 200 | ||
190 | might_sleep(); | 201 | new = prepare_creds(); |
191 | 202 | if (!new) | |
192 | if (!tsk->cred->tgcred->process_keyring) { | 203 | return -ENOMEM; |
193 | sprintf(buf, "_pid.%u", tsk->tgid); | ||
194 | |||
195 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, tsk, | ||
196 | KEY_ALLOC_QUOTA_OVERRUN, NULL); | ||
197 | if (IS_ERR(keyring)) { | ||
198 | ret = PTR_ERR(keyring); | ||
199 | goto error; | ||
200 | } | ||
201 | |||
202 | /* attach keyring */ | ||
203 | spin_lock_irq(&tsk->cred->tgcred->lock); | ||
204 | if (!tsk->cred->tgcred->process_keyring) { | ||
205 | tsk->cred->tgcred->process_keyring = keyring; | ||
206 | keyring = NULL; | ||
207 | } | ||
208 | spin_unlock_irq(&tsk->cred->tgcred->lock); | ||
209 | 204 | ||
210 | key_put(keyring); | 205 | ret = install_process_keyring_to_cred(new); |
206 | if (ret < 0) { | ||
207 | abort_creds(new); | ||
208 | return ret != -EEXIST ?: 0; | ||
211 | } | 209 | } |
212 | 210 | ||
213 | ret = 0; | 211 | return commit_creds(new); |
214 | error: | 212 | } |
215 | return ret; | ||
216 | |||
217 | } /* end install_process_keyring() */ | ||
218 | 213 | ||
219 | /*****************************************************************************/ | ||
220 | /* | 214 | /* |
221 | * install a session keyring, discarding the old one | 215 | * install a session keyring directly to a credentials struct |
222 | * - if a keyring is not supplied, an empty one is invented | ||
223 | */ | 216 | */ |
224 | static int install_session_keyring(struct key *keyring) | 217 | static int install_session_keyring_to_cred(struct cred *cred, |
218 | struct key *keyring) | ||
225 | { | 219 | { |
226 | struct task_struct *tsk = current; | ||
227 | unsigned long flags; | 220 | unsigned long flags; |
228 | struct key *old; | 221 | struct key *old; |
229 | char buf[20]; | ||
230 | 222 | ||
231 | might_sleep(); | 223 | might_sleep(); |
232 | 224 | ||
233 | /* create an empty session keyring */ | 225 | /* create an empty session keyring */ |
234 | if (!keyring) { | 226 | if (!keyring) { |
235 | sprintf(buf, "_ses.%u", tsk->tgid); | ||
236 | |||
237 | flags = KEY_ALLOC_QUOTA_OVERRUN; | 227 | flags = KEY_ALLOC_QUOTA_OVERRUN; |
238 | if (tsk->cred->tgcred->session_keyring) | 228 | if (cred->tgcred->session_keyring) |
239 | flags = KEY_ALLOC_IN_QUOTA; | 229 | flags = KEY_ALLOC_IN_QUOTA; |
240 | 230 | ||
241 | keyring = keyring_alloc(buf, tsk->cred->uid, tsk->cred->gid, | 231 | keyring = keyring_alloc("_ses", cred->uid, cred->gid, |
242 | tsk, flags, NULL); | 232 | cred, flags, NULL); |
243 | if (IS_ERR(keyring)) | 233 | if (IS_ERR(keyring)) |
244 | return PTR_ERR(keyring); | 234 | return PTR_ERR(keyring); |
245 | } | 235 | } else { |
246 | else { | ||
247 | atomic_inc(&keyring->usage); | 236 | atomic_inc(&keyring->usage); |
248 | } | 237 | } |
249 | 238 | ||
250 | /* install the keyring */ | 239 | /* install the keyring */ |
251 | spin_lock_irq(&tsk->cred->tgcred->lock); | 240 | spin_lock_irq(&cred->tgcred->lock); |
252 | old = tsk->cred->tgcred->session_keyring; | 241 | old = cred->tgcred->session_keyring; |
253 | rcu_assign_pointer(tsk->cred->tgcred->session_keyring, keyring); | 242 | rcu_assign_pointer(cred->tgcred->session_keyring, keyring); |
254 | spin_unlock_irq(&tsk->cred->tgcred->lock); | 243 | spin_unlock_irq(&cred->tgcred->lock); |
255 | 244 | ||
256 | /* we're using RCU on the pointer, but there's no point synchronising | 245 | /* we're using RCU on the pointer, but there's no point synchronising |
257 | * on it if it didn't previously point to anything */ | 246 | * on it if it didn't previously point to anything */ |
@@ -261,38 +250,29 @@ static int install_session_keyring(struct key *keyring) | |||
261 | } | 250 | } |
262 | 251 | ||
263 | return 0; | 252 | return 0; |
253 | } | ||
264 | 254 | ||
265 | } /* end install_session_keyring() */ | ||
266 | |||
267 | /*****************************************************************************/ | ||
268 | /* | 255 | /* |
269 | * copy the keys for fork | 256 | * install a session keyring, discarding the old one |
257 | * - if a keyring is not supplied, an empty one is invented | ||
270 | */ | 258 | */ |
271 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | 259 | static int install_session_keyring(struct key *keyring) |
272 | { | 260 | { |
273 | key_check(tsk->cred->thread_keyring); | 261 | struct cred *new; |
274 | key_check(tsk->cred->request_key_auth); | 262 | int ret; |
275 | |||
276 | /* no thread keyring yet */ | ||
277 | tsk->cred->thread_keyring = NULL; | ||
278 | |||
279 | /* copy the request_key() authorisation for this thread */ | ||
280 | key_get(tsk->cred->request_key_auth); | ||
281 | |||
282 | return 0; | ||
283 | 263 | ||
284 | } /* end copy_keys() */ | 264 | new = prepare_creds(); |
265 | if (!new) | ||
266 | return -ENOMEM; | ||
285 | 267 | ||
286 | /*****************************************************************************/ | 268 | ret = install_session_keyring_to_cred(new, NULL); |
287 | /* | 269 | if (ret < 0) { |
288 | * dispose of per-thread keys upon thread exit | 270 | abort_creds(new); |
289 | */ | 271 | return ret; |
290 | void exit_keys(struct task_struct *tsk) | 272 | } |
291 | { | ||
292 | key_put(tsk->cred->thread_keyring); | ||
293 | key_put(tsk->cred->request_key_auth); | ||
294 | 273 | ||
295 | } /* end exit_keys() */ | 274 | return commit_creds(new); |
275 | } | ||
296 | 276 | ||
297 | /*****************************************************************************/ | 277 | /*****************************************************************************/ |
298 | /* | 278 | /* |
@@ -300,38 +280,41 @@ void exit_keys(struct task_struct *tsk) | |||
300 | */ | 280 | */ |
301 | int exec_keys(struct task_struct *tsk) | 281 | int exec_keys(struct task_struct *tsk) |
302 | { | 282 | { |
303 | struct key *old; | 283 | struct thread_group_cred *tgcred = NULL; |
284 | struct cred *new; | ||
304 | 285 | ||
305 | /* newly exec'd tasks don't get a thread keyring */ | 286 | #ifdef CONFIG_KEYS |
306 | task_lock(tsk); | 287 | tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); |
307 | old = tsk->cred->thread_keyring; | 288 | if (!tgcred) |
308 | tsk->cred->thread_keyring = NULL; | 289 | return -ENOMEM; |
309 | task_unlock(tsk); | 290 | #endif |
310 | 291 | ||
311 | key_put(old); | 292 | new = prepare_creds(); |
293 | if (new < 0) | ||
294 | return -ENOMEM; | ||
312 | 295 | ||
313 | /* discard the process keyring from a newly exec'd task */ | 296 | /* newly exec'd tasks don't get a thread keyring */ |
314 | spin_lock_irq(&tsk->cred->tgcred->lock); | 297 | key_put(new->thread_keyring); |
315 | old = tsk->cred->tgcred->process_keyring; | 298 | new->thread_keyring = NULL; |
316 | tsk->cred->tgcred->process_keyring = NULL; | ||
317 | spin_unlock_irq(&tsk->cred->tgcred->lock); | ||
318 | 299 | ||
319 | key_put(old); | 300 | /* create a new per-thread-group creds for all this set of threads to |
301 | * share */ | ||
302 | memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); | ||
320 | 303 | ||
321 | return 0; | 304 | atomic_set(&tgcred->usage, 1); |
305 | spin_lock_init(&tgcred->lock); | ||
322 | 306 | ||
323 | } /* end exec_keys() */ | 307 | /* inherit the session keyring; new process keyring */ |
308 | key_get(tgcred->session_keyring); | ||
309 | tgcred->process_keyring = NULL; | ||
324 | 310 | ||
325 | /*****************************************************************************/ | 311 | release_tgcred(new); |
326 | /* | 312 | new->tgcred = tgcred; |
327 | * deal with SUID programs | 313 | |
328 | * - we might want to make this invent a new session keyring | 314 | commit_creds(new); |
329 | */ | ||
330 | int suid_keys(struct task_struct *tsk) | ||
331 | { | ||
332 | return 0; | 315 | return 0; |
333 | 316 | ||
334 | } /* end suid_keys() */ | 317 | } /* end exec_keys() */ |
335 | 318 | ||
336 | /*****************************************************************************/ | 319 | /*****************************************************************************/ |
337 | /* | 320 | /* |
@@ -376,16 +359,13 @@ void key_fsgid_changed(struct task_struct *tsk) | |||
376 | key_ref_t search_process_keyrings(struct key_type *type, | 359 | key_ref_t search_process_keyrings(struct key_type *type, |
377 | const void *description, | 360 | const void *description, |
378 | key_match_func_t match, | 361 | key_match_func_t match, |
379 | struct task_struct *context) | 362 | const struct cred *cred) |
380 | { | 363 | { |
381 | struct request_key_auth *rka; | 364 | struct request_key_auth *rka; |
382 | struct cred *cred; | ||
383 | key_ref_t key_ref, ret, err; | 365 | key_ref_t key_ref, ret, err; |
384 | 366 | ||
385 | might_sleep(); | 367 | might_sleep(); |
386 | 368 | ||
387 | cred = get_task_cred(context); | ||
388 | |||
389 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 369 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
390 | * searchable, but we failed to find a key or we found a negative key; | 370 | * searchable, but we failed to find a key or we found a negative key; |
391 | * otherwise we want to return a sample error (probably -EACCES) if | 371 | * otherwise we want to return a sample error (probably -EACCES) if |
@@ -401,7 +381,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
401 | if (cred->thread_keyring) { | 381 | if (cred->thread_keyring) { |
402 | key_ref = keyring_search_aux( | 382 | key_ref = keyring_search_aux( |
403 | make_key_ref(cred->thread_keyring, 1), | 383 | make_key_ref(cred->thread_keyring, 1), |
404 | context, type, description, match); | 384 | cred, type, description, match); |
405 | if (!IS_ERR(key_ref)) | 385 | if (!IS_ERR(key_ref)) |
406 | goto found; | 386 | goto found; |
407 | 387 | ||
@@ -422,7 +402,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
422 | if (cred->tgcred->process_keyring) { | 402 | if (cred->tgcred->process_keyring) { |
423 | key_ref = keyring_search_aux( | 403 | key_ref = keyring_search_aux( |
424 | make_key_ref(cred->tgcred->process_keyring, 1), | 404 | make_key_ref(cred->tgcred->process_keyring, 1), |
425 | context, type, description, match); | 405 | cred, type, description, match); |
426 | if (!IS_ERR(key_ref)) | 406 | if (!IS_ERR(key_ref)) |
427 | goto found; | 407 | goto found; |
428 | 408 | ||
@@ -446,7 +426,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
446 | make_key_ref(rcu_dereference( | 426 | make_key_ref(rcu_dereference( |
447 | cred->tgcred->session_keyring), | 427 | cred->tgcred->session_keyring), |
448 | 1), | 428 | 1), |
449 | context, type, description, match); | 429 | cred, type, description, match); |
450 | rcu_read_unlock(); | 430 | rcu_read_unlock(); |
451 | 431 | ||
452 | if (!IS_ERR(key_ref)) | 432 | if (!IS_ERR(key_ref)) |
@@ -468,7 +448,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
468 | else if (cred->user->session_keyring) { | 448 | else if (cred->user->session_keyring) { |
469 | key_ref = keyring_search_aux( | 449 | key_ref = keyring_search_aux( |
470 | make_key_ref(cred->user->session_keyring, 1), | 450 | make_key_ref(cred->user->session_keyring, 1), |
471 | context, type, description, match); | 451 | cred, type, description, match); |
472 | if (!IS_ERR(key_ref)) | 452 | if (!IS_ERR(key_ref)) |
473 | goto found; | 453 | goto found; |
474 | 454 | ||
@@ -490,7 +470,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
490 | * - we don't permit access to request_key auth keys via this method | 470 | * - we don't permit access to request_key auth keys via this method |
491 | */ | 471 | */ |
492 | if (cred->request_key_auth && | 472 | if (cred->request_key_auth && |
493 | context == current && | 473 | cred == current_cred() && |
494 | type != &key_type_request_key_auth | 474 | type != &key_type_request_key_auth |
495 | ) { | 475 | ) { |
496 | /* defend against the auth key being revoked */ | 476 | /* defend against the auth key being revoked */ |
@@ -500,7 +480,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
500 | rka = cred->request_key_auth->payload.data; | 480 | rka = cred->request_key_auth->payload.data; |
501 | 481 | ||
502 | key_ref = search_process_keyrings(type, description, | 482 | key_ref = search_process_keyrings(type, description, |
503 | match, rka->context); | 483 | match, rka->cred); |
504 | 484 | ||
505 | up_read(&cred->request_key_auth->sem); | 485 | up_read(&cred->request_key_auth->sem); |
506 | 486 | ||
@@ -527,7 +507,6 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
527 | key_ref = ret ? ret : err; | 507 | key_ref = ret ? ret : err; |
528 | 508 | ||
529 | found: | 509 | found: |
530 | put_cred(cred); | ||
531 | return key_ref; | 510 | return key_ref; |
532 | 511 | ||
533 | } /* end search_process_keyrings() */ | 512 | } /* end search_process_keyrings() */ |
@@ -552,8 +531,7 @@ key_ref_t lookup_user_key(key_serial_t id, int create, int partial, | |||
552 | key_perm_t perm) | 531 | key_perm_t perm) |
553 | { | 532 | { |
554 | struct request_key_auth *rka; | 533 | struct request_key_auth *rka; |
555 | struct task_struct *t = current; | 534 | const struct cred *cred; |
556 | struct cred *cred; | ||
557 | struct key *key; | 535 | struct key *key; |
558 | key_ref_t key_ref, skey_ref; | 536 | key_ref_t key_ref, skey_ref; |
559 | int ret; | 537 | int ret; |
@@ -608,6 +586,7 @@ try_again: | |||
608 | goto error; | 586 | goto error; |
609 | ret = install_session_keyring( | 587 | ret = install_session_keyring( |
610 | cred->user->session_keyring); | 588 | cred->user->session_keyring); |
589 | |||
611 | if (ret < 0) | 590 | if (ret < 0) |
612 | goto error; | 591 | goto error; |
613 | goto reget_creds; | 592 | goto reget_creds; |
@@ -693,7 +672,7 @@ try_again: | |||
693 | /* check to see if we possess the key */ | 672 | /* check to see if we possess the key */ |
694 | skey_ref = search_process_keyrings(key->type, key, | 673 | skey_ref = search_process_keyrings(key->type, key, |
695 | lookup_user_key_possessed, | 674 | lookup_user_key_possessed, |
696 | current); | 675 | cred); |
697 | 676 | ||
698 | if (!IS_ERR(skey_ref)) { | 677 | if (!IS_ERR(skey_ref)) { |
699 | key_put(key); | 678 | key_put(key); |
@@ -725,7 +704,7 @@ try_again: | |||
725 | goto invalid_key; | 704 | goto invalid_key; |
726 | 705 | ||
727 | /* check the permissions */ | 706 | /* check the permissions */ |
728 | ret = key_task_permission(key_ref, t, perm); | 707 | ret = key_task_permission(key_ref, cred, perm); |
729 | if (ret < 0) | 708 | if (ret < 0) |
730 | goto invalid_key; | 709 | goto invalid_key; |
731 | 710 | ||
@@ -755,21 +734,33 @@ reget_creds: | |||
755 | */ | 734 | */ |
756 | long join_session_keyring(const char *name) | 735 | long join_session_keyring(const char *name) |
757 | { | 736 | { |
758 | struct task_struct *tsk = current; | 737 | const struct cred *old; |
759 | struct cred *cred = current->cred; | 738 | struct cred *new; |
760 | struct key *keyring; | 739 | struct key *keyring; |
761 | long ret; | 740 | long ret, serial; |
741 | |||
742 | /* only permit this if there's a single thread in the thread group - | ||
743 | * this avoids us having to adjust the creds on all threads and risking | ||
744 | * ENOMEM */ | ||
745 | if (!is_single_threaded(current)) | ||
746 | return -EMLINK; | ||
747 | |||
748 | new = prepare_creds(); | ||
749 | if (!new) | ||
750 | return -ENOMEM; | ||
751 | old = current_cred(); | ||
762 | 752 | ||
763 | /* if no name is provided, install an anonymous keyring */ | 753 | /* if no name is provided, install an anonymous keyring */ |
764 | if (!name) { | 754 | if (!name) { |
765 | ret = install_session_keyring(NULL); | 755 | ret = install_session_keyring_to_cred(new, NULL); |
766 | if (ret < 0) | 756 | if (ret < 0) |
767 | goto error; | 757 | goto error; |
768 | 758 | ||
769 | rcu_read_lock(); | 759 | serial = new->tgcred->session_keyring->serial; |
770 | ret = rcu_dereference(cred->tgcred->session_keyring)->serial; | 760 | ret = commit_creds(new); |
771 | rcu_read_unlock(); | 761 | if (ret == 0) |
772 | goto error; | 762 | ret = serial; |
763 | goto okay; | ||
773 | } | 764 | } |
774 | 765 | ||
775 | /* allow the user to join or create a named keyring */ | 766 | /* allow the user to join or create a named keyring */ |
@@ -779,29 +770,33 @@ long join_session_keyring(const char *name) | |||
779 | keyring = find_keyring_by_name(name, false); | 770 | keyring = find_keyring_by_name(name, false); |
780 | if (PTR_ERR(keyring) == -ENOKEY) { | 771 | if (PTR_ERR(keyring) == -ENOKEY) { |
781 | /* not found - try and create a new one */ | 772 | /* not found - try and create a new one */ |
782 | keyring = keyring_alloc(name, cred->uid, cred->gid, tsk, | 773 | keyring = keyring_alloc(name, old->uid, old->gid, old, |
783 | KEY_ALLOC_IN_QUOTA, NULL); | 774 | KEY_ALLOC_IN_QUOTA, NULL); |
784 | if (IS_ERR(keyring)) { | 775 | if (IS_ERR(keyring)) { |
785 | ret = PTR_ERR(keyring); | 776 | ret = PTR_ERR(keyring); |
786 | goto error2; | 777 | goto error2; |
787 | } | 778 | } |
788 | } | 779 | } else if (IS_ERR(keyring)) { |
789 | else if (IS_ERR(keyring)) { | ||
790 | ret = PTR_ERR(keyring); | 780 | ret = PTR_ERR(keyring); |
791 | goto error2; | 781 | goto error2; |
792 | } | 782 | } |
793 | 783 | ||
794 | /* we've got a keyring - now to install it */ | 784 | /* we've got a keyring - now to install it */ |
795 | ret = install_session_keyring(keyring); | 785 | ret = install_session_keyring_to_cred(new, keyring); |
796 | if (ret < 0) | 786 | if (ret < 0) |
797 | goto error2; | 787 | goto error2; |
798 | 788 | ||
789 | commit_creds(new); | ||
790 | mutex_unlock(&key_session_mutex); | ||
791 | |||
799 | ret = keyring->serial; | 792 | ret = keyring->serial; |
800 | key_put(keyring); | 793 | key_put(keyring); |
794 | okay: | ||
795 | return ret; | ||
801 | 796 | ||
802 | error2: | 797 | error2: |
803 | mutex_unlock(&key_session_mutex); | 798 | mutex_unlock(&key_session_mutex); |
804 | error: | 799 | error: |
800 | abort_creds(new); | ||
805 | return ret; | 801 | return ret; |
806 | 802 | } | |
807 | } /* end join_session_keyring() */ | ||