.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "AA_STACK_PROFILE 2" .TH AA_STACK_PROFILE 2 "2016-03-18" "AppArmor 2.10.95" "AppArmor" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" aa_stack_profile, aa_stack_onexec \- combine multiple profiles to confine a task .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fB#include \fR .PP \&\fBint aa_stack_profile(const char *profile);\fR .PP \&\fBint aa_stack_onexec(const char *profile);\fR .PP Link with \fB\-lapparmor\fR when compiling. .SH "DESCRIPTION" .IX Header "DESCRIPTION" AppArmor supports stacking two or more profiles when confining a task. The result is an intersection of all profiles which are stacked. Stacking profiles together is desirable when wanting to ensure that confinement will never become more permissive. When changing between two profiles, as performed with \&\fIaa_change_profile\fR\|(2), there is always the possibility that the new profile is more permissive than the old profile but that possibility is eliminated when using \fIaa_stack_profile()\fR. .PP To stack a profile with the current confinement context, a task can use the \&\fIaa_stack_profile()\fR function. The \fIprofile\fR parameter is a NUL-terminated string indicating a profile name that should be stacked with the current confinement. .PP Calling aa_stack_profile(\*(L"profile_a\*(R") while unconfined is equivalent to calling aa_change_profile(\*(L"profile_a\*(R") since the intersection of unconfined and \&\*(L"profile_a\*(R" is \*(L"profile_a\*(R". Calling aa_stack_profile(\*(L"profile_b\*(R") while confined by \*(L"profile_a\*(R" results in the task's confinement to be the intersection of \*(L"profile_a\*(R" and \*(L"profile_b\*(R". The resulting confinement context will be represented as \*(L"profile_a//&profile_b\*(R" in audit log messages, the return value of \fIaa_getcon\fR\|(2), etc. .PP Confined programs wanting to use \fIaa_stack_profile()\fR need to have rules permitting stacking the named profile. See \fIapparmor.d\fR\|(8) for details. .PP Open file descriptors may not be remediated after a call to \fIaa_stack_profile()\fR so the calling program must \fIclose\fR\|(2) open file descriptors to ensure they are not available after calling \fIaa_stack_profile()\fR. .PP The \fIaa_stack_onexec()\fR function is like the \fIaa_stack_profile()\fR function except it specifies that the stacking should take place on the next exec instead of immediately. The delayed profile change takes precedence over any exec transition rules within the confining profile. Delaying the stacking boundary has a couple of advantages, it removes the need for stub transition profiles and the exec boundary is a natural security layer where potentially sensitive memory is unmapped. .SH "RETURN VALUE" .IX Header "RETURN VALUE" On success zero is returned. On error, \-1 is returned, and \&\fIerrno\fR\|(3) is set appropriately. .SH "ERRORS" .IX Header "ERRORS" .IP "\fB\s-1EINVAL\s0\fR" 4 .IX Item "EINVAL" AppArmor is not loaded, neither a profile nor a namespace was specified, or the communication via the \fI/proc/*/attr/current\fR file did not conform to protocol. .IP "\fB\s-1ENOMEM\s0\fR" 4 .IX Item "ENOMEM" Insufficient kernel memory was available. .IP "\fB\s-1ENOENT\s0\fR" 4 .IX Item "ENOENT" The specified profile does not exist, or is not visible from the current namespace. .SH "NOTES" .IX Header "NOTES" Using \fIaa_stack_profile()\fR and related libapparmor functions are the only way to ensure compatibility between varying kernel versions. However, there may be some situations where libapparmor is not available and directly interacting with the AppArmor filesystem is required to stack a profile. .PP To immediately stack a profile named \*(L"profile_a\*(R", as performed with aa_stack_profile(\*(L"profile_a\*(R"), the equivalent of this shell command can be used: .PP .Vb 1 \& $ echo \-n "stackprofile profile_a" > /proc/self/attr/current .Ve .PP To stack a profile named \*(L"profile_a\*(R" at the next exec, as performed with aa_stack_onexec(\*(L"profile_a\*(R"), the equivalent of this shell command can be used: .PP .Vb 1 \& $ echo \-n "stackexec profile_a" > /proc/self/attr/exec .Ve .PP These raw AppArmor filesystem operations must only be used when using libapparmor is not a viable option. .SH "EXAMPLE" .IX Header "EXAMPLE" The following example shows a simple, if contrived, use of \&\fIaa_stack_profile()\fR. .PP .Vb 8 \& #include \& #include \& #include \& #include \& #include \& #include \& #include \& #include \& \& static void read_passwd() \& { \& int fd; \& char buf[10]; \& \& if ((fd=open("/etc/passwd", O_RDONLY)) < 0) { \& perror("Failure opening /etc/passwd"); \& _exit(1); \& } \& \& /* Verify that we can read /etc/passwd */ \& memset(&buf, 0, 10); \& if (read(fd, &buf, 10) == \-1) { \& perror("Failure reading /etc/passwd"); \& _exit(1); \& } \& buf[9] = \*(Aq\e0\*(Aq; \& printf("/etc/passwd: %s\en", buf); \& close(fd); \& } \& \& int main(int argc, char * argv[]) \& { \& printf("Before aa_stack_profile():\en"); \& read_passwd(); \& \& /* stack the "i_cant_be_trusted_anymore" profile, which \& * should not have read access to /etc/passwd. */ \& if (aa_stack_profile("i_cant_be_trusted_anymore") < 0) { \& perror("Failure changing profile \-\- aborting"); \& _exit(1); \& } \& \& printf("After aa_stack_profile():\en"); \& read_passwd(); \& _exit(0); \& } .Ve .PP This code example requires a profile similar to the following to be loaded with \fIapparmor_parser\fR\|(8): .PP .Vb 6 \& # Confine stack_p to be able to read /etc/passwd and aa_stack_profile() \& # to the \*(Aqi_cant_be_trusted_anymore\*(Aq profile. \& /tmp/stack_p { \& /etc/ld.so.cache mr, \& /lib/ld\-*.so* mrix, \& /lib/libc*.so* mr, \& \& /etc/passwd r, \& \& # Needed for aa_stack_profile() \& /usr/lib/libapparmor*.so* mr, \& /proc/[0\-9]*/attr/current w, \& } .Ve .PP As well as the profile to stack: .PP .Vb 5 \& profile i_cant_be_trusted_anymore { \& /etc/ld.so.cache mr, \& /lib/ld\-*.so* mrix, \& /lib/libc*.so* mr, \& } .Ve .PP The output when run: .PP .Vb 6 \& $ /tmp/stack_p \& Before aa_stack_profile(): \& /etc/passwd: root:x:0: \& After aa_stack_profile(): \& Failure opening /etc/passwd: Permission denied \& $ .Ve .SH "BUGS" .IX Header "BUGS" None known. If you find any, please report them at . Note that using \&\fIaa_stack_profile\fR\|(2) without \fIexecve\fR\|(2) provides no memory barriers between different areas of a program; if address space separation is required, then separate processes should be used. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fIapparmor\fR\|(7), \fIapparmor.d\fR\|(5), \fIapparmor_parser\fR\|(8), \fIaa_change_profile\fR\|(2), \&\fIaa_getcon\fR\|(2) and .