[apparmor] [PATCH 3/5] Library interface for tasks introspectingconfinement.

Seth Arnold seth.arnold at gmail.com
Thu Jul 21 18:43:18 UTC 2011


Looks cool :)

+aa_getpeercon - get the confinement of a sockets other end (peer)

"socket's"

The BUGS section was copied from another manpage and refers to memory barriers -- not needed here.

The exit(errno) calls in the test program feel brittle -- fprintf() might reset errno internally to zero, thus not exiting with the proper error status.

Thanks John!

-----Original Message-----
From: John Johansen <john.johansen at canonical.com>
Sender: apparmor-bounces at lists.ubuntu.com
Date: Thu, 21 Jul 2011 11:16:36 
To: <apparmor at lists.ubuntu.com>
Subject: [apparmor] [PATCH 3/5] Library interface for tasks introspecting
	confinement.

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
 libraries/libapparmor/doc/Makefile.am         |    2 +-
 libraries/libapparmor/doc/aa_getcon.pod       |  111 +++++++++++++++++++++++++
 libraries/libapparmor/src/apparmor.h          |    8 ++-
 libraries/libapparmor/src/kernel_interface.c  |  111 +++++++++++++++++++++++++
 libraries/libapparmor/src/libapparmor.map     |    4 +
 libraries/libapparmor/swig/SWIG/libapparmor.i |    4 +
 tests/regression/apparmor/Makefile            |    2 +
 tests/regression/apparmor/introspect.c        |   71 ++++++++++++++++
 tests/regression/apparmor/introspect.sh       |   67 +++++++++++++++
 9 files changed, 378 insertions(+), 2 deletions(-)
 create mode 100644 libraries/libapparmor/doc/aa_getcon.pod
 create mode 100644 tests/regression/apparmor/introspect.c
 create mode 100755 tests/regression/apparmor/introspect.sh

diff --git a/libraries/libapparmor/doc/Makefile.am b/libraries/libapparmor/doc/Makefile.am
index 2881709..c3f8f9b 100644
--- a/libraries/libapparmor/doc/Makefile.am
+++ b/libraries/libapparmor/doc/Makefile.am
@@ -2,7 +2,7 @@
 
 POD2MAN = pod2man
 
-man_MANS = aa_change_hat.2 aa_change_profile.2
+man_MANS = aa_change_hat.2 aa_change_profile.2 aa_getcon.2
 
 PODS = $(subst .2,.pod,$(man_MANS))
 
diff --git a/libraries/libapparmor/doc/aa_getcon.pod b/libraries/libapparmor/doc/aa_getcon.pod
new file mode 100644
index 0000000..bf13a11
--- /dev/null
+++ b/libraries/libapparmor/doc/aa_getcon.pod
@@ -0,0 +1,111 @@
+# 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_getprocattr_raw, aa_getprocattr - read and parse procattr data
+
+aa_getcon, aa_gettaskcon - get task confinement information
+
+aa_getpeercon - get the confinement of a sockets other end (peer)
+
+=head1 SYNOPSIS
+
+B<#include E<lt>sys/apparmor.hE<gt>>
+
+B<int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
+			 char **mode);>
+
+B<int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);>
+
+B<int aa_gettaskcon(pid_t target, char **con, char **mode);>
+
+B<int aa_getcon(char **con, char **mode);>
+
+B<int aa_getpeercon(int fd, char **con);>
+
+Link with B<-lapparmor> when compiling.
+
+=head1 DESCRIPTION
+
+The aa_getcon function gets the current AppArmor confinement context for the
+current task.  The confinement context is usually just the name of the AppArmor
+profile restricting the task, but it may include the profile namespace or in
+some cases a set of profile names (known as a stack of profiles).  The returned string *con should be freed using <free()>.
+
+The aa_gettaskcon function is like the aa_getcon function except it will work
+for any arbitrary task in the system.
+
+The aa_getpeercon function is similar to that of aa_gettaskcon except that
+it returns the confinement information for task on the other end of a socket
+connection.
+
+The aa_getprocattr function is the backend for the aa_getcon and aa_gettaskcon
+functions and handles the reading and parsing of the confinement data from
+different arbitrary attr files and returns the processed results in
+an allocated buffer.
+
+The aa_getprocattr_raw() is the backend for the aa_getprocattr function and
+does not handle buffer allocation.
+
+=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/file> did not conform to protocol.
+
+=item B<ENOMEM>
+
+Insufficient kernel memory was available.
+
+=item B<EACCES>
+
+Access to the specified I<file/task> was denied.
+
+=item B<ENOENT>
+
+The specified I<file/task> does not exist or is not visible.
+
+=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_change_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), and
+L<http://wiki.apparmor.net>.
+
+=cut
diff --git a/libraries/libapparmor/src/apparmor.h b/libraries/libapparmor/src/apparmor.h
index b0e6a65..58e95c6 100644
--- a/libraries/libapparmor/src/apparmor.h
+++ b/libraries/libapparmor/src/apparmor.h
@@ -34,10 +34,16 @@ extern int aa_change_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, ...);
 
-/* Protypes for introspecting task confinement */
+/* Protypes for introspecting task confinement
+ * Please see the aa_getcon(2) manpage for information
+ */
 extern int aa_getprocattr_raw(pid_t tid, const char *attr, char *buf, int len,
 			      char **mode);
 extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
+extern int aa_gettaskcon(pid_t target, char **con, char **mode);
+extern int aa_getcon(char **con, char **mode);
+extern int aa_getpeercon_raw(int fd, char *buffer, int *size);
+extern int aa_getpeercon(int fd, char **con);
 
 #define __macroarg_counter(Y...) __macroarg_count1 ( , ##Y)
 #define __macroarg_count1(Y...) __macroarg_count2 (Y, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
diff --git a/libraries/libapparmor/src/kernel_interface.c b/libraries/libapparmor/src/kernel_interface.c
index 67356dc..955944b 100644
--- a/libraries/libapparmor/src/kernel_interface.c
+++ b/libraries/libapparmor/src/kernel_interface.c
@@ -22,6 +22,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
+#include <sys/socket.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <limits.h>
@@ -402,3 +403,113 @@ int (aa_change_hat_vargs)(unsigned long token, int nhats, ...)
 	va_end(ap);
 	return aa_change_hatv(argv, token);
 }
+
+/**
+ * aa_gettaskcon - get the confinement for task @target in an allocated buffer
+ * @target: task to query
+ * @con: pointer to returned buffer with the confinement string
+ * @mode: if provided will point to the mode string in @con if present
+ *
+ * Returns: length of confinement data or -1 on error and sets errno
+ *
+ * Guarentees that @con and @mode are null terminated.  The length returned
+ * is for all data including both @con and @mode, and maybe > than strlen(@con)
+ * even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @con.  @mode is
+ * always contained within @con's buffer and so NEVER do free(@mode)
+ */
+int aa_gettaskcon(pid_t target, char **con, char **mode)
+{
+	return aa_getprocattr(target, "current", con, mode);
+}
+
+/**
+ * aa_getcon - get the confinement for current task in an allocated buffer
+ * @con: pointer to return buffer with the confinement if successful
+ * @mode: if provided will point to the mode string in @con if present
+ *
+ * Returns: length of confinement data or -1 on error and sets errno
+ *
+ * Guarentees that @con and @mode are null terminated.  The length returned
+ * is for all data including both @con and @mode, and may > than strlen(@con)
+ * even if @mode is NULL
+ *
+ * Caller is responsible for freeing the buffer returned in @con.  @mode is
+ * always contained within @con's buffer and so NEVER do free(@mode)
+ */
+int aa_getcon(char **con, char **mode)
+{
+	return aa_gettaskcon(aa_gettid(), con, mode);
+}
+
+
+#ifndef SO_PEERSEC
+#define SO_PEERSEC 31
+#endif
+
+/**
+ * aa_getpeercon_raw - get the confinement of the socket's peer (other end)
+ * @fd: socket to get peer confinement for
+ * @con: pointer to buffer to store confinement string
+ * @size: initially contains size of the buffer, returns size of data read
+ *
+ * Returns: length of confinement data including null termination or -1 on error
+ *          if errno == ERANGE then @size will hold the size needed
+ */
+int aa_getpeercon_raw(int fd, char *buffer, int *size)
+{
+	socklen_t optlen = *size;
+	int rc = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &optlen);
+	if (rc == -1)
+		goto out;
+
+	/* check for null termination */
+	if (buffer[optlen - 1] != 0) {
+		if (optlen < *size) {
+			buffer[optlen] = 0;
+			optlen++;
+		} else {
+			/* buffer needs to be bigger by 1 */
+			rc = -1;
+			errno = ERANGE;
+			optlen++;
+		}
+	}
+out:
+	*size = optlen;
+	return rc;
+}
+
+/**
+ * aa_getpeercon - get the confinement of the socket's peer (other end)
+ * @fd: socket to get peer confinement for
+ * @con: pointer to allocated buffer with the confinement string
+ *
+ * Returns: length of confinement data including null termination or -1 on error
+ *
+ * Caller is responsible for freeing the buffer returned.
+ */
+int aa_getpeercon(int fd, char **con)
+{
+	int rc, size = INITIAL_GUESS_SIZE;
+
+	char *buffer = NULL;
+
+	do {
+		buffer = realloc(buffer, size);
+		if (!buffer)
+			return -1;
+		memset(buffer, 0, size);
+
+		rc = aa_getpeercon_raw(fd, buffer, &size);
+	} while (rc == -1 && errno == ERANGE);
+
+	if (rc == -1) {
+		free(buffer);
+		size = -1;
+	} else
+		*con = buffer;
+
+	return size;
+}
diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map
index a0c1a25..6b209af 100644
--- a/libraries/libapparmor/src/libapparmor.map
+++ b/libraries/libapparmor/src/libapparmor.map
@@ -21,6 +21,10 @@ APPARMOR_1.1 {
         aa_change_hat_vargs;
         aa_change_profile;
         aa_change_onexec;
+        aa_gettaskcon;
+        aa_getcon;
+        aa_getpeercon_raw;
+        aa_getpeercon;
         parse_record;
         free_record;
         aa_getprocattr_raw;
diff --git a/libraries/libapparmor/swig/SWIG/libapparmor.i b/libraries/libapparmor/swig/SWIG/libapparmor.i
index 9c39359..d0f6bd5 100644
--- a/libraries/libapparmor/swig/SWIG/libapparmor.i
+++ b/libraries/libapparmor/swig/SWIG/libapparmor.i
@@ -21,3 +21,7 @@ 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,
 			      char **mode);
 extern int aa_getprocattr(pid_t tid, const char *attr, char **buf, char **mode);
+extern int aa_gettaskcon(pid_t target, char **con, char **mode);
+extern int aa_getcon(char **con, char **mode);
+extern int aa_getpeercon_raw(int fd, char *buffer, int *size);
+extern int aa_getpeercon(int fd, char **con);
diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
index 9403618..b288626 100644
--- a/tests/regression/apparmor/Makefile
+++ b/tests/regression/apparmor/Makefile
@@ -6,6 +6,7 @@
 #	License.
 
 SRC=access.c \
+    introspect.c \
     changeprofile.c \
     changehat.c \
     changehat_fork.c \
@@ -106,6 +107,7 @@ LDLIBS+=$(LIBIMMUNIX)
 EXEC=$(SRC:%.c=%)
 
 TESTS=access \
+      introspect \
       capabilities \
       changeprofile \
       changehat \
diff --git a/tests/regression/apparmor/introspect.c b/tests/regression/apparmor/introspect.c
new file mode 100644
index 0000000..8e1a7d0
--- /dev/null
+++ b/tests/regression/apparmor/introspect.c
@@ -0,0 +1,71 @@
+/*
+ *	Copyright (C) 2002-2005 Novell/SUSE
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation, version 2 of the
+ *	License.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <linux/unistd.h>
+
+#include <sys/apparmor.h>
+
+int main(int argc, char *argv[])
+{
+	int rc; 
+	char *profile, *mode;
+
+        if (argc < 3 || argc > 4) {
+                fprintf(stderr, "usage: %s <task> <expected profile> [<expect mode>]\n",
+                        argv[0]);
+                return 1;
+        }
+
+        if (strcmp(argv[1], "self") == 0){
+		if (aa_getcon(&profile, &mode) == -1) {
+                        fprintf(stderr,
+				"FAIL: introspect_confinement %s failed - %s\n",
+                                argv[1], strerror(errno));
+                        exit(errno);
+		}
+	} else {
+		char *end;
+		pid_t pid = strtol(argv[1], &end, 10);
+		if (end == argv[1] || *end != 0) {
+			fprintf(stderr,
+				"FAIL: query_confinement - invalid pid: %s\n",
+				argv[1]);
+			exit(errno);
+		} else if (aa_gettaskcon(pid, &profile, &mode) == -1) {
+                        fprintf(stderr,
+				"FAIL: query_confinement %s failed - %s\n",
+                                argv[1], strerror(errno));
+                        exit(errno);
+		}
+	}
+	if (strcmp(profile, argv[2]) != 0) {
+		fprintf(stderr,
+			"FAIL: expected confinement \"%s\" != \"%s\"\n", argv[2],
+			profile);
+		exit(1);
+	}
+	if (argv[3] && (!mode || strcmp(mode, argv[3]) != 0)) {
+		fprintf(stderr,
+			"FAIL: expected mode \"%s\" != \"%s\"\n", argv[3],
+			mode ? mode : "(null)");
+		exit(1);
+	}
+	free(profile);
+
+        printf("PASS\n");
+	return 0;
+}
diff --git a/tests/regression/apparmor/introspect.sh b/tests/regression/apparmor/introspect.sh
new file mode 100755
index 0000000..e397da4
--- /dev/null
+++ b/tests/regression/apparmor/introspect.sh
@@ -0,0 +1,67 @@
+#! /bin/bash
+#	Copyright (C) 20011 Canonical
+#
+#	This program is free software; you can redistribute it and/or
+#	modify it under the terms of the GNU General Public License as
+#	published by the Free Software Foundation, version 2 of the
+#	License.
+
+#=NAME introspect
+#=DESCRIPTION Test process confinement introspection
+
+pwd=`dirname $0`
+pwd=`cd $pwd ; /bin/pwd`
+
+bin=$pwd
+
+. $bin/prologue.inc
+
+ok_ix_perm=rix
+badperm=r
+ok_ux_perm=ux
+ok_px_perm=px
+bad_mx_perm=rm
+
+#self unconfined
+runchecktest "introspect self unconfined" pass self unconfined
+
+#self unconfined (mode)
+runchecktest "introspect self unconfined (mode)" fail self unconfined enforce
+
+#self confined - no access to introspection
+genprofile
+runchecktest "introspect self confined" fail self "$testexec"
+
+#self confined
+genprofile "/proc/*/attr/current":r
+runchecktest "introspect self confined" pass self "$testexec"
+
+#self confined (enforce)
+runchecktest "introspect self confined" pass self "$testexec" enforce
+
+#### TODO
+
+# query unconfined of unconfined
+
+# query unconfined of confined
+
+# query unconfined of confined (enfore)
+
+# query confined of unconfined - no access permission
+
+# query confined of unconfined - access permission
+
+# query confined of unconfined (mode) - access permission
+
+# query confined of confined same profile - no access permission
+
+# query confined of confined same profile
+
+# query confined of confined same profile (enforce)
+
+# query confined of confined diff profile - no access permission
+
+# query confined of confined diff profile
+
+# query confined of confined diff profile (enforce)
+
-- 
1.7.5.4


-- 
AppArmor mailing list
AppArmor at lists.ubuntu.com
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor


More information about the AppArmor mailing list