[apparmor] [PATCH 1/3] Generate the features list from the features directory

John Johansen john.johansen at canonical.com
Thu Feb 23 23:00:29 UTC 2012


Newer versions of AppArmor use a features directory instead of a file
update the parser to use this to determine features and match string

This is just a first pass at this to get things up quickly.  A much
more comprehensive rework that can parse and use the full information
set is needed.

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
 parser/parser.h        |    1 +
 parser/parser_common.c |    1 +
 parser/parser_main.c   |  129 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/parser/parser.h b/parser/parser.h
index 8d3ef6c..7be0f83 100644
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -247,6 +247,7 @@ extern int perms_create;
 extern int net_af_max_override;
 extern int kernel_load;
 extern int kernel_supports_network;
+extern int kernel_supports_mount;
 extern int flag_changehat_version;
 extern int conf_verbose;
 extern int conf_quiet;
diff --git a/parser/parser_common.c b/parser/parser_common.c
index df78a10..cf68503 100644
--- a/parser/parser_common.c
+++ b/parser/parser_common.c
@@ -27,6 +27,7 @@ int perms_create = 0;                   /* perms contain create flag */
 int net_af_max_override = -1;           /* use kernel to determine af_max */
 int kernel_load = 1;
 int kernel_supports_network = 1;        /* kernel supports network rules */
+int kernel_supports_mount = 0;	        /* kernel supports mount rules */
 int flag_changehat_version = FLAG_CHANGEHAT_1_5;
 int conf_verbose = 0;
 int conf_quiet = 0;
diff --git a/parser/parser_main.c b/parser/parser_main.c
index 721582d..b5b80d9 100644
--- a/parser/parser_main.c
+++ b/parser/parser_main.c
@@ -30,6 +30,7 @@
 #include <mntent.h>
 #include <libintl.h>
 #include <locale.h>
+#include <dirent.h>
 #define _(s) gettext(s)
 
 /* enable the following line to get voluminous debug info */
@@ -74,6 +75,7 @@ int preprocess_only = 0;
 int skip_mode_force = 0;
 struct timespec mru_tstamp;
 
+#define FLAGS_STRING_SIZE 1024
 char *match_string = NULL;
 char *flags_string = NULL;
 
@@ -667,17 +669,137 @@ int have_enough_privilege(void)
 	return 0;
 }
 
+char *snprintf_buffer(char *buf, char *pos, ssize_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i, remaining = size - (pos - buf);
+
+	va_start(args, fmt);
+	i = vsnprintf(pos, remaining, fmt, args);
+	va_end(args);
+
+	if (i >= size) {
+		PERROR(_("Feature buffer full."));
+		exit(1);
+	}
+
+	return pos + i;
+}
+
+static char *handle_features_dir(const char *filename, char **buffer, int size,
+				 char *pos)
+{
+	DIR *dir = NULL;
+	char *dirent_path = NULL;
+	struct dirent *dirent;
+	struct stat my_stat;
+	int len;
+
+	PDEBUG("Opened features directory \"%s\"\n", filename);
+	if (!(dir = opendir(filename))) {
+		PDEBUG("opendir failed '%s'", filename);
+		exit(1);
+	}
+
+	while ((dirent = readdir(dir)) != NULL) {
+		int name_len;
+		/* skip dotfiles silently. */
+		if (dirent->d_name[0] == '.')
+			continue;
+
+		if (dirent_path)
+			free(dirent_path);
+		if (asprintf(&dirent_path, "%s/%s", filename, dirent->d_name) < 0)
+		{
+			PERROR(_("Memory allocation error."));
+			exit(1);
+		}
+
+		name_len = strlen(dirent->d_name);
+		if (!name_len)
+			continue;
+
+		if (stat(dirent_path, &my_stat)) {
+			PERROR(_("stat failed for '%s'"), dirent_path);
+			exit(1);
+		}
+
+		pos = snprintf_buffer(*buffer, pos, size, "%s {", dirent->d_name);
+		if (S_ISREG(my_stat.st_mode)) {
+			int file;
+			int remaining = size - (pos - *buffer);
+			if (!(file = open(dirent_path, O_RDONLY))) {
+				PDEBUG("Could not open '%s' in '%s'", dirent_path, filename);
+				exit(1);
+				break;
+			}
+			PDEBUG("Opened features \"%s\" in \"%s\"\n", dirent_path, filename);
+			if (my_stat.st_size > remaining) {
+				PERROR(_("Feature buffer full."));
+				exit(1);
+			}
+
+			do {
+				len = read(file, pos, remaining);
+				if (len > 0) {
+					remaining -= len;
+					pos += len;
+					*pos = 0;
+				}
+			} while (len > 0);
+			if (len < 0) {
+				PDEBUG("Error reading feature file '%s'\n",
+				       dirent_path);
+				exit(1);
+			}
+			close(file);
+
+		} else if (S_ISDIR(my_stat.st_mode)) {
+			pos = handle_features_dir(dirent_path, buffer, size,
+						  pos);
+			if (!pos)
+				break;
+
+		}
+
+		pos = snprintf_buffer(*buffer, pos, size, " }\n");
+	}
+	if (dirent_path)
+		free(dirent_path);
+	closedir(dir);
+
+	return pos;
+}
+
 /* match_string == NULL --> no match_string available
    match_string != NULL --> either a matching string specified on the
    command line, or the kernel supplied a match string */
 static void get_match_string(void) {
 
 	FILE *ms = NULL;
+	struct stat stat_file;
 
 	/* has process_args() already assigned a match string? */
 	if (match_string)
 		goto out;
 
+	if (stat(FLAGS_FILE, &stat_file) == -1)
+		goto out;
+
+	if (S_ISDIR(stat_file.st_mode)) {
+		/* if we have a features directory default to */
+		regex_type = AARE_DFA;
+		perms_create = 1;
+
+		flags_string = malloc(FLAGS_STRING_SIZE);
+		handle_features_dir(FLAGS_FILE, &flags_string, FLAGS_STRING_SIZE, flags_string);
+		if (strstr(flags_string, "network"))
+			kernel_supports_network = 1;
+		if (strstr(flags_string, "mount"))
+			kernel_supports_mount = 1;
+		return;
+	}
+
 	ms = fopen(MATCH_STRING, "r");
 	if (!ms)
 		goto out;
@@ -718,17 +840,18 @@ static void get_flags_string(char **flags, char *flags_file) {
 	FILE *f = NULL;
 
 	/* abort if missing or already set */
-	if (!flags || *flags) return;
+	if (!flags || *flags)
+		return;
 
 	f = fopen(flags_file, "r");
 	if (!f)
 		return;
 
-	*flags = malloc(1024);
+	*flags = malloc(FLAGS_STRING_SIZE);
 	if (!*flags)
 		goto fail;
 
-	if (!fgets(*flags, 1024, f))
+	if (!fgets(*flags, FLAGS_STRING_SIZE, f))
 		goto fail;
 
 	fclose(f);
-- 
1.7.9




More information about the AppArmor mailing list