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