[apparmor] [PATCH RFC v2] Add profile-based libapparmor query interface

Tyler Hicks tyhicks at canonical.com
Thu Mar 28 01:33:23 UTC 2013


Description: Add simple profile-based query interface
 Wrap the apparmorfs profile query interface with a very simple libapparmor
 interface. This function takes a permission mask and query string consisting
 of a profile name and a DFA match string separated by a NUL char. It sets two
 output parameters indicating whether the action should be allowed and if the
 action should be audited.
 .
 The allowed and audited output parameters take into account deny and quiet
 permission masks returned in the kernel query. Additionally, the audited
 ouput parameter takes into account whether the action is to be allowed or
 not. If not, audited is set to true as long as there was no specific quiet
 rules for the queried permission.
 .
 The function requires a static char array to be allocated and initialized to
 the path of the apparmorfs .access file the first time it is called.
 Otherwise, aa_find_mountpoint() would need to be called for every query which
 would be inefficient. pthread_once() is used to ensure that aa_query_profile()
 is thread-safe while the char array is being allocated and initialized.
Author: Tyler Hicks <tyhicks at canonical.com>
Index: apparmor-2.8.0/libraries/libapparmor/src/kernel_interface.c
===================================================================

 * Improvement from v1:
   - Check read()'s return value to be sure that the expected amount of bytes
     were read. This still allows for newer kernels to extend the query reply
     string but lets libapparmor be sure that it has all of the masks that it
     expected to receive.
 * Bug fixes from v1:
   - Fix conversion issues when transforming the kernel's query reply string
     to uint32_t's. The strings coming from the kernel are in hex form, not
     unsigned int form, so we must use SCNx32 instead of SCNu32. This resulted
     in allow, deny, audit, and quiet to be converted incorrectly.
   - Fix incorrect bit twiddling when setting *allowed and *audited. The
     result of (audit & ~deny) must be negated before being AND'ed with mask.
     Additionally, the final result should be zero to indicate that the
     permissions in mask should all be allowed. Without this change, mask
     could have contained additional permissions that shouldn't be allowed but
     aa_query_profile() would still set *allowed to 1.
     Old check: *allowed = mask & (allow & ~deny) ? 1 : 0;
     New check: *allowed = mask & ~(allow & ~deny) ? 0 : 1;
   - With the new bit twiddling changes, mask must not be 0 or *allowed will
     incorrectly be set to 1. There's no valid reason to call
     aa_query_profile() with a mask value of 0 so error out in this condition.

--- apparmor-2.8.0.orig/libraries/libapparmor/src/kernel_interface.c	2013-03-27 12:32:23.363977349 -0700
+++ apparmor-2.8.0/libraries/libapparmor/src/kernel_interface.c	2013-03-27 17:53:50.230405209 -0700
@@ -28,6 +28,9 @@
 #include <limits.h>
 #include <stdarg.h>
 #include <mntent.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <pthread.h>
 
 #include "apparmor.h"
 
@@ -677,3 +680,98 @@
 {
 	return aa_task_has_perm(aa_gettid(), mask, query, size);
 }
+
+static pthread_once_t aafs_access_control = PTHREAD_ONCE_INIT;
+static char *aafs_access = NULL;
+
+static void aafs_access_init_once(void)
+{
+	char *aafs;
+	int ret;
+
+	ret = aa_find_mountpoint(&aafs);
+	if (ret < 0)
+		return;
+
+	ret = asprintf(&aafs_access, "%s/.access", aafs);
+	if (ret < 0)
+		aafs_access = NULL;
+
+	free(aafs);
+}
+
+/* "allow 0x00000000\ndeny 0x00000000\naudit 0x00000000\nquiet 0x00000000\n" */
+#define QUERY_PROFILE_REPLY_LEN	67
+
+/**
+ * aa_query_profile - test if the profile being enforced allows access to query
+ * @mask: permission bits to query
+ * @query: binary query string, must be offset by AA_QUERY_CMD_PROFILE_SIZE
+ * @size: size of the query string must include AA_QUERY_CMD_PROFILE_SIZE
+ * @allowed: upon successful return, will be 1 if query is allowed and 0 if not
+ * @audited: upon successful return, will be 1 if query should be audited and 0
+ *           if not
+ *
+ * Returns: 0 on success else -1 and sets errno
+ */
+int aa_query_profile(uint32_t mask, char *query, size_t size,
+		     int *allowed, int *audited)
+{
+	char buf[QUERY_PROFILE_REPLY_LEN];
+	uint32_t allow, deny, audit, quiet;
+	int fd, ret, saved;
+
+	if (!mask || size <= AA_QUERY_CMD_PROFILE_SIZE) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	ret = pthread_once(&aafs_access_control, aafs_access_init_once);
+	if (ret) {
+		errno = EINVAL;
+		return -1;
+	} else if (!aafs_access) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	fd = open(aafs_access, O_RDWR);
+	if (fd == -1)
+		return -1;
+
+	memcpy(query, AA_QUERY_CMD_PROFILE, AA_QUERY_CMD_PROFILE_SIZE);
+	errno = 0;
+	ret = write(fd, query, size);
+	if (ret != size) {
+		if (ret >= 0)
+			errno = EPROTO;
+		return -1;
+	}
+
+	ret = read(fd, buf, QUERY_PROFILE_REPLY_LEN);
+	saved = errno;
+	(void)close(fd);
+	errno = saved;
+	if (ret != QUERY_PROFILE_REPLY_LEN) {
+		if (ret >= 0)
+			errno = EPROTO;
+		return -1;
+	}
+
+	ret = sscanf(buf, "allow 0x%8" SCNx32 "\n"
+			  "deny 0x%8"  SCNx32 "\n"
+			  "audit 0x%8" SCNx32 "\n"
+			  "quiet 0x%8" SCNx32 "\n",
+		     &allow, &deny, &audit, &quiet);
+	if (ret != 4) {
+		errno = EPROTONOSUPPORT;
+		return -1;
+	}
+
+	*allowed = mask & ~(allow & ~deny) ? 0 : 1;
+	if (!(*allowed))
+		audit = 0xFFFFFFFF;
+	*audited = mask & ~(audit & ~quiet) ? 0 : 1;
+
+	return 0;
+}
Index: apparmor-2.8.0/libraries/libapparmor/src/apparmor.h
===================================================================
--- apparmor-2.8.0.orig/libraries/libapparmor/src/apparmor.h	2013-03-27 12:32:23.363977349 -0700
+++ apparmor-2.8.0/libraries/libapparmor/src/apparmor.h	2013-03-27 17:41:57.000000000 -0700
@@ -87,6 +87,10 @@
 			    size_t size);
 extern int aa_has_perm(uint32_t mask, char *query, size_t size);
 
+#define AA_QUERY_CMD_PROFILE		"profile\0"
+#define AA_QUERY_CMD_PROFILE_SIZE	8
+extern int aa_query_profile(uint32_t mask, char *query, size_t size,
+			    int *allow, int *audit);
 
 #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)
Index: apparmor-2.8.0/libraries/libapparmor/src/libapparmor.map
===================================================================
--- apparmor-2.8.0.orig/libraries/libapparmor/src/libapparmor.map	2013-03-27 12:32:23.363977349 -0700
+++ apparmor-2.8.0/libraries/libapparmor/src/libapparmor.map	2013-03-27 17:41:57.000000000 -0700
@@ -39,6 +39,7 @@
   global:
         aa_task_has_perm;
 	aa_has_perm;
+	aa_query_profile;
   local:
 	*;
 } APPARMOR_1.1;
Index: apparmor-2.8.0/libraries/libapparmor/swig/SWIG/libapparmor.i
===================================================================
--- apparmor-2.8.0.orig/libraries/libapparmor/swig/SWIG/libapparmor.i	2013-03-27 12:32:23.363977349 -0700
+++ apparmor-2.8.0/libraries/libapparmor/swig/SWIG/libapparmor.i	2013-03-27 17:41:57.000000000 -0700
@@ -30,3 +30,5 @@
 extern int aa_task_has_perm(pid_t task, uint32_t mask, const char *query,
 			    size_t size);
 extern int aa_has_perm(uint32_t mask, const char *query, size_t size);
+extern int aa_query_profile(uint32_t mask, char *query, size_t size,
+			    int *allow, int *audit);
Index: apparmor-2.8.0/libraries/libapparmor/src/Makefile.am
===================================================================
--- apparmor-2.8.0.orig/libraries/libapparmor/src/Makefile.am	2013-03-27 12:32:23.363977349 -0700
+++ apparmor-2.8.0/libraries/libapparmor/src/Makefile.am	2013-03-27 12:32:23.359977349 -0700
@@ -24,7 +24,7 @@
 noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h
 
 libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c
-libapparmor_la_LDFLAGS = -version-info 1:2:0 -XCClinker -dynamic \
+libapparmor_la_LDFLAGS = -version-info 1:2:0 -XCClinker -dynamic -pthread \
 	-Wl,--version-script=$(top_srcdir)/src/libapparmor.map -Wl,-soname=libapparmor.so.1
 
 libimmunix_la_SOURCES = kernel_interface.c libimmunix_warning.c
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20130327/bde7228f/attachment.pgp>


More information about the AppArmor mailing list