| .. | .. |
|---|
| 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); |
|---|