[apparmor] [PATCH 27/31] parser: Shove binary file and fd reading into kernel_interface.c
John Johansen
john.johansen at canonical.com
Thu Jan 22 18:16:08 UTC 2015
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 <tyhicks at canonical.com>
Acked-by: John Johansen <john.johansen 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)
>
More information about the AppArmor
mailing list