| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * AppArmor security module |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2002-2008 Novell/SUSE |
|---|
| 7 | 8 | * Copyright 2009-2010 Canonical Ltd. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is free software; you can redistribute it and/or |
|---|
| 10 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 11 | | - * published by the Free Software Foundation, version 2 of the |
|---|
| 12 | | - * License. |
|---|
| 13 | 9 | */ |
|---|
| 14 | 10 | |
|---|
| 15 | 11 | #include <linux/errno.h> |
|---|
| .. | .. |
|---|
| 44 | 40 | return; |
|---|
| 45 | 41 | |
|---|
| 46 | 42 | for (i = 0; i < domain->size; i++) |
|---|
| 47 | | - kzfree(domain->table[i]); |
|---|
| 48 | | - kzfree(domain->table); |
|---|
| 43 | + kfree_sensitive(domain->table[i]); |
|---|
| 44 | + kfree_sensitive(domain->table); |
|---|
| 49 | 45 | domain->table = NULL; |
|---|
| 50 | 46 | } |
|---|
| 51 | 47 | } |
|---|
| .. | .. |
|---|
| 324 | 320 | might_sleep(); |
|---|
| 325 | 321 | |
|---|
| 326 | 322 | /* transition from exec match to xattr set */ |
|---|
| 327 | | - state = aa_dfa_null_transition(profile->xmatch, state); |
|---|
| 328 | | - |
|---|
| 323 | + state = aa_dfa_outofband_transition(profile->xmatch, state); |
|---|
| 329 | 324 | d = bprm->file->f_path.dentry; |
|---|
| 330 | 325 | |
|---|
| 331 | 326 | for (i = 0; i < profile->xattr_count; i++) { |
|---|
| .. | .. |
|---|
| 334 | 329 | if (size >= 0) { |
|---|
| 335 | 330 | u32 perm; |
|---|
| 336 | 331 | |
|---|
| 337 | | - /* Check the xattr value, not just presence */ |
|---|
| 332 | + /* |
|---|
| 333 | + * Check the xattr presence before value. This ensure |
|---|
| 334 | + * that not present xattr can be distinguished from a 0 |
|---|
| 335 | + * length value or rule that matches any value |
|---|
| 336 | + */ |
|---|
| 337 | + state = aa_dfa_null_transition(profile->xmatch, state); |
|---|
| 338 | + /* Check xattr value */ |
|---|
| 338 | 339 | state = aa_dfa_match_len(profile->xmatch, state, value, |
|---|
| 339 | 340 | size); |
|---|
| 340 | 341 | perm = dfa_user_allow(profile->xmatch, state); |
|---|
| .. | .. |
|---|
| 344 | 345 | } |
|---|
| 345 | 346 | } |
|---|
| 346 | 347 | /* transition to next element */ |
|---|
| 347 | | - state = aa_dfa_null_transition(profile->xmatch, state); |
|---|
| 348 | + state = aa_dfa_outofband_transition(profile->xmatch, state); |
|---|
| 348 | 349 | if (size < 0) { |
|---|
| 349 | 350 | /* |
|---|
| 350 | 351 | * No xattr match, so verify if transition to |
|---|
| .. | .. |
|---|
| 464 | 465 | * xattrs, or a longer match |
|---|
| 465 | 466 | */ |
|---|
| 466 | 467 | candidate = profile; |
|---|
| 467 | | - candidate_len = profile->xmatch_len; |
|---|
| 468 | + candidate_len = max(count, profile->xmatch_len); |
|---|
| 468 | 469 | candidate_xattrs = ret; |
|---|
| 469 | 470 | conflict = false; |
|---|
| 470 | 471 | } |
|---|
| .. | .. |
|---|
| 528 | 529 | label = &new_profile->label; |
|---|
| 529 | 530 | continue; |
|---|
| 530 | 531 | } |
|---|
| 531 | | - label = aa_label_parse(&profile->label, *name, GFP_ATOMIC, |
|---|
| 532 | + label = aa_label_parse(&profile->label, *name, GFP_KERNEL, |
|---|
| 532 | 533 | true, false); |
|---|
| 533 | 534 | if (IS_ERR(label)) |
|---|
| 534 | 535 | label = NULL; |
|---|
| .. | .. |
|---|
| 576 | 577 | stack = NULL; |
|---|
| 577 | 578 | break; |
|---|
| 578 | 579 | } |
|---|
| 579 | | - /* fall through to X_NAME */ |
|---|
| 580 | + fallthrough; /* to X_NAME */ |
|---|
| 580 | 581 | case AA_X_NAME: |
|---|
| 581 | 582 | if (xindex & AA_X_CHILD) |
|---|
| 582 | 583 | /* released by caller */ |
|---|
| .. | .. |
|---|
| 608 | 609 | /* base the stack on post domain transition */ |
|---|
| 609 | 610 | struct aa_label *base = new; |
|---|
| 610 | 611 | |
|---|
| 611 | | - new = aa_label_parse(base, stack, GFP_ATOMIC, true, false); |
|---|
| 612 | + new = aa_label_parse(base, stack, GFP_KERNEL, true, false); |
|---|
| 612 | 613 | if (IS_ERR(new)) |
|---|
| 613 | 614 | new = NULL; |
|---|
| 614 | 615 | aa_put_label(base); |
|---|
| .. | .. |
|---|
| 624 | 625 | bool *secure_exec) |
|---|
| 625 | 626 | { |
|---|
| 626 | 627 | struct aa_label *new = NULL; |
|---|
| 627 | | - struct aa_profile *component; |
|---|
| 628 | | - struct label_it i; |
|---|
| 629 | 628 | const char *info = NULL, *name = NULL, *target = NULL; |
|---|
| 630 | 629 | unsigned int state = profile->file.start; |
|---|
| 631 | 630 | struct aa_perms perms = {}; |
|---|
| .. | .. |
|---|
| 674 | 673 | info = "profile transition not found"; |
|---|
| 675 | 674 | /* remove MAY_EXEC to audit as failure */ |
|---|
| 676 | 675 | perms.allow &= ~MAY_EXEC; |
|---|
| 677 | | - } else { |
|---|
| 678 | | - /* verify that each component's xattr requirements are |
|---|
| 679 | | - * met, and fail execution otherwise |
|---|
| 680 | | - */ |
|---|
| 681 | | - label_for_each(i, new, component) { |
|---|
| 682 | | - if (aa_xattrs_match(bprm, component, state) < |
|---|
| 683 | | - 0) { |
|---|
| 684 | | - error = -EACCES; |
|---|
| 685 | | - info = "required xattrs not present"; |
|---|
| 686 | | - perms.allow &= ~MAY_EXEC; |
|---|
| 687 | | - aa_put_label(new); |
|---|
| 688 | | - new = NULL; |
|---|
| 689 | | - goto audit; |
|---|
| 690 | | - } |
|---|
| 691 | | - } |
|---|
| 692 | 676 | } |
|---|
| 693 | 677 | } else if (COMPLAIN_MODE(profile)) { |
|---|
| 694 | 678 | /* no exec permission - learning mode */ |
|---|
| 695 | 679 | struct aa_profile *new_profile = NULL; |
|---|
| 696 | | - char *n = kstrdup(name, GFP_ATOMIC); |
|---|
| 697 | 680 | |
|---|
| 698 | | - if (n) { |
|---|
| 699 | | - /* name is ptr into buffer */ |
|---|
| 700 | | - long pos = name - buffer; |
|---|
| 701 | | - /* break per cpu buffer hold */ |
|---|
| 702 | | - put_buffers(buffer); |
|---|
| 703 | | - new_profile = aa_new_null_profile(profile, false, n, |
|---|
| 704 | | - GFP_KERNEL); |
|---|
| 705 | | - get_buffers(buffer); |
|---|
| 706 | | - name = buffer + pos; |
|---|
| 707 | | - strcpy((char *)name, n); |
|---|
| 708 | | - kfree(n); |
|---|
| 709 | | - } |
|---|
| 681 | + new_profile = aa_new_null_profile(profile, false, name, |
|---|
| 682 | + GFP_KERNEL); |
|---|
| 710 | 683 | if (!new_profile) { |
|---|
| 711 | 684 | error = -ENOMEM; |
|---|
| 712 | 685 | info = "could not create null profile"; |
|---|
| .. | .. |
|---|
| 727 | 700 | if (DEBUG_ON) { |
|---|
| 728 | 701 | dbg_printk("apparmor: scrubbing environment variables" |
|---|
| 729 | 702 | " for %s profile=", name); |
|---|
| 730 | | - aa_label_printk(new, GFP_ATOMIC); |
|---|
| 703 | + aa_label_printk(new, GFP_KERNEL); |
|---|
| 731 | 704 | dbg_printk("\n"); |
|---|
| 732 | 705 | } |
|---|
| 733 | 706 | *secure_exec = true; |
|---|
| .. | .. |
|---|
| 803 | 776 | if (DEBUG_ON) { |
|---|
| 804 | 777 | dbg_printk("apparmor: scrubbing environment " |
|---|
| 805 | 778 | "variables for %s label=", xname); |
|---|
| 806 | | - aa_label_printk(onexec, GFP_ATOMIC); |
|---|
| 779 | + aa_label_printk(onexec, GFP_KERNEL); |
|---|
| 807 | 780 | dbg_printk("\n"); |
|---|
| 808 | 781 | } |
|---|
| 809 | 782 | *secure_exec = true; |
|---|
| .. | .. |
|---|
| 837 | 810 | bprm, buffer, cond, unsafe)); |
|---|
| 838 | 811 | if (error) |
|---|
| 839 | 812 | return ERR_PTR(error); |
|---|
| 840 | | - new = fn_label_build_in_ns(label, profile, GFP_ATOMIC, |
|---|
| 813 | + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, |
|---|
| 841 | 814 | aa_get_newest_label(onexec), |
|---|
| 842 | 815 | profile_transition(profile, bprm, buffer, |
|---|
| 843 | 816 | cond, unsafe)); |
|---|
| .. | .. |
|---|
| 849 | 822 | buffer, cond, unsafe)); |
|---|
| 850 | 823 | if (error) |
|---|
| 851 | 824 | return ERR_PTR(error); |
|---|
| 852 | | - new = fn_label_build_in_ns(label, profile, GFP_ATOMIC, |
|---|
| 825 | + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, |
|---|
| 853 | 826 | aa_label_merge(&profile->label, onexec, |
|---|
| 854 | | - GFP_ATOMIC), |
|---|
| 827 | + GFP_KERNEL), |
|---|
| 855 | 828 | profile_transition(profile, bprm, buffer, |
|---|
| 856 | 829 | cond, unsafe)); |
|---|
| 857 | 830 | } |
|---|
| .. | .. |
|---|
| 869 | 842 | } |
|---|
| 870 | 843 | |
|---|
| 871 | 844 | /** |
|---|
| 872 | | - * apparmor_bprm_set_creds - set the new creds on the bprm struct |
|---|
| 845 | + * apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct |
|---|
| 873 | 846 | * @bprm: binprm for the exec (NOT NULL) |
|---|
| 874 | 847 | * |
|---|
| 875 | 848 | * Returns: %0 or error on failure |
|---|
| 876 | 849 | * |
|---|
| 877 | 850 | * TODO: once the other paths are done see if we can't refactor into a fn |
|---|
| 878 | 851 | */ |
|---|
| 879 | | -int apparmor_bprm_set_creds(struct linux_binprm *bprm) |
|---|
| 852 | +int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm) |
|---|
| 880 | 853 | { |
|---|
| 881 | 854 | struct aa_task_ctx *ctx; |
|---|
| 882 | 855 | struct aa_label *label, *new = NULL; |
|---|
| .. | .. |
|---|
| 889 | 862 | file_inode(bprm->file)->i_uid, |
|---|
| 890 | 863 | file_inode(bprm->file)->i_mode |
|---|
| 891 | 864 | }; |
|---|
| 892 | | - |
|---|
| 893 | | - if (bprm->called_set_creds) |
|---|
| 894 | | - return 0; |
|---|
| 895 | 865 | |
|---|
| 896 | 866 | ctx = task_ctx(current); |
|---|
| 897 | 867 | AA_BUG(!cred_label(bprm->cred)); |
|---|
| .. | .. |
|---|
| 911 | 881 | ctx->nnp = aa_get_label(label); |
|---|
| 912 | 882 | |
|---|
| 913 | 883 | /* buffer freed below, name is pointer into buffer */ |
|---|
| 914 | | - get_buffers(buffer); |
|---|
| 884 | + buffer = aa_get_buffer(false); |
|---|
| 885 | + if (!buffer) { |
|---|
| 886 | + error = -ENOMEM; |
|---|
| 887 | + goto done; |
|---|
| 888 | + } |
|---|
| 889 | + |
|---|
| 915 | 890 | /* Test for onexec first as onexec override other x transitions. */ |
|---|
| 916 | 891 | if (ctx->onexec) |
|---|
| 917 | 892 | new = handle_onexec(label, ctx->onexec, ctx->token, |
|---|
| 918 | 893 | bprm, buffer, &cond, &unsafe); |
|---|
| 919 | 894 | else |
|---|
| 920 | | - new = fn_label_build(label, profile, GFP_ATOMIC, |
|---|
| 895 | + new = fn_label_build(label, profile, GFP_KERNEL, |
|---|
| 921 | 896 | profile_transition(profile, bprm, buffer, |
|---|
| 922 | 897 | &cond, &unsafe)); |
|---|
| 923 | 898 | |
|---|
| .. | .. |
|---|
| 962 | 937 | if (DEBUG_ON) { |
|---|
| 963 | 938 | dbg_printk("scrubbing environment variables for %s " |
|---|
| 964 | 939 | "label=", bprm->filename); |
|---|
| 965 | | - aa_label_printk(new, GFP_ATOMIC); |
|---|
| 940 | + aa_label_printk(new, GFP_KERNEL); |
|---|
| 966 | 941 | dbg_printk("\n"); |
|---|
| 967 | 942 | } |
|---|
| 968 | 943 | bprm->secureexec = 1; |
|---|
| .. | .. |
|---|
| 973 | 948 | if (DEBUG_ON) { |
|---|
| 974 | 949 | dbg_printk("apparmor: clearing unsafe personality " |
|---|
| 975 | 950 | "bits. %s label=", bprm->filename); |
|---|
| 976 | | - aa_label_printk(new, GFP_ATOMIC); |
|---|
| 951 | + aa_label_printk(new, GFP_KERNEL); |
|---|
| 977 | 952 | dbg_printk("\n"); |
|---|
| 978 | 953 | } |
|---|
| 979 | 954 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
|---|
| 980 | 955 | } |
|---|
| 981 | 956 | aa_put_label(cred_label(bprm->cred)); |
|---|
| 982 | 957 | /* transfer reference, released when cred is freed */ |
|---|
| 983 | | - cred_label(bprm->cred) = new; |
|---|
| 958 | + set_cred_label(bprm->cred, new); |
|---|
| 984 | 959 | |
|---|
| 985 | 960 | done: |
|---|
| 986 | 961 | aa_put_label(label); |
|---|
| 987 | | - put_buffers(buffer); |
|---|
| 962 | + aa_put_buffer(buffer); |
|---|
| 988 | 963 | |
|---|
| 989 | 964 | return error; |
|---|
| 990 | 965 | |
|---|