.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* Task credentials management - see Documentation/security/credentials.rst |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * 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 Licence |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the Licence, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | #include <linux/export.h> |
---|
12 | 8 | #include <linux/cred.h> |
---|
.. | .. |
---|
19 | 15 | #include <linux/security.h> |
---|
20 | 16 | #include <linux/binfmts.h> |
---|
21 | 17 | #include <linux/cn_proc.h> |
---|
| 18 | +#include <linux/uidgid.h> |
---|
| 19 | + |
---|
| 20 | +#include <trace/hooks/creds.h> |
---|
22 | 21 | |
---|
23 | 22 | #if 0 |
---|
24 | 23 | #define kdebug(FMT, ...) \ |
---|
.. | .. |
---|
176 | 175 | validate_creds(cred); |
---|
177 | 176 | alter_cred_subscribers(cred, -1); |
---|
178 | 177 | put_cred(cred); |
---|
| 178 | + |
---|
| 179 | +#ifdef CONFIG_KEYS_REQUEST_CACHE |
---|
| 180 | + key_put(tsk->cached_requested_key); |
---|
| 181 | + tsk->cached_requested_key = NULL; |
---|
| 182 | +#endif |
---|
| 183 | + trace_android_vh_exit_creds(tsk, cred); |
---|
179 | 184 | } |
---|
180 | 185 | |
---|
181 | 186 | /** |
---|
.. | .. |
---|
197 | 202 | do { |
---|
198 | 203 | cred = __task_cred((task)); |
---|
199 | 204 | BUG_ON(!cred); |
---|
200 | | - } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage)); |
---|
| 205 | + } while (!get_cred_rcu(cred)); |
---|
201 | 206 | |
---|
202 | 207 | rcu_read_unlock(); |
---|
203 | 208 | return cred; |
---|
204 | 209 | } |
---|
| 210 | +EXPORT_SYMBOL(get_task_cred); |
---|
205 | 211 | |
---|
206 | 212 | /* |
---|
207 | 213 | * Allocate blank credentials, such that the credentials can be filled in at a |
---|
.. | .. |
---|
312 | 318 | new->process_keyring = NULL; |
---|
313 | 319 | #endif |
---|
314 | 320 | |
---|
| 321 | + new->suid = new->fsuid = new->euid; |
---|
| 322 | + new->sgid = new->fsgid = new->egid; |
---|
| 323 | + |
---|
315 | 324 | return new; |
---|
316 | 325 | } |
---|
317 | 326 | |
---|
.. | .. |
---|
328 | 337 | { |
---|
329 | 338 | struct cred *new; |
---|
330 | 339 | int ret; |
---|
| 340 | + |
---|
| 341 | +#ifdef CONFIG_KEYS_REQUEST_CACHE |
---|
| 342 | + p->cached_requested_key = NULL; |
---|
| 343 | +#endif |
---|
331 | 344 | |
---|
332 | 345 | if ( |
---|
333 | 346 | #ifdef CONFIG_KEYS |
---|
.. | .. |
---|
466 | 479 | |
---|
467 | 480 | /* alter the thread keyring */ |
---|
468 | 481 | if (!uid_eq(new->fsuid, old->fsuid)) |
---|
469 | | - key_fsuid_changed(task); |
---|
| 482 | + key_fsuid_changed(new); |
---|
470 | 483 | if (!gid_eq(new->fsgid, old->fsgid)) |
---|
471 | | - key_fsgid_changed(task); |
---|
| 484 | + key_fsgid_changed(new); |
---|
472 | 485 | |
---|
473 | 486 | /* do it |
---|
474 | 487 | * RLIMIT_NPROC limits on user->processes have already been checked |
---|
.. | .. |
---|
479 | 492 | atomic_inc(&new->user->processes); |
---|
480 | 493 | rcu_assign_pointer(task->real_cred, new); |
---|
481 | 494 | rcu_assign_pointer(task->cred, new); |
---|
| 495 | + trace_android_vh_commit_creds(task, new); |
---|
482 | 496 | if (new->user != old->user) |
---|
483 | 497 | atomic_dec(&old->user->processes); |
---|
484 | 498 | alter_cred_subscribers(old, -2); |
---|
.. | .. |
---|
556 | 570 | get_new_cred((struct cred *)new); |
---|
557 | 571 | alter_cred_subscribers(new, 1); |
---|
558 | 572 | rcu_assign_pointer(current->cred, new); |
---|
| 573 | + trace_android_vh_override_creds(current, new); |
---|
559 | 574 | alter_cred_subscribers(old, -1); |
---|
560 | 575 | |
---|
561 | 576 | kdebug("override_creds() = %p{%d,%d}", old, |
---|
.. | .. |
---|
584 | 599 | validate_creds(override); |
---|
585 | 600 | alter_cred_subscribers(old, 1); |
---|
586 | 601 | rcu_assign_pointer(current->cred, old); |
---|
| 602 | + trace_android_vh_revert_creds(current, old); |
---|
587 | 603 | alter_cred_subscribers(override, -1); |
---|
588 | 604 | put_cred(override); |
---|
589 | 605 | } |
---|
590 | 606 | EXPORT_SYMBOL(revert_creds); |
---|
| 607 | + |
---|
| 608 | +/** |
---|
| 609 | + * cred_fscmp - Compare two credentials with respect to filesystem access. |
---|
| 610 | + * @a: The first credential |
---|
| 611 | + * @b: The second credential |
---|
| 612 | + * |
---|
| 613 | + * cred_cmp() will return zero if both credentials have the same |
---|
| 614 | + * fsuid, fsgid, and supplementary groups. That is, if they will both |
---|
| 615 | + * provide the same access to files based on mode/uid/gid. |
---|
| 616 | + * If the credentials are different, then either -1 or 1 will |
---|
| 617 | + * be returned depending on whether @a comes before or after @b |
---|
| 618 | + * respectively in an arbitrary, but stable, ordering of credentials. |
---|
| 619 | + * |
---|
| 620 | + * Return: -1, 0, or 1 depending on comparison |
---|
| 621 | + */ |
---|
| 622 | +int cred_fscmp(const struct cred *a, const struct cred *b) |
---|
| 623 | +{ |
---|
| 624 | + struct group_info *ga, *gb; |
---|
| 625 | + int g; |
---|
| 626 | + |
---|
| 627 | + if (a == b) |
---|
| 628 | + return 0; |
---|
| 629 | + if (uid_lt(a->fsuid, b->fsuid)) |
---|
| 630 | + return -1; |
---|
| 631 | + if (uid_gt(a->fsuid, b->fsuid)) |
---|
| 632 | + return 1; |
---|
| 633 | + |
---|
| 634 | + if (gid_lt(a->fsgid, b->fsgid)) |
---|
| 635 | + return -1; |
---|
| 636 | + if (gid_gt(a->fsgid, b->fsgid)) |
---|
| 637 | + return 1; |
---|
| 638 | + |
---|
| 639 | + ga = a->group_info; |
---|
| 640 | + gb = b->group_info; |
---|
| 641 | + if (ga == gb) |
---|
| 642 | + return 0; |
---|
| 643 | + if (ga == NULL) |
---|
| 644 | + return -1; |
---|
| 645 | + if (gb == NULL) |
---|
| 646 | + return 1; |
---|
| 647 | + if (ga->ngroups < gb->ngroups) |
---|
| 648 | + return -1; |
---|
| 649 | + if (ga->ngroups > gb->ngroups) |
---|
| 650 | + return 1; |
---|
| 651 | + |
---|
| 652 | + for (g = 0; g < ga->ngroups; g++) { |
---|
| 653 | + if (gid_lt(ga->gid[g], gb->gid[g])) |
---|
| 654 | + return -1; |
---|
| 655 | + if (gid_gt(ga->gid[g], gb->gid[g])) |
---|
| 656 | + return 1; |
---|
| 657 | + } |
---|
| 658 | + return 0; |
---|
| 659 | +} |
---|
| 660 | +EXPORT_SYMBOL(cred_fscmp); |
---|
591 | 661 | |
---|
592 | 662 | /* |
---|
593 | 663 | * initialise the credentials stuff |
---|
.. | .. |
---|
614 | 684 | * The caller may change these controls afterwards if desired. |
---|
615 | 685 | * |
---|
616 | 686 | * Returns the new credentials or NULL if out of memory. |
---|
617 | | - * |
---|
618 | | - * Does not take, and does not return holding current->cred_replace_mutex. |
---|
619 | 687 | */ |
---|
620 | 688 | struct cred *prepare_kernel_cred(struct task_struct *daemon) |
---|
621 | 689 | { |
---|
.. | .. |
---|
730 | 798 | { |
---|
731 | 799 | if (cred->magic != CRED_MAGIC) |
---|
732 | 800 | return true; |
---|
733 | | -#ifdef CONFIG_SECURITY_SELINUX |
---|
734 | | - /* |
---|
735 | | - * cred->security == NULL if security_cred_alloc_blank() or |
---|
736 | | - * security_prepare_creds() returned an error. |
---|
737 | | - */ |
---|
738 | | - if (selinux_is_enabled() && cred->security) { |
---|
739 | | - if ((unsigned long) cred->security < PAGE_SIZE) |
---|
740 | | - return true; |
---|
741 | | - if ((*(u32 *)cred->security & 0xffffff00) == |
---|
742 | | - (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) |
---|
743 | | - return true; |
---|
744 | | - } |
---|
745 | | -#endif |
---|
746 | 801 | return false; |
---|
747 | 802 | } |
---|
748 | 803 | EXPORT_SYMBOL(creds_are_invalid); |
---|