[apparmor] [PATCH 2/3] Add userspace support for stacking

John Johansen john.johansen at canonical.com
Fri Jan 6 17:53:17 UTC 2012


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 <john.johansen at canonical.com>
---
 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,
+and set the specified I<profile> as the top of the stack.  This tightens the
+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
+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.
+
+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.
+
+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 at 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
+	   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
+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
+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.
+
+* 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
-- 
1.7.7.3




More information about the AppArmor mailing list