[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