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 <[email protected]>
---
 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


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to