[apparmor] [PATCH 1/2] libapparmor: Create man page for aa_stack_profile()/aa_stack_onexec()

John Johansen john.johansen at canonical.com
Thu Feb 25 11:55:24 UTC 2016


On 02/12/2016 04:06 PM, Tyler Hicks wrote:
> Modeled after the aa_change_profile(2) man page, this profile defines
> the libapparmor and kernel interfaces for the in-progress profile
> stacking feature.
> 
> Signed-off-by: Tyler Hicks <tyhicks at canonical.com>

Acked-by: John Johansen <john.johansen at canonical.com>

> ---
>  libraries/libapparmor/doc/Makefile.am          |   2 +-
>  libraries/libapparmor/doc/aa_stack_profile.pod | 221 +++++++++++++++++++++++++
>  2 files changed, 222 insertions(+), 1 deletion(-)
>  create mode 100644 libraries/libapparmor/doc/aa_stack_profile.pod
> 
> diff --git a/libraries/libapparmor/doc/Makefile.am b/libraries/libapparmor/doc/Makefile.am
> index 90cc149..0811e23 100644
> --- a/libraries/libapparmor/doc/Makefile.am
> +++ b/libraries/libapparmor/doc/Makefile.am
> @@ -5,7 +5,7 @@ PODCHECKER = podchecker
>  
>  if ENABLE_MAN_PAGES
>  
> -man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2 aa_find_mountpoint.2 aa_splitcon.3 aa_query_label.2 aa_features.3 aa_kernel_interface.3 aa_policy_cache.3
> +man_MANS = aa_change_hat.2 aa_change_profile.2 aa_stack_profile.2 aa_getcon.2 aa_find_mountpoint.2 aa_splitcon.3 aa_query_label.2 aa_features.3 aa_kernel_interface.3 aa_policy_cache.3
>  
>  PODS = $(subst .2,.pod,$(man_MANS)) $(subst .3,.pod,$(man_MANS))
>  
> diff --git a/libraries/libapparmor/doc/aa_stack_profile.pod b/libraries/libapparmor/doc/aa_stack_profile.pod
> new file mode 100644
> index 0000000..4396148
> --- /dev/null
> +++ b/libraries/libapparmor/doc/aa_stack_profile.pod
> @@ -0,0 +1,221 @@
> +# This publication is intellectual property of Canonical Ltd. Its contents
> +# can be duplicated, either in part or in whole, provided that a copyright
> +# label is visibly located on each copy.
> +#
> +# All information found in this book has been compiled with utmost
> +# attention to detail. However, this does not guarantee complete accuracy.
> +# Neither Canonical Ltd, the authors, nor the translators shall be held
> +# liable for possible errors or the consequences thereof.
> +#
> +# Many of the software and hardware descriptions cited in this book
> +# are registered trademarks. All trade names are subject to copyright
> +# restrictions and may be registered trade marks. Canonical Ltd.
> +# essentially adhere to the manufacturer's spelling.
> +#
> +# Names of products and trademarks appearing in this book (with or without
> +# specific notation) are likewise subject to trademark and trade protection
> +# laws and may thus fall under copyright restrictions.
> +#
> +
> +
> +=pod
> +
> +=head1 NAME
> +
> +aa_stack_profile, aa_stack_onexec - combine multiple profiles to confine a task
> +
> +=head1 SYNOPSIS
> +
> +B<#include E<lt>sys/apparmor.hE<gt>>
> +
> +B<int aa_stack_profile(const char *profile);>
> +
> +B<int aa_stack_onexec(const char *profile);>
> +
> +Link with B<-lapparmor> when compiling.
> +
> +=head1 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
> +aa_change_profile(2), there is always the possibility that the new profile is
> +more permissive than the old profile but that possibility is eliminated when
> +using aa_stack_profile().
> +
> +To stack a profile with the current confinement context, a task can use the
> +aa_stack_profile() function. The I<profile> parameter is a NUL-terminated
> +string indicating a profile name that should be stacked with the current
> +confinement.
> +
> +Calling aa_stack_profile("profile_a") while unconfined is equivalent to calling
> +aa_change_profile("profile_a") since the intersection of unconfined and
> +"profile_a" is "profile_a". Calling aa_stack_profile("profile_b") while
> +confined by "profile_a" results in the task's confinement to be the
> +intersection of "profile_a" and "profile_b". The resulting confinement context
> +will be represented as "profile_a//&profile_b" in audit log messages, the
> +return value of aa_getcon(2), etc.
> +
> +Confined programs wanting to use aa_stack_profile() need to have rules
> +permitting stacking the named profile. See apparmor.d(8) for details.
> +
> +Open file descriptors may not be remediated after a call to aa_stack_profile()
> +so the calling program must close(2) open file descriptors to ensure they
> +are not available after calling aa_stack_profile().
> +
> +The aa_stack_onexec() function is like the aa_stack_profile() 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.
> +
> +=head1 RETURN VALUE
> +
> +On success zero is returned. On error, -1 is returned, and
> +errno(3) is set appropriately.
> +
> +=head1 ERRORS
> +
> +=over 4
> +
> +=item B<EINVAL>
> +
> +AppArmor is not loaded, neither a profile nor a namespace was specified,
> +or the communication via the F</proc/*/attr/current> file did not conform
> +to protocol.
> +
> +=item B<ENOMEM>
> +
> +Insufficient kernel memory was available.
> +
> +=item B<ENOENT>
> +
> +The specified profile does not exist, or is not visible from the current
> +namespace.
> +
> +=back
> +
> +=head1 NOTES
> +
> +Using aa_stack_profile() 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.
> +
> +To immediately stack a profile named "profile_a", as performed with
> +aa_stack_profile("profile_a"), the equivalent of this shell command can be
> +used:
> +
> + $ echo -n "stackprofile profile_a" > /proc/self/attr/current
> +
> +To stack a profile named "profile_a" at the next exec, as performed with
> +aa_stack_onexec("profile_a"), the equivalent of this shell command can be used:
> +
> + $ echo -n "stackexec profile_a" > /proc/self/attr/exec
> +
> +These raw AppArmor filesystem operations must only be used when using
> +libapparmor is not a viable option.
> +
> +=head1 EXAMPLE
> +
> +The following example shows a simple, if contrived, use of
> +aa_stack_profile().
> +
> + #include <stdlib.h>
> + #include <string.h>
> + #include <sys/apparmor.h>
> + #include <sys/types.h>
> + #include <sys/stat.h>
> + #include <fcntl.h>
> + #include <stdio.h>
> + #include <unistd.h>
> +
> + 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] = '\0';
> +         printf("/etc/passwd: %s\n", buf);
> +         close(fd);
> + }
> + 
> + int main(int argc, char * argv[])
> + {
> +         printf("Before aa_stack_profile():\n");
> +         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():\n");
> +         read_passwd();
> +         _exit(0);
> + }
> +
> +This code example requires a profile similar to the following to be loaded
> +with apparmor_parser(8):
> +
> + # Confine stack_p to be able to read /etc/passwd and aa_stack_profile()
> + # to the 'i_cant_be_trusted_anymore' 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,
> + }
> +
> +As well as the profile to stack:
> +
> + profile i_cant_be_trusted_anymore {
> +     /etc/ld.so.cache      mr,
> +     /lib/ld-*.so*         mrix,
> +     /lib/libc*.so*        mr,
> + }
> +
> +The output when run:
> +
> + $ /tmp/stack_p
> + Before aa_stack_profile():
> + /etc/passwd: root:x:0:
> + After aa_stack_profile():
> + Failure opening /etc/passwd: Permission denied
> + $
> +
> +=head1 BUGS
> +
> +None known. If you find any, please report them at
> +L<https://bugs.launchpad.net/apparmor/+filebug>. Note that using
> +aa_stack_profile(2) without execve(2) provides no memory barriers between
> +different areas of a program; if address space separation is required, then
> +separate processes should be used.
> +
> +=head1 SEE ALSO
> +
> +apparmor(7), apparmor.d(5), apparmor_parser(8), aa_change_profile(2),
> +aa_getcon(2) and L<http://wiki.apparmor.net>.
> +
> +=cut
> 




More information about the AppArmor mailing list