[apparmor] [PATCH 27/31] parser: Shove binary file and fd reading into kernel_interface.c

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


This is the start of the kernel_interface API that allows callers to
specify a buffer, a file path, or a file descriptor that should be
copied to the proper kernel interface for loading, replacing, or
removing in-kernel policies.

Support exists for reading from a file path or file descriptor into a
buffer and then writing that buffer to the appropriate apparmorfs
interface file.

An aa_kernel_interface_write_policy() function is also provided for
callers that want to route a buffer to an arbitrary file descriptor
instead of to an apparmorfs file. This is useful when an admin instructs
apparmor_parser to write to stdout or a file.

Additionally, it removes some parser-specific globals from the
kernel_interface.c file, such as OPTION_{ADD,REPLACE,REMOVE}, in
preparation for moving the code into a library.

Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
---
 parser/kernel_interface.c | 194 +++++++++++++++++++++++++++++++---------------
 parser/kernel_interface.h |  10 ++-
 parser/parser_interface.c |   2 +-
 parser/parser_main.c      |  73 ++++++++---------
 4 files changed, 174 insertions(+), 105 deletions(-)

diff --git a/parser/kernel_interface.c b/parser/kernel_interface.c
index a33a6be..9d7406e 100644
--- a/parser/kernel_interface.c
+++ b/parser/kernel_interface.c
@@ -88,15 +88,12 @@ static const char *next_profile_buffer(const char *buffer, int size)
 	return NULL;
 }
 
-static int write_buffer(int fd, const char *buffer, int size, int set)
+static int write_buffer(int fd, const char *buffer, int size)
 {
-	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 -1;
 	} else if (wsize < size) {
-		PERROR(_("%s: Unable to write %s\n"), progname, err_str);
 		errno = EPROTO;
 		return -1;
 	}
@@ -124,7 +121,7 @@ static int write_policy_buffer(int fd, int atomic,
 	int rc;
 
 	if (atomic) {
-		rc = write_buffer(fd, buffer, size, true);
+		rc = write_buffer(fd, buffer, size);
 	} else {
 		const char *b, *next;
 
@@ -136,7 +133,7 @@ static int write_policy_buffer(int fd, int atomic,
 				bsize = next - b;
 			else
 				bsize = size;
-			if (write_buffer(fd, b, bsize, false) == -1)
+			if (write_buffer(fd, b, bsize) == -1)
 				return -1;
 		}
 	}
@@ -147,83 +144,156 @@ static int write_policy_buffer(int fd, int atomic,
 	return 0;
 }
 
-/**
- * open_option_iface - open the interface file for @option
- * @aadir: apparmorfs dir
- * @option: load command option
- *
- * Returns: fd to interface or -1 on error, with errno set.
- */
-static int open_option_iface(int aadir, int option)
-{
-	const char *name;
-
-	switch (option) {
-	case OPTION_ADD:
-		name = ".load";
-		break;
-	case OPTION_REPLACE:
-		name = ".replace";
-		break;
-	case OPTION_REMOVE:
-		name = ".remove";
-		break;
-	default:
-		errno = EINVAL;
-		return -1;
-	}
+#define AA_IFACE_FILE_LOAD	".load"
+#define AA_IFACE_FILE_REMOVE	".remove"
+#define AA_IFACE_FILE_REPLACE	".replace"
 
-	return openat(aadir, name, O_WRONLY);
-
-	/* TODO: push up */
-	/*
-	if (fd < 0) {
-		PERROR(_("Unable to open %s - %s\n"), filename,
-		       strerror(errno));
-		return -errno;
-	}
-	*/
-}
-
-int aa_load_buffer(int option, char *buffer, int size)
+static int write_policy_buffer_to_iface(const char *iface_file,
+					const char *buffer, size_t size)
 {
 	autoclose int dirfd = -1;
 	autoclose int fd = -1;
 
-	/* TODO: push backup into caller */
-	if (!kernel_load)
-		return 0;
-
 	dirfd = open_iface_dir();
 	if (dirfd == -1)
 		return -1;
 
-	fd = open_option_iface(dirfd, option);
+	fd = openat(dirfd, iface_file, O_WRONLY | O_CLOEXEC);
 	if (fd == -1)
 		return -1;
 
 	return write_policy_buffer(fd, kernel_supports_setload, buffer, size);
 }
 
+static int write_policy_fd_to_iface(const char *iface_file, int fd)
+{
+	autofree char *buffer = NULL;
+	int size = 0, asize = 0, rsize;
+	int chunksize = 1 << 14;
+
+	do {
+		if (asize - size == 0) {
+			buffer = (char *) realloc(buffer, chunksize);
+			asize = chunksize;
+			chunksize <<= 1;
+			if (!buffer) {
+				errno = ENOMEM;
+				return -1;
+			}
+		}
+
+		rsize = read(fd, buffer + size, asize - size);
+		if (rsize)
+			size += rsize;
+	} while (rsize > 0);
+
+	if (rsize == -1)
+		return -1;
+
+	return write_policy_buffer_to_iface(iface_file, buffer, size);
+}
+
+static int write_policy_file_to_iface(const char *iface_file, const char *path)
+{
+	autoclose int fd;
+
+	fd = open(path, O_RDONLY);
+	if (fd == -1)
+		return -1;
+
+	return write_policy_fd_to_iface(iface_file, fd);
+}
+
 /**
- * aa_remove_profile - remove a profile from the kernel
- * @fqname: the fully qualified name of the profile to remove
+ * aa_kernel_interface_load_policy - load a policy into the kernel
+ * @buffer: a buffer containing a policy
+ * @size: the size of the buffer
  *
  * Returns: 0 on success, -1 on error with errno set
  */
-int aa_remove_profile(const char *fqname)
+int aa_kernel_interface_load_policy(const char *buffer, size_t size)
 {
-	autoclose int dirfd = -1;
-	autoclose int fd = -1;
+	return write_policy_buffer_to_iface(AA_IFACE_FILE_LOAD, buffer, size);
+}
 
-	dirfd = open_iface_dir();
-	if (dirfd == -1)
-		return -1;
+/**
+ * aa_kernel_interface_load_policy_from_file - load a policy into the kernel
+ * @path: path to a policy binary
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_load_policy_from_file(const char *path)
+{
+	return write_policy_file_to_iface(AA_IFACE_FILE_LOAD, path);
+}
 
-	fd = open_option_iface(dirfd, OPTION_REMOVE);
-	if (fd == -1)
-		return -1;
+/**
+ * aa_kernel_interface_load_policy_from_fd - load a policy into the kernel
+ * @fd: a pre-opened, readable file descriptor at the correct offset
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_load_policy_from_fd(int fd)
+{
+	return write_policy_fd_to_iface(AA_IFACE_FILE_LOAD, fd);
+}
+
+/**
+ * aa_kernel_interface_replace_policy - replace a policy in the kernel
+ * @buffer: a buffer containing a policy
+ * @size: the size of the buffer
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_replace_policy(const char *buffer, size_t size)
+{
+	return write_policy_buffer_to_iface(AA_IFACE_FILE_REPLACE,
+					    buffer, size);
+}
+
+/**
+ * aa_kernel_interface_replace_policy_from_file - replace a policy in the kernel
+ * @path: path to a policy binary
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_replace_policy_from_file(const char *path)
+{
+	return write_policy_file_to_iface(AA_IFACE_FILE_REPLACE, path);
+}
+
+/**
+ * aa_kernel_interface_replace_policy_from_fd - replace a policy in the kernel
+ * @fd: a pre-opened, readable file descriptor at the correct offset
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_replace_policy_from_fd(int fd)
+{
+	return write_policy_fd_to_iface(AA_IFACE_FILE_REPLACE, fd);
+}
+
+/**
+ * aa_kernel_interface_remove_policy - remove a policy from the kernel
+ * @fqname: nul-terminated fully qualified name of the policy to remove
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_remove_policy(const char *fqname)
+{
+	return write_policy_buffer_to_iface(AA_IFACE_FILE_REMOVE,
+					    fqname, strlen(fqname) + 1);
+}
 
-	/* include trailing \0 in buffer write */
-	return write_buffer(fd, fqname, strlen(fqname) + 1, 0);
+/**
+ * aa_kernel_interface_write_policy - write a policy to a file descriptor
+ * @fd: a pre-opened, writeable file descriptor at the correct offset
+ * @buffer: a buffer containing a policy
+ * @size: the size of the buffer
+ *
+ * Returns: 0 on success, -1 on error with errno set
+ */
+int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size)
+{
+	return write_policy_buffer(fd, 1, buffer, size);
 }
diff --git a/parser/kernel_interface.h b/parser/kernel_interface.h
index 3d53238..52e537e 100644
--- a/parser/kernel_interface.h
+++ b/parser/kernel_interface.h
@@ -20,7 +20,13 @@
 #define __AA_KERNEL_INTERFACE_H
 
 int aa_find_iface_dir(char **dir);
-int aa_load_buffer(int option, char *buffer, int size);
-int aa_remove_profile(const char *fqname);
+int aa_kernel_interface_load_policy(const char *buffer, size_t size);
+int aa_kernel_interface_load_policy_from_file(const char *path);
+int aa_kernel_interface_load_policy_from_fd(int fd);
+int aa_kernel_interface_replace_policy(const char *buffer, size_t size);
+int aa_kernel_interface_replace_policy_from_file(const char *path);
+int aa_kernel_interface_replace_policy_from_fd(int fd);
+int aa_kernel_interface_remove_policy(const char *fqname);
+int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size);
 
 #endif /* __AA_KERNEL_INTERFACE_H */
diff --git a/parser/parser_interface.c b/parser/parser_interface.c
index be279b1..49c8748 100644
--- a/parser/parser_interface.c
+++ b/parser/parser_interface.c
@@ -522,7 +522,7 @@ int __sd_serialize_profile(int option, Profile *prof, int cache_fd)
 
 	if (option == OPTION_REMOVE) {
 		if (kernel_load) {
-			if (aa_remove_profile(prof->fqname().c_str()) == -1)
+			if (aa_kernel_interface_remove_policy(prof->fqname().c_str()) == -1)
 				error = -errno;
 		}
 	} else {
diff --git a/parser/parser_main.c b/parser/parser_main.c
index 00b0bad..8e10bd4 100644
--- a/parser/parser_main.c
+++ b/parser/parser_main.c
@@ -590,62 +590,55 @@ static void set_supported_features(void)
 
 int process_binary(int option, const char *profilename)
 {
-	autofree char *buffer = NULL;
-	int retval = 0, size = 0, asize = 0, rsize;
-	int chunksize = 1 << 14;
-	autoclose int fd = -1;
-
-	if (profilename) {
-		fd = open(profilename, O_RDONLY);
-		if (fd == -1) {
-			retval = errno;
-			PERROR(_("Error: Could not read binary profile or cache file %s: %s.\n"),
-			       profilename, strerror(errno));
-			return retval;
-		}
-	} else {
-		fd = dup(0);
-	}
-
-	do {
-		if (asize - size == 0) {
-			buffer = (char *) realloc(buffer, chunksize);
-			asize = chunksize;
-			chunksize <<= 1;
-			if (!buffer) {
-				PERROR(_("Memory allocation error."));
-				return ENOMEM;
+	const char *printed_name;
+	int retval;
+
+	printed_name = profilename ? profilename : "stdin";
+
+	if (kernel_load) {
+		if (option == OPTION_ADD) {
+			retval = profilename ?
+				 aa_kernel_interface_load_policy_from_file(profilename) :
+				 aa_kernel_interface_load_policy_from_fd(0);
+			if (retval == -1) {
+				retval = errno;
+				PERROR(_("Error: Could not load profile %s: %s\n"),
+				       printed_name, strerror(retval));
+				return retval;
 			}
+		} else if (option == OPTION_REPLACE) {
+			retval = profilename ?
+				 aa_kernel_interface_replace_policy_from_file(profilename) :
+				 aa_kernel_interface_replace_policy_from_fd(0);
+			if (retval == -1) {
+				retval = errno;
+				PERROR(_("Error: Could not replace profile %s: %s\n"),
+				       printed_name, strerror(retval));
+				return retval;
+			}
+		} else {
+			PERROR(_("Error: Invalid load option specified: %d\n"),
+			       option);
+			return EINVAL;
 		}
-
-		rsize = read(fd, buffer + size, asize - size);
-		if (rsize)
-			size += rsize;
-	} while (rsize > 0);
-
-	if (rsize == 0) {
-		retval = aa_load_buffer(option, buffer, size);
-		if (retval == -1)
-			retval = -errno;
-	} else
-		retval = rsize;
+	}
 
 	if (conf_verbose) {
 		switch (option) {
 		case OPTION_ADD:
 			printf(_("Cached load succeeded for \"%s\".\n"),
-			       profilename ? profilename : "stdin");
+			       printed_name);
 			break;
 		case OPTION_REPLACE:
 			printf(_("Cached reload succeeded for \"%s\".\n"),
-			       profilename ? profilename : "stdin");
+			       printed_name);
 			break;
 		default:
 			break;
 		}
 	}
 
-	return retval;
+	return 0;
 }
 
 void reset_parser(const char *filename)
-- 
2.1.0




More information about the AppArmor mailing list