On 12/05/2014 04:22 PM, Tyler Hicks wrote:
> 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]>
Acked-by: John Johansen <[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)
> 



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

Reply via email to