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