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;
}