1 // SPDX-License-Identifier: GPL-2.0-only
3 * AppArmor security module
5 * This file contains AppArmor policy attachment and domain transitions
7 * Copyright (C) 2002-2008 Novell/SUSE
8 * Copyright 2009-2010 Canonical Ltd.
11 #include <linux/errno.h>
12 #include <linux/fdtable.h>
13 #include <linux/file.h>
14 #include <linux/mount.h>
15 #include <linux/syscalls.h>
16 #include <linux/tracehook.h>
17 #include <linux/personality.h>
18 #include <linux/xattr.h>
20 #include "include/audit.h"
21 #include "include/apparmorfs.h"
22 #include "include/cred.h"
23 #include "include/domain.h"
24 #include "include/file.h"
25 #include "include/ipc.h"
26 #include "include/match.h"
27 #include "include/path.h"
28 #include "include/policy.h"
29 #include "include/policy_ns.h"
32 * aa_free_domain_entries - free entries in a domain table
33 * @domain: the domain table to free (MAYBE NULL)
35 void aa_free_domain_entries(struct aa_domain
*domain
)
42 for (i
= 0; i
< domain
->size
; i
++)
43 kfree_sensitive(domain
->table
[i
]);
44 kfree_sensitive(domain
->table
);
50 * may_change_ptraced_domain - check if can change profile on ptraced task
51 * @to_label: profile to change to (NOT NULL)
52 * @info: message if there is an error
54 * Check if current is ptraced and if so if the tracing task is allowed
55 * to trace the new domain
57 * Returns: %0 or error if change not allowed
59 static int may_change_ptraced_domain(struct aa_label
*to_label
,
62 struct task_struct
*tracer
;
63 struct aa_label
*tracerl
= NULL
;
67 tracer
= ptrace_parent(current
);
70 tracerl
= aa_get_task_label(tracer
);
73 if (!tracer
|| unconfined(tracerl
))
76 error
= aa_may_ptrace(tracerl
, to_label
, PTRACE_MODE_ATTACH
);
80 aa_put_label(tracerl
);
83 *info
= "ptrace prevents transition";
87 /**** TODO: dedup to aa_label_match - needs perm and dfa, merging
88 * specifically this is an exact copy of aa_label_match except
89 * aa_compute_perms is replaced with aa_compute_fperms
90 * and policy.dfa with file.dfa
92 /* match a profile and its associated ns component if needed
93 * Assumes visibility test has already been done.
94 * If a subns profile is not to be matched should be prescreened with
97 static inline unsigned int match_component(struct aa_profile
*profile
,
98 struct aa_profile
*tp
,
99 bool stack
, unsigned int state
)
104 state
= aa_dfa_match(profile
->file
.dfa
, state
, "&");
105 if (profile
->ns
== tp
->ns
)
106 return aa_dfa_match(profile
->file
.dfa
, state
, tp
->base
.hname
);
108 /* try matching with namespace name and then profile */
109 ns_name
= aa_ns_name(profile
->ns
, tp
->ns
, true);
110 state
= aa_dfa_match_len(profile
->file
.dfa
, state
, ":", 1);
111 state
= aa_dfa_match(profile
->file
.dfa
, state
, ns_name
);
112 state
= aa_dfa_match_len(profile
->file
.dfa
, state
, ":", 1);
113 return aa_dfa_match(profile
->file
.dfa
, state
, tp
->base
.hname
);
117 * label_compound_match - find perms for full compound label
118 * @profile: profile to find perms for
119 * @label: label to check access permissions for
120 * @stack: whether this is a stacking request
121 * @start: state to start match in
122 * @subns: whether to do permission checks on components in a subns
123 * @request: permissions to request
124 * @perms: perms struct to set
126 * Returns: 0 on success else ERROR
128 * For the label A//&B//&C this does the perm match for A//&B//&C
129 * @perms should be preinitialized with allperms OR a previous permission
130 * check to be stacked.
132 static int label_compound_match(struct aa_profile
*profile
,
133 struct aa_label
*label
, bool stack
,
134 unsigned int state
, bool subns
, u32 request
,
135 struct aa_perms
*perms
)
137 struct aa_profile
*tp
;
139 struct path_cond cond
= { };
141 /* find first subcomponent that is visible */
142 label_for_each(i
, label
, tp
) {
143 if (!aa_ns_visible(profile
->ns
, tp
->ns
, subns
))
145 state
= match_component(profile
, tp
, stack
, state
);
151 /* no component visible */
156 label_for_each_cont(i
, label
, tp
) {
157 if (!aa_ns_visible(profile
->ns
, tp
->ns
, subns
))
159 state
= aa_dfa_match(profile
->file
.dfa
, state
, "//&");
160 state
= match_component(profile
, tp
, false, state
);
164 *perms
= aa_compute_fperms(profile
->file
.dfa
, state
, &cond
);
165 aa_apply_modes_to_perms(profile
, perms
);
166 if ((perms
->allow
& request
) != request
)
177 * label_components_match - find perms for all subcomponents of a label
178 * @profile: profile to find perms for
179 * @label: label to check access permissions for
180 * @stack: whether this is a stacking request
181 * @start: state to start match in
182 * @subns: whether to do permission checks on components in a subns
183 * @request: permissions to request
184 * @perms: an initialized perms struct to add accumulation to
186 * Returns: 0 on success else ERROR
188 * For the label A//&B//&C this does the perm match for each of A and B and C
189 * @perms should be preinitialized with allperms OR a previous permission
190 * check to be stacked.
192 static int label_components_match(struct aa_profile
*profile
,
193 struct aa_label
*label
, bool stack
,
194 unsigned int start
, bool subns
, u32 request
,
195 struct aa_perms
*perms
)
197 struct aa_profile
*tp
;
200 struct path_cond cond
= { };
201 unsigned int state
= 0;
203 /* find first subcomponent to test */
204 label_for_each(i
, label
, tp
) {
205 if (!aa_ns_visible(profile
->ns
, tp
->ns
, subns
))
207 state
= match_component(profile
, tp
, stack
, start
);
213 /* no subcomponents visible - no change in perms */
217 tmp
= aa_compute_fperms(profile
->file
.dfa
, state
, &cond
);
218 aa_apply_modes_to_perms(profile
, &tmp
);
219 aa_perms_accum(perms
, &tmp
);
220 label_for_each_cont(i
, label
, tp
) {
221 if (!aa_ns_visible(profile
->ns
, tp
->ns
, subns
))
223 state
= match_component(profile
, tp
, stack
, start
);
226 tmp
= aa_compute_fperms(profile
->file
.dfa
, state
, &cond
);
227 aa_apply_modes_to_perms(profile
, &tmp
);
228 aa_perms_accum(perms
, &tmp
);
231 if ((perms
->allow
& request
) != request
)
242 * label_match - do a multi-component label match
243 * @profile: profile to match against (NOT NULL)
244 * @label: label to match (NOT NULL)
245 * @stack: whether this is a stacking request
246 * @state: state to start in
247 * @subns: whether to match subns components
248 * @request: permission request
249 * @perms: Returns computed perms (NOT NULL)
251 * Returns: the state the match finished in, may be the none matching state
253 static int label_match(struct aa_profile
*profile
, struct aa_label
*label
,
254 bool stack
, unsigned int state
, bool subns
, u32 request
,
255 struct aa_perms
*perms
)
260 error
= label_compound_match(profile
, label
, stack
, state
, subns
,
266 return label_components_match(profile
, label
, stack
, state
, subns
,
270 /******* end TODO: dedup *****/
273 * change_profile_perms - find permissions for change_profile
274 * @profile: the current profile (NOT NULL)
275 * @target: label to transition to (NOT NULL)
276 * @stack: whether this is a stacking request
277 * @request: requested perms
278 * @start: state to start matching in
281 * Returns: permission set
283 * currently only matches full label A//&B//&C or individual components A, B, C
284 * not arbitrary combinations. Eg. A//&B, C
286 static int change_profile_perms(struct aa_profile
*profile
,
287 struct aa_label
*target
, bool stack
,
288 u32 request
, unsigned int start
,
289 struct aa_perms
*perms
)
291 if (profile_unconfined(profile
)) {
292 perms
->allow
= AA_MAY_CHANGE_PROFILE
| AA_MAY_ONEXEC
;
293 perms
->audit
= perms
->quiet
= perms
->kill
= 0;
297 /* TODO: add profile in ns screening */
298 return label_match(profile
, target
, stack
, start
, true, request
, perms
);
302 * aa_xattrs_match - check whether a file matches the xattrs defined in profile
303 * @bprm: binprm struct for the process to validate
304 * @profile: profile to match against (NOT NULL)
305 * @state: state to start match in
307 * Returns: number of extended attributes that matched, or < 0 on error
309 static int aa_xattrs_match(const struct linux_binprm
*bprm
,
310 struct aa_profile
*profile
, unsigned int state
)
316 int value_size
= 0, ret
= profile
->xattr_count
;
318 if (!bprm
|| !profile
->xattr_count
)
322 /* transition from exec match to xattr set */
323 state
= aa_dfa_outofband_transition(profile
->xmatch
, state
);
324 d
= bprm
->file
->f_path
.dentry
;
326 for (i
= 0; i
< profile
->xattr_count
; i
++) {
327 size
= vfs_getxattr_alloc(d
, profile
->xattrs
[i
], &value
,
328 value_size
, GFP_KERNEL
);
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
337 state
= aa_dfa_null_transition(profile
->xmatch
, state
);
338 /* Check xattr value */
339 state
= aa_dfa_match_len(profile
->xmatch
, state
, value
,
341 perm
= dfa_user_allow(profile
->xmatch
, state
);
342 if (!(perm
& MAY_EXEC
)) {
347 /* transition to next element */
348 state
= aa_dfa_outofband_transition(profile
->xmatch
, state
);
351 * No xattr match, so verify if transition to
352 * next element was valid. IFF so the xattr
359 /* don't count missing optional xattr as matched */
370 * find_attach - do attachment search for unconfined processes
371 * @bprm - binprm structure of transitioning task
372 * @ns: the current namespace (NOT NULL)
373 * @head - profile list to walk (NOT NULL)
374 * @name - to match against (NOT NULL)
375 * @info - info message if there was an error (NOT NULL)
377 * Do a linear search on the profiles in the list. There is a matching
378 * preference where an exact match is preferred over a name which uses
379 * expressions to match, and matching expressions with the greatest
380 * xmatch_len are preferred.
382 * Requires: @head not be shared or have appropriate locks held
384 * Returns: label or NULL if no match found
386 static struct aa_label
*find_attach(const struct linux_binprm
*bprm
,
387 struct aa_ns
*ns
, struct list_head
*head
,
388 const char *name
, const char **info
)
390 int candidate_len
= 0, candidate_xattrs
= 0;
391 bool conflict
= false;
392 struct aa_profile
*profile
, *candidate
= NULL
;
399 list_for_each_entry_rcu(profile
, head
, base
.list
) {
400 if (profile
->label
.flags
& FLAG_NULL
&&
401 &profile
->label
== ns_unconfined(profile
->ns
))
404 /* Find the "best" matching profile. Profiles must
405 * match the path and extended attributes (if any)
406 * associated with the file. A more specific path
407 * match will be preferred over a less specific one,
408 * and a match with more matching extended attributes
409 * will be preferred over one with fewer. If the best
410 * match has both the same level of path specificity
411 * and the same number of matching extended attributes
412 * as another profile, signal a conflict and refuse to
415 if (profile
->xmatch
) {
416 unsigned int state
, count
;
419 state
= aa_dfa_leftmatch(profile
->xmatch
, DFA_START
,
421 perm
= dfa_user_allow(profile
->xmatch
, state
);
422 /* any accepting state means a valid match. */
423 if (perm
& MAY_EXEC
) {
426 if (count
< candidate_len
)
429 if (bprm
&& profile
->xattr_count
) {
430 long rev
= READ_ONCE(ns
->revision
);
432 if (!aa_get_profile_not0(profile
))
435 ret
= aa_xattrs_match(bprm
, profile
,
438 aa_put_profile(profile
);
440 READ_ONCE(ns
->revision
))
444 * Fail matching if the xattrs don't
451 * TODO: allow for more flexible best match
453 * The new match isn't more specific
454 * than the current best match
456 if (count
== candidate_len
&&
457 ret
<= candidate_xattrs
) {
458 /* Match is equivalent, so conflict */
459 if (ret
== candidate_xattrs
)
464 /* Either the same length with more matching
465 * xattrs, or a longer match
468 candidate_len
= profile
->xmatch_len
;
469 candidate_xattrs
= ret
;
472 } else if (!strcmp(profile
->base
.name
, name
)) {
474 * old exact non-re match, without conditionals such
475 * as xattrs. no more searching required
482 if (!candidate
|| conflict
) {
484 *info
= "conflicting profile attachments";
490 candidate
= aa_get_newest_profile(candidate
);
493 return &candidate
->label
;
496 static const char *next_name(int xtype
, const char *name
)
502 * x_table_lookup - lookup an x transition name via transition table
503 * @profile: current profile (NOT NULL)
504 * @xindex: index into x transition table
505 * @name: returns: name tested to find label (NOT NULL)
507 * Returns: refcounted label, or NULL on failure (MAYBE NULL)
509 struct aa_label
*x_table_lookup(struct aa_profile
*profile
, u32 xindex
,
512 struct aa_label
*label
= NULL
;
513 u32 xtype
= xindex
& AA_X_TYPE_MASK
;
514 int index
= xindex
& AA_X_INDEX_MASK
;
518 /* index is guaranteed to be in range, validated at load time */
519 /* TODO: move lookup parsing to unpack time so this is a straight
520 * index into the resultant label
522 for (*name
= profile
->file
.trans
.table
[index
]; !label
&& *name
;
523 *name
= next_name(xtype
, *name
)) {
524 if (xindex
& AA_X_CHILD
) {
525 struct aa_profile
*new_profile
;
526 /* release by caller */
527 new_profile
= aa_find_child(profile
, *name
);
529 label
= &new_profile
->label
;
532 label
= aa_label_parse(&profile
->label
, *name
, GFP_KERNEL
,
538 /* released by caller */
544 * x_to_label - get target label for a given xindex
545 * @profile: current profile (NOT NULL)
546 * @bprm: binprm structure of transitioning task
547 * @name: name to lookup (NOT NULL)
548 * @xindex: index into x transition table
549 * @lookupname: returns: name used in lookup if one was specified (NOT NULL)
551 * find label for a transition index
553 * Returns: refcounted label or NULL if not found available
555 static struct aa_label
*x_to_label(struct aa_profile
*profile
,
556 const struct linux_binprm
*bprm
,
557 const char *name
, u32 xindex
,
558 const char **lookupname
,
561 struct aa_label
*new = NULL
;
562 struct aa_ns
*ns
= profile
->ns
;
563 u32 xtype
= xindex
& AA_X_TYPE_MASK
;
564 const char *stack
= NULL
;
568 /* fail exec unless ix || ux fallback - handled by caller */
572 /* TODO: fix when perm mapping done at unload */
573 stack
= profile
->file
.trans
.table
[xindex
& AA_X_INDEX_MASK
];
575 /* released by caller */
576 new = x_table_lookup(profile
, xindex
, lookupname
);
580 fallthrough
; /* to X_NAME */
582 if (xindex
& AA_X_CHILD
)
583 /* released by caller */
584 new = find_attach(bprm
, ns
, &profile
->base
.profiles
,
587 /* released by caller */
588 new = find_attach(bprm
, ns
, &ns
->base
.profiles
,
595 if (xindex
& AA_X_INHERIT
) {
596 /* (p|c|n)ix - don't change profile but do
597 * use the newest version
599 *info
= "ix fallback";
600 /* no profile && no error */
601 new = aa_get_newest_label(&profile
->label
);
602 } else if (xindex
& AA_X_UNCONFINED
) {
603 new = aa_get_newest_label(ns_unconfined(profile
->ns
));
604 *info
= "ux fallback";
609 /* base the stack on post domain transition */
610 struct aa_label
*base
= new;
612 new = aa_label_parse(base
, stack
, GFP_KERNEL
, true, false);
618 /* released by caller */
622 static struct aa_label
*profile_transition(struct aa_profile
*profile
,
623 const struct linux_binprm
*bprm
,
624 char *buffer
, struct path_cond
*cond
,
627 struct aa_label
*new = NULL
;
628 const char *info
= NULL
, *name
= NULL
, *target
= NULL
;
629 unsigned int state
= profile
->file
.start
;
630 struct aa_perms perms
= {};
631 bool nonewprivs
= false;
638 error
= aa_path_name(&bprm
->file
->f_path
, profile
->path_flags
, buffer
,
639 &name
, &info
, profile
->disconnected
);
641 if (profile_unconfined(profile
) ||
642 (profile
->label
.flags
& FLAG_IX_ON_NAME_ERROR
)) {
643 AA_DEBUG("name lookup ix on error");
645 new = aa_get_newest_label(&profile
->label
);
647 name
= bprm
->filename
;
651 if (profile_unconfined(profile
)) {
652 new = find_attach(bprm
, profile
->ns
,
653 &profile
->ns
->base
.profiles
, name
, &info
);
655 AA_DEBUG("unconfined attached to new label");
658 AA_DEBUG("unconfined exec no attachment");
659 return aa_get_newest_label(&profile
->label
);
662 /* find exec permissions for name */
663 state
= aa_str_perms(profile
->file
.dfa
, state
, name
, cond
, &perms
);
664 if (perms
.allow
& MAY_EXEC
) {
665 /* exec permission determine how to transition */
666 new = x_to_label(profile
, bprm
, name
, perms
.xindex
, &target
,
668 if (new && new->proxy
== profile
->label
.proxy
&& info
) {
669 /* hack ix fallback - improve how this is detected */
673 info
= "profile transition not found";
674 /* remove MAY_EXEC to audit as failure */
675 perms
.allow
&= ~MAY_EXEC
;
677 } else if (COMPLAIN_MODE(profile
)) {
678 /* no exec permission - learning mode */
679 struct aa_profile
*new_profile
= NULL
;
681 new_profile
= aa_new_null_profile(profile
, false, name
,
685 info
= "could not create null profile";
688 new = &new_profile
->label
;
690 perms
.xindex
|= AA_X_UNSAFE
;
699 if (!(perms
.xindex
& AA_X_UNSAFE
)) {
701 dbg_printk("apparmor: scrubbing environment variables"
702 " for %s profile=", name
);
703 aa_label_printk(new, GFP_KERNEL
);
710 aa_audit_file(profile
, &perms
, OP_EXEC
, MAY_EXEC
, name
, target
, new,
711 cond
->uid
, info
, error
);
712 if (!new || nonewprivs
) {
714 return ERR_PTR(error
);
720 static int profile_onexec(struct aa_profile
*profile
, struct aa_label
*onexec
,
721 bool stack
, const struct linux_binprm
*bprm
,
722 char *buffer
, struct path_cond
*cond
,
725 unsigned int state
= profile
->file
.start
;
726 struct aa_perms perms
= {};
727 const char *xname
= NULL
, *info
= "change_profile onexec";
735 if (profile_unconfined(profile
)) {
736 /* change_profile on exec already granted */
738 * NOTE: Domain transitions from unconfined are allowed
739 * even when no_new_privs is set because this aways results
740 * in a further reduction of permissions.
745 error
= aa_path_name(&bprm
->file
->f_path
, profile
->path_flags
, buffer
,
746 &xname
, &info
, profile
->disconnected
);
748 if (profile_unconfined(profile
) ||
749 (profile
->label
.flags
& FLAG_IX_ON_NAME_ERROR
)) {
750 AA_DEBUG("name lookup ix on error");
753 xname
= bprm
->filename
;
757 /* find exec permissions for name */
758 state
= aa_str_perms(profile
->file
.dfa
, state
, xname
, cond
, &perms
);
759 if (!(perms
.allow
& AA_MAY_ONEXEC
)) {
760 info
= "no change_onexec valid for executable";
763 /* test if this exec can be paired with change_profile onexec.
764 * onexec permission is linked to exec with a standard pairing
765 * exec\0change_profile
767 state
= aa_dfa_null_transition(profile
->file
.dfa
, state
);
768 error
= change_profile_perms(profile
, onexec
, stack
, AA_MAY_ONEXEC
,
771 perms
.allow
&= ~AA_MAY_ONEXEC
;
775 if (!(perms
.xindex
& AA_X_UNSAFE
)) {
777 dbg_printk("apparmor: scrubbing environment "
778 "variables for %s label=", xname
);
779 aa_label_printk(onexec
, GFP_KERNEL
);
786 return aa_audit_file(profile
, &perms
, OP_EXEC
, AA_MAY_ONEXEC
, xname
,
787 NULL
, onexec
, cond
->uid
, info
, error
);
790 /* ensure none ns domain transitions are correctly applied with onexec */
792 static struct aa_label
*handle_onexec(struct aa_label
*label
,
793 struct aa_label
*onexec
, bool stack
,
794 const struct linux_binprm
*bprm
,
795 char *buffer
, struct path_cond
*cond
,
798 struct aa_profile
*profile
;
799 struct aa_label
*new;
808 error
= fn_for_each_in_ns(label
, profile
,
809 profile_onexec(profile
, onexec
, stack
,
810 bprm
, buffer
, cond
, unsafe
));
812 return ERR_PTR(error
);
813 new = fn_label_build_in_ns(label
, profile
, GFP_KERNEL
,
814 aa_get_newest_label(onexec
),
815 profile_transition(profile
, bprm
, buffer
,
819 /* TODO: determine how much we want to loosen this */
820 error
= fn_for_each_in_ns(label
, profile
,
821 profile_onexec(profile
, onexec
, stack
, bprm
,
822 buffer
, cond
, unsafe
));
824 return ERR_PTR(error
);
825 new = fn_label_build_in_ns(label
, profile
, GFP_KERNEL
,
826 aa_label_merge(&profile
->label
, onexec
,
828 profile_transition(profile
, bprm
, buffer
,
835 /* TODO: get rid of GLOBAL_ROOT_UID */
836 error
= fn_for_each_in_ns(label
, profile
,
837 aa_audit_file(profile
, &nullperms
, OP_CHANGE_ONEXEC
,
838 AA_MAY_ONEXEC
, bprm
->filename
, NULL
,
839 onexec
, GLOBAL_ROOT_UID
,
840 "failed to build target label", -ENOMEM
));
841 return ERR_PTR(error
);
845 * apparmor_bprm_creds_for_exec - Update the new creds on the bprm struct
846 * @bprm: binprm for the exec (NOT NULL)
848 * Returns: %0 or error on failure
850 * TODO: once the other paths are done see if we can't refactor into a fn
852 int apparmor_bprm_creds_for_exec(struct linux_binprm
*bprm
)
854 struct aa_task_ctx
*ctx
;
855 struct aa_label
*label
, *new = NULL
;
856 struct aa_profile
*profile
;
858 const char *info
= NULL
;
861 struct path_cond cond
= {
862 file_inode(bprm
->file
)->i_uid
,
863 file_inode(bprm
->file
)->i_mode
866 ctx
= task_ctx(current
);
867 AA_BUG(!cred_label(bprm
->cred
));
870 label
= aa_get_newest_label(cred_label(bprm
->cred
));
873 * Detect no new privs being set, and store the label it
874 * occurred under. Ideally this would happen when nnp
875 * is set but there isn't a good way to do that yet.
877 * Testing for unconfined must be done before the subset test
879 if ((bprm
->unsafe
& LSM_UNSAFE_NO_NEW_PRIVS
) && !unconfined(label
) &&
881 ctx
->nnp
= aa_get_label(label
);
883 /* buffer freed below, name is pointer into buffer */
884 buffer
= aa_get_buffer(false);
890 /* Test for onexec first as onexec override other x transitions. */
892 new = handle_onexec(label
, ctx
->onexec
, ctx
->token
,
893 bprm
, buffer
, &cond
, &unsafe
);
895 new = fn_label_build(label
, profile
, GFP_KERNEL
,
896 profile_transition(profile
, bprm
, buffer
,
901 error
= PTR_ERR(new);
908 /* Policy has specified a domain transitions. If no_new_privs and
909 * confined ensure the transition is to confinement that is subset
910 * of the confinement when the task entered no new privs.
912 * NOTE: Domain transitions from unconfined and to stacked
913 * subsets are allowed even when no_new_privs is set because this
914 * aways results in a further reduction of permissions.
916 if ((bprm
->unsafe
& LSM_UNSAFE_NO_NEW_PRIVS
) &&
917 !unconfined(label
) &&
918 !aa_label_is_unconfined_subset(new, ctx
->nnp
)) {
920 info
= "no new privs";
924 if (bprm
->unsafe
& LSM_UNSAFE_SHARE
) {
925 /* FIXME: currently don't mediate shared state */
929 if (bprm
->unsafe
& (LSM_UNSAFE_PTRACE
)) {
930 /* TODO: test needs to be profile of label to new */
931 error
= may_change_ptraced_domain(new, &info
);
938 dbg_printk("scrubbing environment variables for %s "
939 "label=", bprm
->filename
);
940 aa_label_printk(new, GFP_KERNEL
);
943 bprm
->secureexec
= 1;
946 if (label
->proxy
!= new->proxy
) {
947 /* when transitioning clear unsafe personality bits */
949 dbg_printk("apparmor: clearing unsafe personality "
950 "bits. %s label=", bprm
->filename
);
951 aa_label_printk(new, GFP_KERNEL
);
954 bprm
->per_clear
|= PER_CLEAR_ON_SETID
;
956 aa_put_label(cred_label(bprm
->cred
));
957 /* transfer reference, released when cred is freed */
958 set_cred_label(bprm
->cred
, new);
962 aa_put_buffer(buffer
);
967 error
= fn_for_each(label
, profile
,
968 aa_audit_file(profile
, &nullperms
, OP_EXEC
, MAY_EXEC
,
969 bprm
->filename
, NULL
, new,
970 file_inode(bprm
->file
)->i_uid
, info
,
977 * Functions for self directed profile change
981 /* helper fn for change_hat
983 * Returns: label for hat transition OR ERR_PTR. Does NOT return NULL
985 static struct aa_label
*build_change_hat(struct aa_profile
*profile
,
986 const char *name
, bool sibling
)
988 struct aa_profile
*root
, *hat
= NULL
;
989 const char *info
= NULL
;
992 if (sibling
&& PROFILE_IS_HAT(profile
)) {
993 root
= aa_get_profile_rcu(&profile
->parent
);
994 } else if (!sibling
&& !PROFILE_IS_HAT(profile
)) {
995 root
= aa_get_profile(profile
);
997 info
= "conflicting target types";
1002 hat
= aa_find_child(root
, name
);
1005 if (COMPLAIN_MODE(profile
)) {
1006 hat
= aa_new_null_profile(profile
, true, name
,
1009 info
= "failed null profile create";
1014 aa_put_profile(root
);
1017 aa_audit_file(profile
, &nullperms
, OP_CHANGE_HAT
, AA_MAY_CHANGEHAT
,
1018 name
, hat
? hat
->base
.hname
: NULL
,
1019 hat
? &hat
->label
: NULL
, GLOBAL_ROOT_UID
, info
,
1021 if (!hat
|| (error
&& error
!= -ENOENT
))
1022 return ERR_PTR(error
);
1023 /* if hat && error - complain mode, already audited and we adjust for
1024 * complain mode allow by returning hat->label
1029 /* helper fn for changing into a hat
1031 * Returns: label for hat transition or ERR_PTR. Does not return NULL
1033 static struct aa_label
*change_hat(struct aa_label
*label
, const char *hats
[],
1034 int count
, int flags
)
1036 struct aa_profile
*profile
, *root
, *hat
= NULL
;
1037 struct aa_label
*new;
1039 bool sibling
= false;
1040 const char *name
, *info
= NULL
;
1047 if (PROFILE_IS_HAT(labels_profile(label
)))
1050 /*find first matching hat */
1051 for (i
= 0; i
< count
&& !hat
; i
++) {
1053 label_for_each_in_ns(it
, labels_ns(label
), label
, profile
) {
1054 if (sibling
&& PROFILE_IS_HAT(profile
)) {
1055 root
= aa_get_profile_rcu(&profile
->parent
);
1056 } else if (!sibling
&& !PROFILE_IS_HAT(profile
)) {
1057 root
= aa_get_profile(profile
);
1058 } else { /* conflicting change type */
1059 info
= "conflicting targets types";
1063 hat
= aa_find_child(root
, name
);
1064 aa_put_profile(root
);
1066 if (!COMPLAIN_MODE(profile
))
1067 goto outer_continue
;
1068 /* complain mode succeed as if hat */
1069 } else if (!PROFILE_IS_HAT(hat
)) {
1070 info
= "target not hat";
1072 aa_put_profile(hat
);
1075 aa_put_profile(hat
);
1077 /* found a hat for all profiles in ns */
1082 /* no hats that match, find appropriate error
1084 * In complain mode audit of the failure is based off of the first
1085 * hat supplied. This is done due how userspace interacts with
1089 label_for_each_in_ns(it
, labels_ns(label
), label
, profile
) {
1090 if (!list_empty(&profile
->base
.profiles
)) {
1091 info
= "hat not found";
1096 info
= "no hats defined";
1100 label_for_each_in_ns(it
, labels_ns(label
), label
, profile
) {
1102 * no target as it has failed to be found or built
1104 * change_hat uses probing and should not log failures
1105 * related to missing hats
1107 /* TODO: get rid of GLOBAL_ROOT_UID */
1108 if (count
> 1 || COMPLAIN_MODE(profile
)) {
1109 aa_audit_file(profile
, &nullperms
, OP_CHANGE_HAT
,
1110 AA_MAY_CHANGEHAT
, name
, NULL
, NULL
,
1111 GLOBAL_ROOT_UID
, info
, error
);
1114 return ERR_PTR(error
);
1117 new = fn_label_build_in_ns(label
, profile
, GFP_KERNEL
,
1118 build_change_hat(profile
, name
, sibling
),
1119 aa_get_label(&profile
->label
));
1121 info
= "label build failed";
1124 } /* else if (IS_ERR) build_change_hat has logged error so return new */
1130 * aa_change_hat - change hat to/from subprofile
1131 * @hats: vector of hat names to try changing into (MAYBE NULL if @count == 0)
1132 * @count: number of hat names in @hats
1133 * @token: magic value to validate the hat change
1134 * @flags: flags affecting behavior of the change
1136 * Returns %0 on success, error otherwise.
1138 * Change to the first profile specified in @hats that exists, and store
1139 * the @hat_magic in the current task context. If the count == 0 and the
1140 * @token matches that stored in the current task context, return to the
1141 * top level profile.
1143 * change_hat only applies to profiles in the current ns, and each profile
1144 * in the ns must make the same transition otherwise change_hat will fail.
1146 int aa_change_hat(const char *hats
[], int count
, u64 token
, int flags
)
1148 const struct cred
*cred
;
1149 struct aa_task_ctx
*ctx
= task_ctx(current
);
1150 struct aa_label
*label
, *previous
, *new = NULL
, *target
= NULL
;
1151 struct aa_profile
*profile
;
1152 struct aa_perms perms
= {};
1153 const char *info
= NULL
;
1156 /* released below */
1157 cred
= get_current_cred();
1158 label
= aa_get_newest_cred_label(cred
);
1159 previous
= aa_get_newest_label(ctx
->previous
);
1162 * Detect no new privs being set, and store the label it
1163 * occurred under. Ideally this would happen when nnp
1164 * is set but there isn't a good way to do that yet.
1166 * Testing for unconfined must be done before the subset test
1168 if (task_no_new_privs(current
) && !unconfined(label
) && !ctx
->nnp
)
1169 ctx
->nnp
= aa_get_label(label
);
1171 if (unconfined(label
)) {
1172 info
= "unconfined can not change_hat";
1178 new = change_hat(label
, hats
, count
, flags
);
1181 error
= PTR_ERR(new);
1183 /* already audited */
1187 error
= may_change_ptraced_domain(new, &info
);
1192 * no new privs prevents domain transitions that would
1193 * reduce restrictions.
1195 if (task_no_new_privs(current
) && !unconfined(label
) &&
1196 !aa_label_is_unconfined_subset(new, ctx
->nnp
)) {
1197 /* not an apparmor denial per se, so don't log it */
1198 AA_DEBUG("no_new_privs - change_hat denied");
1203 if (flags
& AA_CHANGE_TEST
)
1207 error
= aa_set_current_hat(new, token
);
1208 if (error
== -EACCES
)
1209 /* kill task in case of brute force attacks */
1211 } else if (previous
&& !(flags
& AA_CHANGE_TEST
)) {
1213 * no new privs prevents domain transitions that would
1214 * reduce restrictions.
1216 if (task_no_new_privs(current
) && !unconfined(label
) &&
1217 !aa_label_is_unconfined_subset(previous
, ctx
->nnp
)) {
1218 /* not an apparmor denial per se, so don't log it */
1219 AA_DEBUG("no_new_privs - change_hat denied");
1224 /* Return to saved label. Kill task if restore fails
1225 * to avoid brute force attacks
1228 error
= aa_restore_previous_label(token
);
1230 if (error
== -EACCES
)
1234 } /* else ignore @flags && restores when there is no saved profile */
1238 aa_put_label(previous
);
1239 aa_put_label(label
);
1245 info
= "failed token match";
1246 perms
.kill
= AA_MAY_CHANGEHAT
;
1249 fn_for_each_in_ns(label
, profile
,
1250 aa_audit_file(profile
, &perms
, OP_CHANGE_HAT
,
1251 AA_MAY_CHANGEHAT
, NULL
, NULL
, target
,
1252 GLOBAL_ROOT_UID
, info
, error
));
1258 static int change_profile_perms_wrapper(const char *op
, const char *name
,
1259 struct aa_profile
*profile
,
1260 struct aa_label
*target
, bool stack
,
1261 u32 request
, struct aa_perms
*perms
)
1263 const char *info
= NULL
;
1267 error
= change_profile_perms(profile
, target
, stack
, request
,
1268 profile
->file
.start
, perms
);
1270 error
= aa_audit_file(profile
, perms
, op
, request
, name
,
1271 NULL
, target
, GLOBAL_ROOT_UID
, info
,
1278 * aa_change_profile - perform a one-way profile transition
1279 * @fqname: name of profile may include namespace (NOT NULL)
1280 * @onexec: whether this transition is to take place immediately or at exec
1281 * @flags: flags affecting change behavior
1283 * Change to new profile @name. Unlike with hats, there is no way
1284 * to change back. If @name isn't specified the current profile name is
1286 * If @onexec then the transition is delayed until
1289 * Returns %0 on success, error otherwise.
1291 int aa_change_profile(const char *fqname
, int flags
)
1293 struct aa_label
*label
, *new = NULL
, *target
= NULL
;
1294 struct aa_profile
*profile
;
1295 struct aa_perms perms
= {};
1296 const char *info
= NULL
;
1297 const char *auditname
= fqname
; /* retain leading & if stack */
1298 bool stack
= flags
& AA_CHANGE_STACK
;
1299 struct aa_task_ctx
*ctx
= task_ctx(current
);
1304 label
= aa_get_current_label();
1307 * Detect no new privs being set, and store the label it
1308 * occurred under. Ideally this would happen when nnp
1309 * is set but there isn't a good way to do that yet.
1311 * Testing for unconfined must be done before the subset test
1313 if (task_no_new_privs(current
) && !unconfined(label
) && !ctx
->nnp
)
1314 ctx
->nnp
= aa_get_label(label
);
1316 if (!fqname
|| !*fqname
) {
1317 aa_put_label(label
);
1318 AA_DEBUG("no profile name");
1322 if (flags
& AA_CHANGE_ONEXEC
) {
1323 request
= AA_MAY_ONEXEC
;
1325 op
= OP_STACK_ONEXEC
;
1327 op
= OP_CHANGE_ONEXEC
;
1329 request
= AA_MAY_CHANGE_PROFILE
;
1333 op
= OP_CHANGE_PROFILE
;
1336 if (*fqname
== '&') {
1338 /* don't have label_parse() do stacking */
1341 target
= aa_label_parse(label
, fqname
, GFP_KERNEL
, true, false);
1342 if (IS_ERR(target
)) {
1343 struct aa_profile
*tprofile
;
1345 info
= "label not found";
1346 error
= PTR_ERR(target
);
1349 * TODO: fixme using labels_profile is not right - do profile
1350 * per complain profile
1352 if ((flags
& AA_CHANGE_TEST
) ||
1353 !COMPLAIN_MODE(labels_profile(label
)))
1355 /* released below */
1356 tprofile
= aa_new_null_profile(labels_profile(label
), false,
1357 fqname
, GFP_KERNEL
);
1359 info
= "failed null profile create";
1363 target
= &tprofile
->label
;
1368 * self directed transitions only apply to current policy ns
1369 * TODO: currently requiring perms for stacking and straight change
1370 * stacking doesn't strictly need this. Determine how much
1371 * we want to loosen this restriction for stacking
1375 error
= fn_for_each_in_ns(label
, profile
,
1376 change_profile_perms_wrapper(op
, auditname
,
1377 profile
, target
, stack
,
1380 /* auditing done in change_profile_perms_wrapper */
1386 /* check if tracing task is allowed to trace target domain */
1387 error
= may_change_ptraced_domain(target
, &info
);
1388 if (error
&& !fn_for_each_in_ns(label
, profile
,
1389 COMPLAIN_MODE(profile
)))
1392 /* TODO: add permission check to allow this
1393 * if ((flags & AA_CHANGE_ONEXEC) && !current_is_single_threaded()) {
1394 * info = "not a single threaded task";
1399 if (flags
& AA_CHANGE_TEST
)
1402 /* stacking is always a subset, so only check the nonstack case */
1404 new = fn_label_build_in_ns(label
, profile
, GFP_KERNEL
,
1405 aa_get_label(target
),
1406 aa_get_label(&profile
->label
));
1408 * no new privs prevents domain transitions that would
1409 * reduce restrictions.
1411 if (task_no_new_privs(current
) && !unconfined(label
) &&
1412 !aa_label_is_unconfined_subset(new, ctx
->nnp
)) {
1413 /* not an apparmor denial per se, so don't log it */
1414 AA_DEBUG("no_new_privs - change_hat denied");
1420 if (!(flags
& AA_CHANGE_ONEXEC
)) {
1421 /* only transition profiles in the current ns */
1423 new = aa_label_merge(label
, target
, GFP_KERNEL
);
1424 if (IS_ERR_OR_NULL(new)) {
1425 info
= "failed to build target label";
1429 error
= PTR_ERR(new);
1434 error
= aa_replace_current_label(new);
1441 /* full transition will be built in exec path */
1442 error
= aa_set_current_onexec(target
, stack
);
1446 error
= fn_for_each_in_ns(label
, profile
,
1447 aa_audit_file(profile
, &perms
, op
, request
, auditname
,
1448 NULL
, new ? new : target
,
1449 GLOBAL_ROOT_UID
, info
, error
));
1453 aa_put_label(target
);
1454 aa_put_label(label
);