[apparmor] [PATCH 17/31] parser: Make match file interface suitable for a library

Tyler Hicks tyhicks at canonical.com
Sat Dec 6 00:22:16 UTC 2014


The aa_match_new_from_kernel() function creates an aa_match object. It
can be thought of as the constructor of aa_match objects.

The default match file path is hidden from the caller so that it doesn't
become part of our ABI when we move this code into libapparmor later.
If, for example, another match file location was needed to be checked in
the future, we can transparently do it behind the
aa_match_new_from_kernel() call instead of breaking ABI by changing the
macro.

The aa_match_ref() and aa_match_unref() functions are used to grab and
give up references to an aa_match. When the ref count hits zero, all
allocated memory is freed. Like with free(), aa_match_unref() can be
called with a NULL pointer for convenience.

A set of aa_match_supports_*() functions are added for checking the
features represented by a match file.

Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
---
 parser/match.c       | 118 +++++++++++++++++++++++++++++++++++++++++++++------
 parser/match.h       |   9 +++-
 parser/parser_main.c |  18 +++++---
 3 files changed, 124 insertions(+), 21 deletions(-)

diff --git a/parser/match.c b/parser/match.c
index 770d548..e5a3ede 100644
--- a/parser/match.c
+++ b/parser/match.c
@@ -24,23 +24,113 @@
 #include "lib.h"
 #include "parser.h"
 
+#define AA_MATCH_FILE "/sys/kernel/security/" MODULE_NAME "/matching"
+
 #define MATCH_STRING_SIZE 1000
 
-void set_features_by_match_file(void)
+#define SUPPORT_PERMS_CREATE	(1<<1)
+#define SUPPORT_NETWORK		(1<<2)
+
+struct aa_match {
+	unsigned int ref_count;
+	uint8_t support;
+};
+
+/**
+ * aa_match_new_from_kernel - create a new match based on the current kernel
+ * @match: will point to the address of an allocated and initialized aa_match
+ *         object upon success
+ *
+ * Returns: 0 on success, -1 on error with errno set and *@match pointing to
+ *          NULL
+ */
+int aa_match_new_from_kernel(aa_match **match)
 {
-	autofclose FILE *ms = fopen(MATCH_FILE, "r");
-	if (ms) {
-		autofree char *match_string = (char *) malloc(MATCH_STRING_SIZE);
-		if (!match_string)
-			goto no_match;
-		if (!fgets(match_string, MATCH_STRING_SIZE, ms))
-			goto no_match;
-		if (strstr(match_string, " perms=c"))
-			perms_create = 1;
-		kernel_supports_network = 1;
-		return;
+	autofclose FILE *match_file = NULL;
+	autofree char *match_string = NULL;
+	aa_match *m;
+
+	*match = NULL;
+
+	m = (aa_match *) calloc(1, sizeof(*m));
+	if (!m) {
+		aa_match_unref(m);
+		errno = ENOMEM;
+		return -1;
+	}
+	aa_match_ref(m);
+
+	match_file = fopen(AA_MATCH_FILE, "r");
+	if (!match_file) {
+		int save = errno;
+
+		aa_match_unref(m);
+		errno = save;
+		return -1;
+	}
+
+	match_string = (char *) malloc(MATCH_STRING_SIZE);
+	if (!match_string) {
+		aa_match_unref(m);
+		errno = ENOMEM;
+		return -1;
+	}
+
+	if (!fgets(match_string, MATCH_STRING_SIZE, match_file)) {
+		aa_match_unref(m);
+		errno = EIO;
+		return -1;
 	}
 
-no_match:
-	perms_create = 1;
+	if (strstr(match_string, " perms=c"))
+		m->support |= SUPPORT_PERMS_CREATE;
+
+	m->support |= SUPPORT_NETWORK;
+	*match = m;
+
+	return 0;
+}
+
+/**
+ * aa_match_ref - increments the ref count of a match
+ * @match: the match
+ *
+ * Returns: the match
+ */
+aa_match *aa_match_ref(aa_match *match)
+{
+	atomic_inc(&match->ref_count);
+	return match;
+}
+
+/**
+ * aa_match_unref - decrements the ref count and frees the match when 0
+ * @match: the match (can be NULL)
+ */
+void aa_match_unref(aa_match *match)
+{
+	if (match && atomic_dec_and_test(&match->ref_count))
+		free(match);
+}
+
+/**
+ * aa_match_supports_perms_create - provides match support status of perms_create
+ * @match: the match
+ *
+ * Returns: true if perms_create is supported, false if not
+ */
+bool aa_match_supports_perms_create(aa_match *match)
+{
+	return match->support & SUPPORT_PERMS_CREATE;
+}
+
+/**
+ * aa_match_supports_network - provides match supports status of network
+ * @match: the match
+ *
+ * Returns: true if network is supported, false if not
+ */
+bool aa_match_supports_network(aa_match *match)
+{
+	return match->support & SUPPORT_NETWORK;
 }
diff --git a/parser/match.h b/parser/match.h
index deb7c00..6ad157a 100644
--- a/parser/match.h
+++ b/parser/match.h
@@ -19,8 +19,13 @@
 #ifndef __AA_MATCH_H
 #define __AA_MATCH_H
 
-#define MATCH_FILE "/sys/kernel/security/" MODULE_NAME "/matching"
+typedef struct aa_match aa_match;
 
-void set_features_by_match_file(void);
+int aa_match_new_from_kernel(aa_match **match);
+aa_match *aa_match_ref(aa_match *);
+void aa_match_unref(aa_match *match);
+
+bool aa_match_supports_perms_create(aa_match *match);
+bool aa_match_supports_network(aa_match *match);
 
 #endif /* __AA_MATCH_H */
diff --git a/parser/parser_main.c b/parser/parser_main.c
index 2888a1a..f9fbfe0 100644
--- a/parser/parser_main.c
+++ b/parser/parser_main.c
@@ -546,14 +546,22 @@ int have_enough_privilege(void)
 	return 0;
 }
 
-static void set_supported_features(void) {
-
+static void set_supported_features(void)
+{
 	/* has process_args() already assigned a match string? */
-	if (!features_string) {
-		if (load_features(FEATURES_FILE) == -1) {
-			set_features_by_match_file();
+	if (!features_string && load_features(FEATURES_FILE) == -1) {
+		aa_match *match;
+
+		if (aa_match_new_from_kernel(&match)) {
+			perms_create = 1;
 			return;
 		}
+
+		perms_create = aa_match_supports_perms_create(match);
+		kernel_supports_network = aa_match_supports_network(match);
+
+		aa_match_unref(match);
+		return;
 	}
 
 	perms_create = 1;
-- 
2.1.0




More information about the AppArmor mailing list