On Fri, Jan 06, 2012 at 09:53:17AM -0800, John Johansen wrote: > Add the library interface and untility functions to provide access to > profile stacking. This allows a task to have its confinement based off > of multiple profiles. > > Signed-off-by: John Johansen <[email protected]> > --- > libraries/libapparmor/doc/Makefile.am | 3 +- > libraries/libapparmor/doc/aa_stackcon.pod | 120 +++++++++++++++++++++++ > libraries/libapparmor/src/apparmor.h | 2 + > libraries/libapparmor/src/kernel_interface.c | 43 ++++++++ > libraries/libapparmor/src/libapparmor.map | 8 ++ > libraries/libapparmor/swig/SWIG/libapparmor.i | 2 + > utils/Makefile | 2 +- > utils/aa-stack | 129 > +++++++++++++++++++++++++ > utils/aa-stack.pod | 100 +++++++++++++++++++ > 9 files changed, 407 insertions(+), 2 deletions(-) > create mode 100644 libraries/libapparmor/doc/aa_stackcon.pod > create mode 100644 utils/aa-stack > create mode 100644 utils/aa-stack.pod > > diff --git a/libraries/libapparmor/doc/Makefile.am > b/libraries/libapparmor/doc/Makefile.am > index e21a075..dda2c88 100644 > --- a/libraries/libapparmor/doc/Makefile.am > +++ b/libraries/libapparmor/doc/Makefile.am > @@ -2,7 +2,8 @@ > > POD2MAN = pod2man > > -man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2 > aa_find_mountpoint.2 > +man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2 > aa_find_mountpoint.2\ > + aa_stackcon.2 > > PODS = $(subst .2,.pod,$(man_MANS)) > > diff --git a/libraries/libapparmor/doc/aa_stackcon.pod > b/libraries/libapparmor/doc/aa_stackcon.pod > new file mode 100644 > index 0000000..0efe738 > --- /dev/null > +++ b/libraries/libapparmor/doc/aa_stackcon.pod > @@ -0,0 +1,120 @@ > +# 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_stackcon, aa_stackcon_onexec - add a new profile layer to a task > + > +=head1 SYNOPSIS > + > +B<#include E<lt>sys/apparmor.hE<gt>> > + > +B<int aa_stackcon(const char *profile);> > + > +B<int aa_stackcon_onexec(const char *profile);> > + > +Link with B<-lapparmor> when compiling. > + > +=head1 DESCRIPTION > + > +The aa_stackcon() function Setups a new layer in the profile context stack,
s/Setups/sets up/ ? > +and set the specified I<profile> as the top of the stack. This tightens the s/set/sets/ ? > +calling task's current mediation to the intersection of the previous > +confinement and the new I<profile> that is being added to the context stack. > + > +The namespace of the specified I<profile> defines the current namespace for > +the task, and hence determines which namespace policy administration is > +done in. If the namespace is different from the previous namespace, > +the profile(s) from that namespace remain on the task as part of its > +confinement. > + > +If the specified I<profile> is the same as a profile already confining the > +task (and is in the same policy namespace), the I<profile> will merge > +with the existing profile and a new layer will not be added to the > confinement > +stack. > + > +The specified I<profile> can be a compound name including a namespace prefix. > +If a namespace prefix is included, the specified profile will be searched > +for in the specified namespace instead of the current namespace. If only > +a namespace prefix is specified then name of the current profile will be > +searched for in the specified namespace. The there is more than a single s/The there/If there/ ? > +profile confining the task, the name of the profile that defines the current > +namespace will be used. > + > +Once a new stacking level has been created there is no way to undo it. > Except > +to remove all profiles confining the task from the system. s/it. Except/it, except/ ? (Otherwise the second sentence is just a sentence fragment.) > + > +Open file descriptors may have to be revalidated after the stacking to > +account for the new mediation controls on the task. > + > +The aa_stackcon_onexec() function is like the aa_stackcon() function except > +it specifies that the the stacking transition should take place on the > +next exec instead of immediately. The delayed stacking takes precedence > +over any exec transition rules within the confining profile. A separate question from this patch, but how are threads affected by this? For example, if one thread calls aa_stackcon() and another thread calls exec(), will it have the aa_stackcon_onexec() applied to it? If a process calls aa_stackcon_onexec() and then makes a clone() call, what will the behavior of subsequent exec()s be? > + > +Delaying the stacking boundry has a couple of advantages: it can reduce > +profile complexity 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> > + > +The apparmor kernel module is not loaded 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 I<profile> or namespace does not exist. > + > +=item B<EACCES> > + > +The task does not have sufficient permissions to add a layer to it context > +stack. > + > +=back > + > +=head1 BUGS > + > +None known. If you find any, please report them at > +L<http://https://bugs.launchpad.net/apparmor/+filebug>. Note that using > +aa_stackcon(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 > + > +aa-stack(8), apparmor(7), apparmor.d(5), apparmor_parser(8), and > +L<http://wiki.apparmor.net>. > + > +=cut > diff --git a/libraries/libapparmor/src/apparmor.h > b/libraries/libapparmor/src/apparmor.h > index c93bee8..9adb63f 100644 > --- a/libraries/libapparmor/src/apparmor.h > +++ b/libraries/libapparmor/src/apparmor.h > @@ -36,6 +36,8 @@ extern int (change_hat)(const char *subprofile, unsigned > int magic_token); > extern int aa_change_hat(const char *subprofile, unsigned long magic_token); > extern int aa_change_profile(const char *profile); > extern int aa_change_onexec(const char *profile); > +extern int aa_stackcon(const char *profile); > +extern int aa_stackcon_onexec(const char *profile); > > extern int aa_change_hatv(const char *subprofiles[], unsigned long token); > extern int (aa_change_hat_vargs)(unsigned long token, int count, ...); > diff --git a/libraries/libapparmor/src/kernel_interface.c > b/libraries/libapparmor/src/kernel_interface.c > index 33fdda9..bc29d99 100644 > --- a/libraries/libapparmor/src/kernel_interface.c > +++ b/libraries/libapparmor/src/kernel_interface.c > @@ -408,6 +408,49 @@ int aa_change_onexec(const char *profile) > return rc; > } > > +int aa_stackcon(const char *profile) > +{ > + char *buf = NULL; > + int len; > + int rc; > + > + if (!profile) { > + errno = EINVAL; > + return -1; > + } > + > + len = asprintf(&buf, "stackcon %s", profile); > + if (len < 0) > + return -1; > + > + rc = setprocattr(aa_gettid(), "current", buf, len); > + > + free(buf); > + return rc; > +} > + > +int aa_stackcon_onexec(const char *profile) > +{ > + char *buf = NULL; > + int len; > + int rc; > + > + if (!profile) { > + errno = EINVAL; > + return -1; > + } > + > + len = asprintf(&buf, "stackcon %s", profile); > + if (len < 0) > + return -1; > + > + rc = setprocattr(aa_gettid(), "exec", buf, len); > + > + free(buf); > + return rc; > +} > + > + > /* create an alias for the old change_hat@IMMUNIX_1.0 symbol */ > extern typeof((__change_hat)) __old_change_hat __attribute__((alias > ("__change_hat"))); > symbol_version(__old_change_hat, change_hat, IMMUNIX_1.0); > diff --git a/libraries/libapparmor/src/libapparmor.map > b/libraries/libapparmor/src/libapparmor.map > index 444278e..b5ff2ca 100644 > --- a/libraries/libapparmor/src/libapparmor.map > +++ b/libraries/libapparmor/src/libapparmor.map > @@ -35,3 +35,11 @@ APPARMOR_1.1 { > local: > *; > } APPARMOR_1.0; > + > +APPARMOR_3.0 { > + global: > + aa_stackcon; > + aa_stackcon_onexec; > + local: > + *; > +} APPARMOR_1.1; > diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i > b/libraries/libapparmor/swig/SWIG/libapparmor.i > index f0ebf5a..9cd6d5c 100644 > --- a/libraries/libapparmor/swig/SWIG/libapparmor.i > +++ b/libraries/libapparmor/swig/SWIG/libapparmor.i > @@ -18,6 +18,8 @@ extern int aa_find_mountpoint(char **mnt); > extern int aa_change_hat(const char *subprofile, unsigned long magic_token); > extern int aa_change_profile(const char *profile); > extern int aa_change_onexec(const char *profile); > +extern int aa_stackcon(const char *profile); > +extern int aa_stackcon_onexec(const char *profile); > extern int aa_change_hatv(const char *subprofiles[], unsigned long token); > extern int aa_change_hat_vargs(unsigned long token, int count, ...); > extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int > len, > diff --git a/utils/Makefile b/utils/Makefile > index f4f8707..5baa26d 100644 > --- a/utils/Makefile > +++ b/utils/Makefile > @@ -28,7 +28,7 @@ endif > > MODDIR = Immunix > PERLTOOLS = aa-genprof aa-logprof aa-autodep aa-audit aa-complain aa-enforce > \ > - aa-unconfined aa-notify aa-disable aa-exec > + aa-unconfined aa-notify aa-disable aa-exec aa-stack > TOOLS = ${PERLTOOLS} aa-decode aa-status > MODULES = ${MODDIR}/AppArmor.pm ${MODDIR}/Repository.pm \ > ${MODDIR}/Config.pm ${MODDIR}/Severity.pm > diff --git a/utils/aa-stack b/utils/aa-stack > new file mode 100644 > index 0000000..e147715 > --- /dev/null > +++ b/utils/aa-stack > @@ -0,0 +1,129 @@ > +#!/usr/bin/perl > +# ------------------------------------------------------------------ > +# > +# Copyright (C) 2009-2011 Canonical Ltd. > +# > +# This program is free software; you can redistribute it and/or > +# modify it under the terms of version 2 of the GNU General Public > +# License published by the Free Software Foundation. > +# > +# ------------------------------------------------------------------ > + > +use strict; > +use warnings; > +use Errno; > + > +require LibAppArmor; > +require POSIX; > +require Time::Local; > +require File::Basename; > + > +my $opt_d = ''; > +my $opt_h = ''; > +my $opt_p = ''; > +my $opt_n = ''; > +my $opt_i = ''; > +my $opt_v = ''; > +my $opt_f = ''; > + > +sub _warn { > + my $msg = $_[0]; > + print STDERR "aa-stack: WARN: $msg\n"; > +} > +sub _error { > + my $msg = $_[0]; > + print STDERR "aa-stack: ERROR: $msg\n"; > + exit 1 > +} > + > +sub _debug { > + $opt_d or return; > + my $msg = $_[0]; > + print STDERR "aa-stack: DEBUG: $msg\n"; > +} > + > +sub _verbose { > + $opt_v or return; > + my $msg = $_[0]; > + print STDERR "$msg\n"; > +} > + > +sub usage() { > + my $s = <<'EOF'; > +USAGE: aa-stack [OPTIONS] <prog> <args> > + > +Confine <prog> with a new confinement context that is based off of the old > +context with a new layer set to PROFILE. > + > +OPTIONS: > + -p PROFILE, --profile=PROFILE PROFILE to confine <prog> with > + -n NAMESPACE, --namespace=NAMESPACE NAMESPACE to confine <prog> in > + -f FILE, --file=FILE file to load a profile from before > stacking > + -i, --immediate change profile immediately instead of at exec > + -v, --verbose show messages with stats > + -h, --help display this help > + > +EOF > + print $s; > +} > + > +use Getopt::Long; > + > +GetOptions( > + 'debug|d' => \$opt_d, > + 'help|h' => \$opt_h, > + 'profile|p=s' => \$opt_p, > + 'namespace|n=s' => \$opt_n, > + 'file|f=s' => \$opt_f, > + 'immediate|i' => \$opt_i, > + 'verbose|v' => \$opt_v, > +); > + > +if ($opt_h) { > + usage(); > + exit(0); > +} > + > +if ($opt_n || $opt_p) { > + my $test; > + my $prof; > + > + if ($opt_n) { > + $prof = ":$opt_n:"; > + } > + > + $prof .= $opt_p; > + > + if ($opt_f) { > + my $ns = ""; > + if ($opt_n) { > + $ns = "-n $opt_n"; > + } > + system("apparmor_parser $ns -f $opt_f") == 0 Same issue for system() as with aa-exec here > + or _error("aborting could not load $opt_f"); > + } > + > + if ($opt_i) { > + _verbose("aa_stackcon(\"$prof\")"); > + $test = LibAppArmor::aa_stackcon($prof); > + _debug("$test = aa_stackcon(\"$prof\"); $!"); > + } else { > + _verbose("aa_stackcon_onexec(\"$prof\")"); > + $test = LibAppArmor::aa_stackcon_onexec($prof); > + _debug("$test = aa_stackcon_onexec(\"$prof\"); $!"); > + } > + > + if ($test != 0) { > + if ($!{ENOENT} || $!{EACCESS}) { > + my $pre = ($opt_p) ? "profile" : "namespace"; > + _error("$pre \'$prof\' does not exist\n"); > + } elsif ($!{EINVAL}) { > + _error("AppArmor interface not available\n"); > + } else { > + _error("$!\n"); > + } > + } > +} > + > +_verbose("exec @ARGV"); > +exec @ARGV; > diff --git a/utils/aa-stack.pod b/utils/aa-stack.pod > new file mode 100644 > index 0000000..fa7e9c9 > --- /dev/null > +++ b/utils/aa-stack.pod > @@ -0,0 +1,100 @@ > +# 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 adheres 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 - setup in new layer in the profile context stack, and confine the "setup in new layer in the profile context stack" sounds awkward to me > +program with the specified profile as the top of the stack. > + > + > +=head1 SYNOPSIS > + > +B<aa-stack> [options] [I<E<lt>executableE<gt>> ...] > + > +=head1 DESCRIPTION > + > +B<aa-stack> is used to launch a program confined by the by the current s/by the by the/by the/ > +context plus a new layer with the specified profile as the intial confinement > +for the new layer in the confinement stack. > + > +If a namespace and profile are specified the profile within the specified > +namespace is used. If only a profile is specified then the tasks current > +namespace is used. If only a namespace is specified then the current* > profile > +name is used in the new namespace. If neither a profile or namespace is > defined > +then executable is run from the current confinement. > + > +The program is subject to mediation by all layers in the new context, and > +if a permission request is denied by any layer of the context the request > will > +be denied. > + > +When switching to a new namespace if the unconfined state is desired both > +then -p unconfined should be used. "is desired both" ? > + > +* The current profile name is based off of the top profile on the stack, ie. > + the last profile/namespace combination added, or its decendent after > + exec transitions. > + > +=head1 OPTIONS > +B<aa-stack> accepts the following arguments: > + > +=over 4 > + > +=item -p PROFILE, --profile=PROFILE > + > +confine I<E<lt>executableE<gt>> with PROFILE. If the PROFILE is not specified > +use the current profile name (likely unconfined). > + > +=item -n NAMESPACE, --namespace=NAMESPACE > + > +use profiles in NAMESPACE. This will result in confinement transitioning > +to using the new profile namespace. > + > +=item -f FILE, --file=FILE > + > +a file or directory containing profiles to load before performing the stack. > + > +=item -i, --immediate > + > +transition to PROFILE before doing executing I<E<lt>executableE<gt>>. This > +subjects the running of I<E<lt>executableE<gt>> to the exec transition rules > +of the current profile. > + > +=item -v, --verbose > + > +show commands being performed > + > +=item -d, --debug > + > +show commands and error codes > + > +=head1 BUGS > + > +If you find any bugs, please report them at > +L<http://https://bugs.launchpad.net/apparmor/+filebug>. > + > +=head1 SEE ALSO > + > +aa-confine(8), aa-namespace(8), apparmor(7), apparmor-stacking(7), > +apparmor.d(5), aa_stackcon(3), aa_stackcon_onexec(3) and > +L<http://wiki.apparmor.net>. > + > +=cut -- Steve Beattie <[email protected]> http://NxNW.org/~steve/
signature.asc
Description: Digital signature
-- AppArmor mailing list [email protected] Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
