File apparmor-fix-profile-loads-from-cache.diff of Package apparmor.472

=== modified file 'parser/parser.h'
---
 parser/parser.h           |    1 
 parser/parser_common.c    |    1 
 parser/parser_interface.c |   69 ++++++++++++++++++++++++++++++----------------
 parser/parser_main.c      |    2 +
 4 files changed, 49 insertions(+), 24 deletions(-)

--- a/parser/parser.h
+++ b/parser/parser.h
@@ -265,6 +265,7 @@ extern int regex_type;
 extern int perms_create;
 extern int net_af_max_override;
 extern int kernel_load;
+extern int kernel_supports_setload;
 extern int kernel_supports_network;
 extern int kernel_supports_mount;
 extern int flag_changehat_version;
--- a/parser/parser_common.c
+++ b/parser/parser_common.c
@@ -26,6 +26,7 @@ int regex_type = AARE_DFA;
 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_setload = 0;	/* kernel supports atomic set loads */
 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;
--- a/parser/parser_interface.c
+++ b/parser/parser_interface.c
@@ -887,52 +887,73 @@ static char *next_profile_buffer(char *b
 	return NULL;
 }
 
+static int write_buffer(int fd, char *buffer, int size, int set)
+{
+	const char *err_str = set ? "profile set" : "profile";
+	int wsize = write(fd, buffer, size);
+	if (wsize < 0) {
+		PERROR(_("%s: Unable to write %s\n"), progname, err_str);
+		return -errno;
+	} else if (wsize < size) {
+		PERROR(_("%s: Unable to write %s\n"), progname, err_str);
+		return -EPROTO;
+	}
+	return 0;
+}
+
 int sd_load_buffer(int option, char *buffer, int size)
 {
 	int fd = -1;
-	int error = -ENOMEM, wsize, bsize;
+	int error, bsize;
 	char *filename = NULL;
-	char *b;
+
+	/* TODO: push backup into caller */
+	if (!kernel_load)
+		return 0;
 
 	switch (option) {
 	case OPTION_ADD:
 		if (asprintf(&filename, "%s/.load", subdomainbase) == -1)
-			goto exit;
-		if (kernel_load) fd = open(filename, O_WRONLY);
+			return -ENOMEM;
 		break;
 	case OPTION_REPLACE:
 		if (asprintf(&filename, "%s/.replace", subdomainbase) == -1)
-			goto exit;
-		if (kernel_load) fd = open(filename, O_WRONLY);
+			return -ENOMEM;
 		break;
 	default:
-		error = -EINVAL;
-		goto exit;
-		break;
+		return -EINVAL;
 	}
 
-	if (kernel_load && fd < 0) {
+	fd = open(filename, O_WRONLY);
+	if (fd < 0) {
 		PERROR(_("Unable to open %s - %s\n"), filename,
 		       strerror(errno));
 		error = -errno;
-		goto exit;
+		goto out;
 	}
 
-	error = 0;
-	for (b = buffer; b ; b = next_profile_buffer(b + sizeof(header_version), bsize)) {
-		bsize = size - (b - buffer);
-		if (kernel_load) {
-			wsize = write(fd, b, bsize);
-			if (wsize < 0) {
-				error = -errno;
-			} else if (wsize < bsize) {
-				PERROR(_("%s: Unable to write entire profile entry\n"),
-				       progname);
-			}
+	if (kernel_supports_setload) {
+		error = write_buffer(fd, buffer, size, 1);
+	} else {
+		char *b, *next;
+
+		error = 0;	/* in case there are no profiles */
+		for (b = buffer; b; b = next, size -= bsize) {
+			next = next_profile_buffer(b + sizeof(header_version),
+						   size);
+			if (next)
+				bsize = next - b;
+			else
+				bsize = size;
+			error = write_buffer(fd, b, bsize, 0);
+			if (error)
+				break;
 		}
 	}
-	if (kernel_load) close(fd);
-exit:
+	close(fd);
+
+out:
 	free(filename);
+
 	return error;
 }
--- a/parser/parser_main.c
+++ b/parser/parser_main.c
@@ -820,6 +820,8 @@ static void get_match_string(void) {
 			kernel_supports_network = 0;
 		if (strstr(flags_string, "mount"))
 			kernel_supports_mount = 1;
+		if (strstr(flags_string, "set_load"))
+			kernel_supports_setload = 1;
 		return;
 	}
 
openSUSE Build Service is sponsored by