[apparmor] [PATCH v2 36/42] libapparmor: Move the aa_features API

Tyler Hicks tyhicks at canonical.com
Thu Mar 12 21:45:32 UTC 2015


On 2015-03-12 05:03:49, John Johansen wrote:
> On 03/06/2015 01:48 PM, Tyler Hicks wrote:
> > Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
> > ---
> >  libraries/libapparmor/include/sys/apparmor.h |  13 +
> >  libraries/libapparmor/src/Makefile.am        |   2 +-
> >  libraries/libapparmor/src/features.c         | 448 +++++++++++++++++++++++++++
> >  libraries/libapparmor/src/libapparmor.map    |  23 ++
> >  libraries/libapparmor/src/private.h          |   1 +
> >  parser/Makefile                              |   9 +-
> >  parser/features.c                            | 448 ---------------------------
> >  parser/features.h                            |  34 --
> >  parser/kernel_interface.h                    |   2 +
> >  9 files changed, 491 insertions(+), 489 deletions(-)
> >  create mode 100644 libraries/libapparmor/src/features.c
> >  delete mode 100644 parser/features.c
> >  delete mode 100644 parser/features.h
> > 
> > diff --git a/libraries/libapparmor/include/sys/apparmor.h b/libraries/libapparmor/include/sys/apparmor.h
> > index 361cde8..34507e4 100644
> > --- a/libraries/libapparmor/include/sys/apparmor.h
> > +++ b/libraries/libapparmor/include/sys/apparmor.h
> > @@ -18,6 +18,7 @@
> >  #ifndef _SYS_APPARMOR_H
> >  #define _SYS_APPARMOR_H	1
> >  
> > +#include <stdbool.h>
> >  #include <stdint.h>
> >  #include <sys/types.h>
> >  
> > @@ -103,6 +104,18 @@ extern int aa_query_label(uint32_t mask, char *query, size_t size, int *allow,
> >  #define aa_change_hat_vargs(T, X...) \
> >  	(aa_change_hat_vargs)(T, __macroarg_counter(X), X)
> >  
> > +typedef struct aa_features aa_features;
> > +int aa_features_new(aa_features **features, const char *path);
> > +int aa_features_new_from_string(aa_features **features,
> > +				const char *string, size_t size);
> > +int aa_features_new_from_kernel(aa_features **features);
> > +aa_features *aa_features_ref(aa_features *features);
> > +void aa_features_unref(aa_features *features);
> > +
> > +int aa_features_write_to_file(aa_features *features, const char *path);
> > +bool aa_features_is_equal(aa_features *features1, aa_features *features2);
> > +bool aa_features_supports(aa_features *features, char *str);
> > +
> >  __END_DECLS
> >  
> >  #endif	/* sys/apparmor.h */
> > diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am
> > index 42934d0..ac93bf5 100644
> > --- a/libraries/libapparmor/src/Makefile.am
> > +++ b/libraries/libapparmor/src/Makefile.am
> > @@ -48,7 +48,7 @@ af_protos.h: /usr/include/netinet/in.h
> >  lib_LTLIBRARIES = libapparmor.la
> >  noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h private.h
> >  
> > -libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c private.c
> > +libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel_interface.c scanner.c private.c features.c
> >  libapparmor_la_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \
> >  	-Wl,--version-script=$(top_srcdir)/src/libapparmor.map
> >  
> > diff --git a/libraries/libapparmor/src/features.c b/libraries/libapparmor/src/features.c
> > new file mode 100644
> > index 0000000..cf2389c
> > --- /dev/null
> > +++ b/libraries/libapparmor/src/features.c
> > @@ -0,0 +1,448 @@
> > +/*
> > + *   Copyright (c) 2014
> > + *   Canonical, Ltd. (All rights reserved)
> > + *
> > + *   This program is free software; you can redistribute it and/or
> > + *   modify it under the terms of version 2 of the GNU General Public
> > + *   License published by the Free Software Foundation.
> > + *
> > + *   This program is distributed in the hope that it will be useful,
> > + *   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + *   GNU General Public License for more details.
> > + *
> > + *   You should have received a copy of the GNU General Public License
> > + *   along with this program; if not, contact Novell, Inc. or Canonical
> > + *   Ltd.
> > + */
> > +
> > +#include <errno.h>
> > +#include <ctype.h>
> > +#include <dirent.h>
> > +#include <fcntl.h>
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <stdarg.h>
> > +#include <stdlib.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <unistd.h>
> > +#include <sys/apparmor.h>
> > +
> > +#include "private.h"
> > +
> > +#define FEATURES_FILE "/sys/kernel/security/apparmor/features"
> > +
> > +#define STRING_SIZE 8192
> > +
> > +struct aa_features {
> > +	unsigned int ref_count;
> > +	char string[STRING_SIZE];
> > +};
> > +
> > +struct features_struct {
> > +	char *buffer;
> > +	int size;
> > +	char *pos;
> > +};
> > +
> > +static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
> > +{
> > +	va_list args;
> > +	int i, remaining = fst->size - (fst->pos - fst->buffer);
> > +
> > +	if (remaining < 0) {
> > +		errno = EINVAL;
> > +		PERROR("Invalid features buffer offset\n");
> > +		return -1;
> > +	}
> > +
> > +	va_start(args, fmt);
> > +	i = vsnprintf(fst->pos, remaining, fmt, args);
> > +	va_end(args);
> > +
> > +	if (i < 0) {
> > +		errno = EIO;
> > +		PERROR("Failed to write to features buffer\n");
> > +		return -1;
> > +	} else if (i >= remaining) {
> > +		errno = ENOBUFS;
> > +		PERROR("Feature buffer full.");
> > +		return -1;
> > +	}
> > +
> > +	fst->pos += i;
> > +	return 0;
> > +}
> > +
> > +static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
> > +			   void *data)
> > +{
> > +	struct features_struct *fst = (struct features_struct *) data;
> > +
> > +	/* skip dot files and files with no name */
> > +	if (*name == '.' || !strlen(name))
> > +		return 0;
> > +
> > +	if (features_snprintf(fst, "%s {", name) == -1)
> > +		return -1;
> > +
> > +	if (S_ISREG(st->st_mode)) {
> > +		autoclose int file = -1;
> > +		int len;
> > +		int remaining = fst->size - (fst->pos - fst->buffer);
> > +
> > +		file = openat(dirfd(dir), name, O_RDONLY);
> > +		if (file == -1) {
> > +			PDEBUG("Could not open '%s'", name);
> > +			return -1;
> > +		}
> > +		PDEBUG("Opened features \"%s\"\n", name);
> > +		if (st->st_size > remaining) {
> > +			PDEBUG("Feature buffer full.");
> > +			errno = ENOBUFS;
> > +			return -1;
> > +		}
> > +
> > +		do {
> > +			len = read(file, fst->pos, remaining);
> > +			if (len > 0) {
> > +				remaining -= len;
> > +				fst->pos += len;
> > +				*fst->pos = 0;
> > +			}
> > +		} while (len > 0);
> > +		if (len < 0) {
> > +			PDEBUG("Error reading feature file '%s'\n", name);
> > +			return -1;
> > +		}
> > +	} else if (S_ISDIR(st->st_mode)) {
> > +		if (_aa_dirat_for_each(dir, name, fst, features_dir_cb))
> > +			return -1;
> > +	}
> > +
> > +	if (features_snprintf(fst, "}\n") == -1)
> > +		return -1;
> > +
> > +	return 0;
> > +}
> > +
> > +static int handle_features_dir(const char *filename, char *buffer, int size,
> > +			       char *pos)
> > +{
> > +	struct features_struct fst = { buffer, size, pos };
> > +
> > +	if (_aa_dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
> > +		PDEBUG("Failed evaluating %s\n", filename);
> > +		return -1;
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +static int load_features_file(const char *name, char *buffer, size_t size)
> > +{
> > +	autofclose FILE *f = NULL;
> > +	size_t end;
> > +
> > +	f = fopen(name, "r");
> > +	if (!f)
> > +		return -1;
> > +
> > +	errno = 0;
> > +	end = fread(buffer, 1, size - 1, f);
> > +	if (ferror(f)) {
> > +		if (!errno)
> > +			errno = EIO;
> > +		return -1;
> > +	}
> > +	buffer[end] = 0;
> > +
> > +	return 0;
> > +}
> > +
> > +static bool walk_one(const char **str, const char *component, bool is_top_level)
> > +{
> > +	const char *cur = *str;
> > +	uint32_t bracket_count = 0;
> > +	int i = 0;
> > +
> > +	/* Empty strings are not accepted */
> > +	if (!*cur || !component[0])
> > +		return false;
> > +
> > +	/**
> > +	 * If @component is not top-level, the first character in the string to
> > +	 * search MUST be '{'
> > +	 */
> > +	if (!is_top_level) {
> > +		if (*cur != '{')
> > +			return false;
> > +
> > +		cur++;
> > +	}
> > +
> > +	/**
> > +	 * This loop tries to find the @component in *@str. When this loops
> > +	 * completes, cur will either point one character past the end of the
> > +	 * matched @component or to the NUL terminator of *@str.
> > +	 */
> > +	while(*cur && component[i]) {
> > +		if (!isascii(*cur)) {
> > +			/* Only ASCII is expected */
> > +			return false;
> > +		} else if (*cur == '{') {
> > +			/* There's a limit to the number of opening brackets */
> > +			if (bracket_count == UINT32_MAX)
> > +				return false;
> > +
> > +			bracket_count++;
> > +		} else if (*cur == '}') {
> > +			/* Check for unexpected closing brackets */
> > +			if (bracket_count == 0)
> > +				return false;
> > +
> > +			bracket_count--;
> > +		}
> > +
> > +		/**
> > +		 * Move to the next character in @component if we have a match
> > +		 * and either @component is not top-level or, if @component is
> > +		 * top-level, we're not inside of brackets
> > +		 */
> > +		if (*cur == component[i] &&
> > +		    (!is_top_level || bracket_count == 0))
> > +			i++;
> > +		else
> > +			i = 0;
> > +
> > +		cur++;
> > +	}
> > +
> > +	/* A full match was not found if component[i] is non-NUL */
> > +	if (component[i])
> > +		return false;
> > +
> > +	/**
> > +	 * This loop eats up valid (ASCII) characters until a non-bracket or
> > +	 * non-space character is found so that *@str is properly set to call
> > +	 * back into this function, if necessary
> > +	 */
> > +	while (*cur) {
> > +		if (!isascii(*cur))
> > +			return false;
> > +		else if (*cur == '{' || *cur == '}' || !isspace(*cur))
> > +			break;
> > +
> > +		cur++;
> > +	}
> > +
> > +	*str = cur;
> > +	return true;
> > +}
> > +
> > +/**
> > + * aa_features_new - create a new features based on a path
> > + * @features: will point to the address of an allocated and initialized
> > + *            aa_features object upon success
> > + * @path: path to a features file or directory
> > + *
> > + * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > + *          NULL
> > + */
> > +int aa_features_new(aa_features **features, const char *path)
> > +{
> > +	struct stat stat_file;
> > +	aa_features *f;
> > +	int retval;
> > +
> > +	*features = NULL;
> > +
> > +	if (stat(path, &stat_file) == -1)
> > +		return -1;
> > +
> > +	f = (aa_features *) calloc(1, sizeof(*f));
> > +	if (!f) {
> > +		errno = ENOMEM;
> > +		return -1;
> > +	}
> > +	aa_features_ref(f);
> > +
> > +	retval = S_ISDIR(stat_file.st_mode) ?
> > +		 handle_features_dir(path, f->string, STRING_SIZE, f->string) :
> > +		 load_features_file(path, f->string, STRING_SIZE);
> > +	if (retval) {
> > +		int save = errno;
> > +
> > +		aa_features_unref(f);
> > +		errno = save;
> > +		return -1;
> > +	}
> > +
> > +	*features = f;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * aa_features_new_from_string - create a new features based on a string
> > + * @features: will point to the address of an allocated and initialized
> > + *            aa_features object upon success
> > + * @string: a NUL-terminated string representation of features
> > + * @size: the size of @string, not counting the NUL-terminator
> > + *
> > + * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > + *          NULL
> > + */
> > +int aa_features_new_from_string(aa_features **features,
> > +				const char *string, size_t size)
> > +{
> > +	aa_features *f;
> > +
> > +	*features = NULL;
> > +
> > +	/* Require size to be less than STRING_SIZE so there's room for a NUL */
> > +	if (size >= STRING_SIZE)
> > +		return ENOBUFS;
> > +
> > +	f = (aa_features *) calloc(1, sizeof(*f));
> > +	if (!f) {
> > +		errno = ENOMEM;
> > +		return -1;
> > +	}
> > +	aa_features_ref(f);
> > +
> > +	memcpy(f->string, string, size);
> > +	f->string[size] = '\0';
> > +	*features = f;
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * aa_features_new_from_kernel - create a new features based on the current kernel
> > + * @features: will point to the address of an allocated and initialized
> > + *            aa_features object upon success
> > + *
> > + * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > + *          NULL
> > + */
> > +int aa_features_new_from_kernel(aa_features **features)
> > +{
> > +	return aa_features_new(features, FEATURES_FILE);
> > +}
> > +
> > +/**
> > + * aa_features_ref - increments the ref count of a features
> > + * @features: the features
> > + *
> > + * Returns: the features
> > + */
> > +aa_features *aa_features_ref(aa_features *features)
> > +{
> > +	atomic_inc(&features->ref_count);
> > +	return features;
> > +}
> > +
> > +/**
> > + * aa_features_unref - decrements the ref count and frees the features when 0
> > + * @features: the features (can be NULL)
> > + */
> > +void aa_features_unref(aa_features *features)
> > +{
> > +	if (features && atomic_dec_and_test(&features->ref_count))
> > +		free(features);
> > +}
> > +
> > +/**
> > + * aa_features_write_to_file - write a string representation to a file
> > + * @features: the features
> > + * @path: the path to write to
> > + *
> > + * Returns: 0 on success, -1 on error with errno set
> > + */
> > +int aa_features_write_to_file(aa_features *features, const char *path)
> > +{
> > +	autoclose int fd = -1;
> > +	size_t size;
> > +	ssize_t retval;
> > +	char *string;
> > +
> > +	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
> > +		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
> > +	if (fd == -1)
> > +		return -1;
> > +
> > +	string = features->string;
> > +	size = strlen(string);
> > +	do {
> > +		retval = write(fd, string, size);
> > +		if (retval == -1)
> > +			return -1;
> > +
> > +		size -= retval;
> > +		string += retval;
> > +	} while (size);
> > +
> > +	return 0;
> > +}
> > +
> > +/**
> > + * aa_features_is_equal - equality test for two features
> > + * @features1: the first features (can be NULL)
> > + * @features2: the second features (can be NULL)
> > + *
> > + * Returns: true if they're equal, false if they're not or either are NULL
> > + */
> > +bool aa_features_is_equal(aa_features *features1, aa_features *features2)
> > +{
> > +	return features1 && features2 &&
> > +	       strcmp(features1->string, features2->string) == 0;
> > +}
> > +
> > +/**
> > + * aa_features_supports - provides features support status
> > + * @features: the features
> > + * @str: the string representation of a feature to check
> > + *
> > + * Example @str values are "dbus/mask/send", "caps/mask/audit_read", and
> > + * "policy/versions/v7".
> > + *
> > + * Returns: a bool specifying the support status of @str feature
> > + */
> > +bool aa_features_supports(aa_features *features, char *str)
> > +{
> > +	const char *features_string = features->string;
> > +	char *components[32];
> > +	char *saveptr = NULL;
> > +	size_t i;
> > +
> > +	/* Empty strings are not accepted. Neither are leading '/' chars. */
> > +	if (!str || str[0] == '/')
> > +		return false;
> > +
> > +	/**
> > +	 * Break @str into an array of components. For example,
> > +	 * "mount/mask/mount" would turn into "mount" as the first component,
> > +	 * "mask" as the second, and "mount" as the third
> > +	 */
> > +	for (i = 0; i < sizeof(components); i++) {
> > +		components[i] = strtok_r(str, "/", &saveptr);
> > +		if (!components[i])
> > +			break;
> > +
> > +		str = NULL;
> > +	}
> > +
> > +	/* At least one valid token is required */
> > +	if (!components[0])
> > +		return false;
> > +
> > +	/* Ensure that all components are valid and found */
> > +	for (i = 0; i < sizeof(components) && components[i]; i++) {
> > +		if (!walk_one(&features_string, components[i], i == 0))
> > +			return false;
> > +	}
> > +
> > +	return true;
> > +}
> > diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map
> > index 1ea221f..d0020c7 100644
> > --- a/libraries/libapparmor/src/libapparmor.map
> > +++ b/libraries/libapparmor/src/libapparmor.map
> > @@ -52,6 +52,29 @@ APPARMOR_2.9 {
> >  	*;
> >  } APPARMOR_1.1;
> >  
> > +APPARMOR_2.10 {
> > +  global:
> > +        aa_features_new;
> > +        aa_features_new_from_string;
> > +        aa_features_new_from_kernel;
> > +        aa_features_ref;
> > +        aa_features_unref;
> > +        aa_features_write_to_file;
> > +        aa_features_is_equal;
> > +        aa_features_supports_max_abi;
> > +        aa_features_supports_policydb;
> > +        aa_features_supports_set_load;
> > +        aa_features_supports_network;
> > +        aa_features_supports_af_unix;
> > +        aa_features_supports_mount;
> > +        aa_features_supports_dbus;
> > +        aa_features_supports_signal;
> > +        aa_features_supports_ptrace;
> > +        aa_features_supports_diff_encode;
> 
> the map file doesn't matchup with what is being exported, basically
> drop all the different support_X for just supports

Good catch! I'll reply with a fixup patch to show you the change that
I'll make locally.

Tyler

> 
> typedef struct aa_features aa_features;
> int aa_features_new(aa_features **features, const char *path);
> int aa_features_new_from_string(aa_features **features,
> 				const char *string, size_t size);
> int aa_features_new_from_kernel(aa_features **features);
> aa_features *aa_features_ref(aa_features *features);
> void aa_features_unref(aa_features *features);
> 
> int aa_features_write_to_file(aa_features *features, const char *path);
> bool aa_features_is_equal(aa_features *features1, aa_features *features2);
> bool aa_features_supports(aa_features *features, char *str);
> 
> > +  local:
> > +        *;
> > +} APPARMOR_2.9;
> > +
> >  PRIVATE {
> >  	global:
> >  		_aa_is_blacklisted;
> > diff --git a/libraries/libapparmor/src/private.h b/libraries/libapparmor/src/private.h
> > index 3a8beac..83813c4 100644
> > --- a/libraries/libapparmor/src/private.h
> > +++ b/libraries/libapparmor/src/private.h
> > @@ -18,6 +18,7 @@
> >  #define _AA_PRIVATE_H 1
> >  
> >  #include <stdbool.h>
> > +#include <sys/apparmor_private.h>
> >  
> >  #define autofree __attribute((cleanup(_aa_autofree)))
> >  #define autoclose __attribute((cleanup(_aa_autoclose)))
> > diff --git a/parser/Makefile b/parser/Makefile
> > index 372136d..120672f 100644
> > --- a/parser/Makefile
> > +++ b/parser/Makefile
> > @@ -75,10 +75,10 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \
> >         parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \
> >         parser_alias.c common_optarg.c lib.c network.c \
> >         mount.cc dbus.cc profile.cc rule.cc signal.cc ptrace.cc \
> > -       af_rule.cc af_unix.cc features.c policy_cache.c kernel_interface.c
> > +       af_rule.cc af_unix.cc policy_cache.c kernel_interface.c
> >  HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h \
> >         rule.h common_optarg.h signal.h ptrace.h network.h af_rule.h af_unix.h \
> > -       features.h policy_cache.h kernel_interface.h
> > +       policy_cache.h kernel_interface.h
> >  TOOLS = apparmor_parser
> >  
> >  OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o))
> > @@ -237,10 +237,7 @@ mount.o: mount.cc mount.h parser.h immunix.h rule.h
> >  common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmor_re.h
> >  	$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
> >  
> > -features.o: features.c features.h parser.h libapparmor_re/apparmor_re.h
> > -	$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
> > -
> > -policy_cache.o: policy_cache.c policy_cache.h parser.h features.h
> > +policy_cache.o: policy_cache.c policy_cache.h parser.h
> >  	$(CXX) $(EXTRA_CFLAGS) -c -o $@ $<
> >  
> >  kernel_interface.o: kernel_interface.c kernel_interface.h
> > diff --git a/parser/features.c b/parser/features.c
> > deleted file mode 100644
> > index 8b9844f..0000000
> > --- a/parser/features.c
> > +++ /dev/null
> > @@ -1,448 +0,0 @@
> > -/*
> > - *   Copyright (c) 2014
> > - *   Canonical, Ltd. (All rights reserved)
> > - *
> > - *   This program is free software; you can redistribute it and/or
> > - *   modify it under the terms of version 2 of the GNU General Public
> > - *   License published by the Free Software Foundation.
> > - *
> > - *   This program is distributed in the hope that it will be useful,
> > - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > - *   GNU General Public License for more details.
> > - *
> > - *   You should have received a copy of the GNU General Public License
> > - *   along with this program; if not, contact Novell, Inc. or Canonical
> > - *   Ltd.
> > - */
> > -
> > -#include <errno.h>
> > -#include <ctype.h>
> > -#include <fcntl.h>
> > -#include <stdio.h>
> > -#include <string.h>
> > -#include <stdarg.h>
> > -#include <stdlib.h>
> > -#include <sys/types.h>
> > -#include <sys/stat.h>
> > -#include <unistd.h>
> > -
> > -#include "features.h"
> > -#include "lib.h"
> > -#include "parser.h"
> > -
> > -#define FEATURES_FILE "/sys/kernel/security/" MODULE_NAME "/features"
> > -
> > -#define STRING_SIZE 8192
> > -
> > -struct aa_features {
> > -	unsigned int ref_count;
> > -	char string[STRING_SIZE];
> > -};
> > -
> > -struct features_struct {
> > -	char *buffer;
> > -	int size;
> > -	char *pos;
> > -};
> > -
> > -static int features_snprintf(struct features_struct *fst, const char *fmt, ...)
> > -{
> > -	va_list args;
> > -	int i, remaining = fst->size - (fst->pos - fst->buffer);
> > -
> > -	if (remaining < 0) {
> > -		errno = EINVAL;
> > -		PERROR("Invalid features buffer offset\n");
> > -		return -1;
> > -	}
> > -
> > -	va_start(args, fmt);
> > -	i = vsnprintf(fst->pos, remaining, fmt, args);
> > -	va_end(args);
> > -
> > -	if (i < 0) {
> > -		errno = EIO;
> > -		PERROR("Failed to write to features buffer\n");
> > -		return -1;
> > -	} else if (i >= remaining) {
> > -		errno = ENOBUFS;
> > -		PERROR("Feature buffer full.");
> > -		return -1;
> > -	}
> > -
> > -	fst->pos += i;
> > -	return 0;
> > -}
> > -
> > -static int features_dir_cb(DIR *dir, const char *name, struct stat *st,
> > -			   void *data)
> > -{
> > -	struct features_struct *fst = (struct features_struct *) data;
> > -
> > -	/* skip dot files and files with no name */
> > -	if (*name == '.' || !strlen(name))
> > -		return 0;
> > -
> > -	if (features_snprintf(fst, "%s {", name) == -1)
> > -		return -1;
> > -
> > -	if (S_ISREG(st->st_mode)) {
> > -		autoclose int file = -1;
> > -		int len;
> > -		int remaining = fst->size - (fst->pos - fst->buffer);
> > -
> > -		file = openat(dirfd(dir), name, O_RDONLY);
> > -		if (file == -1) {
> > -			PDEBUG("Could not open '%s'", name);
> > -			return -1;
> > -		}
> > -		PDEBUG("Opened features \"%s\"\n", name);
> > -		if (st->st_size > remaining) {
> > -			PDEBUG("Feature buffer full.");
> > -			errno = ENOBUFS;
> > -			return -1;
> > -		}
> > -
> > -		do {
> > -			len = read(file, fst->pos, remaining);
> > -			if (len > 0) {
> > -				remaining -= len;
> > -				fst->pos += len;
> > -				*fst->pos = 0;
> > -			}
> > -		} while (len > 0);
> > -		if (len < 0) {
> > -			PDEBUG("Error reading feature file '%s'\n", name);
> > -			return -1;
> > -		}
> > -	} else if (S_ISDIR(st->st_mode)) {
> > -		if (dirat_for_each(dir, name, fst, features_dir_cb))
> > -			return -1;
> > -	}
> > -
> > -	if (features_snprintf(fst, "}\n") == -1)
> > -		return -1;
> > -
> > -	return 0;
> > -}
> > -
> > -static int handle_features_dir(const char *filename, char *buffer, int size,
> > -			       char *pos)
> > -{
> > -	struct features_struct fst = { buffer, size, pos };
> > -
> > -	if (dirat_for_each(NULL, filename, &fst, features_dir_cb)) {
> > -		PDEBUG("Failed evaluating %s\n", filename);
> > -		return -1;
> > -	}
> > -
> > -	return 0;
> > -}
> > -
> > -static int load_features_file(const char *name, char *buffer, size_t size)
> > -{
> > -	autofclose FILE *f = NULL;
> > -	size_t end;
> > -
> > -	f = fopen(name, "r");
> > -	if (!f)
> > -		return -1;
> > -
> > -	errno = 0;
> > -	end = fread(buffer, 1, size - 1, f);
> > -	if (ferror(f)) {
> > -		if (!errno)
> > -			errno = EIO;
> > -		return -1;
> > -	}
> > -	buffer[end] = 0;
> > -
> > -	return 0;
> > -}
> > -
> > -static bool walk_one(const char **str, const char *component, bool is_top_level)
> > -{
> > -	const char *cur = *str;
> > -	uint32_t bracket_count = 0;
> > -	int i = 0;
> > -
> > -	/* Empty strings are not accepted */
> > -	if (!*cur || !component[0])
> > -		return false;
> > -
> > -	/**
> > -	 * If @component is not top-level, the first character in the string to
> > -	 * search MUST be '{'
> > -	 */
> > -	if (!is_top_level) {
> > -		if (*cur != '{')
> > -			return false;
> > -
> > -		cur++;
> > -	}
> > -
> > -	/**
> > -	 * This loop tries to find the @component in *@str. When this loops
> > -	 * completes, cur will either point one character past the end of the
> > -	 * matched @component or to the NUL terminator of *@str.
> > -	 */
> > -	while(*cur && component[i]) {
> > -		if (!isascii(*cur)) {
> > -			/* Only ASCII is expected */
> > -			return false;
> > -		} else if (*cur == '{') {
> > -			/* There's a limit to the number of opening brackets */
> > -			if (bracket_count == UINT32_MAX)
> > -				return false;
> > -
> > -			bracket_count++;
> > -		} else if (*cur == '}') {
> > -			/* Check for unexpected closing brackets */
> > -			if (bracket_count == 0)
> > -				return false;
> > -
> > -			bracket_count--;
> > -		}
> > -
> > -		/**
> > -		 * Move to the next character in @component if we have a match
> > -		 * and either @component is not top-level or, if @component is
> > -		 * top-level, we're not inside of brackets
> > -		 */
> > -		if (*cur == component[i] &&
> > -		    (!is_top_level || bracket_count == 0))
> > -			i++;
> > -		else
> > -			i = 0;
> > -
> > -		cur++;
> > -	}
> > -
> > -	/* A full match was not found if component[i] is non-NUL */
> > -	if (component[i])
> > -		return false;
> > -
> > -	/**
> > -	 * This loop eats up valid (ASCII) characters until a non-bracket or
> > -	 * non-space character is found so that *@str is properly set to call
> > -	 * back into this function, if necessary
> > -	 */
> > -	while (*cur) {
> > -		if (!isascii(*cur))
> > -			return false;
> > -		else if (*cur == '{' || *cur == '}' || !isspace(*cur))
> > -			break;
> > -
> > -		cur++;
> > -	}
> > -
> > -	*str = cur;
> > -	return true;
> > -}
> > -
> > -/**
> > - * aa_features_new - create a new features based on a path
> > - * @features: will point to the address of an allocated and initialized
> > - *            aa_features object upon success
> > - * @path: path to a features file or directory
> > - *
> > - * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > - *          NULL
> > - */
> > -int aa_features_new(aa_features **features, const char *path)
> > -{
> > -	struct stat stat_file;
> > -	aa_features *f;
> > -	int retval;
> > -
> > -	*features = NULL;
> > -
> > -	if (stat(path, &stat_file) == -1)
> > -		return -1;
> > -
> > -	f = (aa_features *) calloc(1, sizeof(*f));
> > -	if (!f) {
> > -		errno = ENOMEM;
> > -		return -1;
> > -	}
> > -	aa_features_ref(f);
> > -
> > -	retval = S_ISDIR(stat_file.st_mode) ?
> > -		 handle_features_dir(path, f->string, STRING_SIZE, f->string) :
> > -		 load_features_file(path, f->string, STRING_SIZE);
> > -	if (retval) {
> > -		int save = errno;
> > -
> > -		aa_features_unref(f);
> > -		errno = save;
> > -		return -1;
> > -	}
> > -
> > -	*features = f;
> > -
> > -	return 0;
> > -}
> > -
> > -/**
> > - * aa_features_new_from_string - create a new features based on a string
> > - * @features: will point to the address of an allocated and initialized
> > - *            aa_features object upon success
> > - * @string: a NUL-terminated string representation of features
> > - * @size: the size of @string, not counting the NUL-terminator
> > - *
> > - * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > - *          NULL
> > - */
> > -int aa_features_new_from_string(aa_features **features,
> > -				const char *string, size_t size)
> > -{
> > -	aa_features *f;
> > -
> > -	*features = NULL;
> > -
> > -	/* Require size to be less than STRING_SIZE so there's room for a NUL */
> > -	if (size >= STRING_SIZE)
> > -		return ENOBUFS;
> > -
> > -	f = (aa_features *) calloc(1, sizeof(*f));
> > -	if (!f) {
> > -		errno = ENOMEM;
> > -		return -1;
> > -	}
> > -	aa_features_ref(f);
> > -
> > -	memcpy(f->string, string, size);
> > -	f->string[size] = '\0';
> > -	*features = f;
> > -
> > -	return 0;
> > -}
> > -
> > -/**
> > - * aa_features_new_from_kernel - create a new features based on the current kernel
> > - * @features: will point to the address of an allocated and initialized
> > - *            aa_features object upon success
> > - *
> > - * Returns: 0 on success, -1 on error with errno set and *@features pointing to
> > - *          NULL
> > - */
> > -int aa_features_new_from_kernel(aa_features **features)
> > -{
> > -	return aa_features_new(features, FEATURES_FILE);
> > -}
> > -
> > -/**
> > - * aa_features_ref - increments the ref count of a features
> > - * @features: the features
> > - *
> > - * Returns: the features
> > - */
> > -aa_features *aa_features_ref(aa_features *features)
> > -{
> > -	atomic_inc(&features->ref_count);
> > -	return features;
> > -}
> > -
> > -/**
> > - * aa_features_unref - decrements the ref count and frees the features when 0
> > - * @features: the features (can be NULL)
> > - */
> > -void aa_features_unref(aa_features *features)
> > -{
> > -	if (features && atomic_dec_and_test(&features->ref_count))
> > -		free(features);
> > -}
> > -
> > -/**
> > - * aa_features_write_to_file - write a string representation to a file
> > - * @features: the features
> > - * @path: the path to write to
> > - *
> > - * Returns: 0 on success, -1 on error with errno set
> > - */
> > -int aa_features_write_to_file(aa_features *features, const char *path)
> > -{
> > -	autoclose int fd = -1;
> > -	size_t size;
> > -	ssize_t retval;
> > -	char *string;
> > -
> > -	fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC | O_CLOEXEC,
> > -		  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
> > -	if (fd == -1)
> > -		return -1;
> > -
> > -	string = features->string;
> > -	size = strlen(string);
> > -	do {
> > -		retval = write(fd, string, size);
> > -		if (retval == -1)
> > -			return -1;
> > -
> > -		size -= retval;
> > -		string += retval;
> > -	} while (size);
> > -
> > -	return 0;
> > -}
> > -
> > -/**
> > - * aa_features_is_equal - equality test for two features
> > - * @features1: the first features (can be NULL)
> > - * @features2: the second features (can be NULL)
> > - *
> > - * Returns: true if they're equal, false if they're not or either are NULL
> > - */
> > -bool aa_features_is_equal(aa_features *features1, aa_features *features2)
> > -{
> > -	return features1 && features2 &&
> > -	       strcmp(features1->string, features2->string) == 0;
> > -}
> > -
> > -/**
> > - * aa_features_supports - provides features support status
> > - * @features: the features
> > - * @str: the string representation of a feature to check
> > - *
> > - * Example @str values are "dbus/mask/send", "caps/mask/audit_read", and
> > - * "policy/versions/v7".
> > - *
> > - * Returns: a bool specifying the support status of @str feature
> > - */
> > -bool aa_features_supports(aa_features *features, char *str)
> > -{
> > -	const char *features_string = features->string;
> > -	char *components[32];
> > -	char *saveptr = NULL;
> > -	size_t i;
> > -
> > -	/* Empty strings are not accepted. Neither are leading '/' chars. */
> > -	if (!str || str[0] == '/')
> > -		return false;
> > -
> > -	/**
> > -	 * Break @str into an array of components. For example,
> > -	 * "mount/mask/mount" would turn into "mount" as the first component,
> > -	 * "mask" as the second, and "mount" as the third
> > -	 */
> > -	for (i = 0; i < sizeof(components); i++) {
> > -		components[i] = strtok_r(str, "/", &saveptr);
> > -		if (!components[i])
> > -			break;
> > -
> > -		str = NULL;
> > -	}
> > -
> > -	/* At least one valid token is required */
> > -	if (!components[0])
> > -		return false;
> > -
> > -	/* Ensure that all components are valid and found */
> > -	for (i = 0; i < sizeof(components) && components[i]; i++) {
> > -		if (!walk_one(&features_string, components[i], i == 0))
> > -			return false;
> > -	}
> > -
> > -	return true;
> > -}
> > diff --git a/parser/features.h b/parser/features.h
> > deleted file mode 100644
> > index 1d3cf3f..0000000
> > --- a/parser/features.h
> > +++ /dev/null
> > @@ -1,34 +0,0 @@
> > -/*
> > - *   Copyright (c) 2014
> > - *   Canonical, Ltd. (All rights reserved)
> > - *
> > - *   This program is free software; you can redistribute it and/or
> > - *   modify it under the terms of version 2 of the GNU General Public
> > - *   License published by the Free Software Foundation.
> > - *
> > - *   This program is distributed in the hope that it will be useful,
> > - *   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > - *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > - *   GNU General Public License for more details.
> > - *
> > - *   You should have received a copy of the GNU General Public License
> > - *   along with this program; if not, contact Novell, Inc. or Canonical
> > - *   Ltd.
> > - */
> > -
> > -#ifndef __AA_FEATURES_H
> > -#define __AA_FEATURES_H
> > -
> > -typedef struct aa_features aa_features;
> > -
> > -int aa_features_new(aa_features **features, const char *path);
> > -int aa_features_new_from_string(aa_features **features,
> > -				const char *string, size_t size);
> > -int aa_features_new_from_kernel(aa_features **features);
> > -aa_features *aa_features_ref(aa_features *features);
> > -void aa_features_unref(aa_features *features);
> > -int aa_features_write_to_file(aa_features *features, const char *path);
> > -bool aa_features_is_equal(aa_features *features1, aa_features *features2);
> > -bool aa_features_supports(aa_features *features, char *str);
> > -
> > -#endif /* __AA_FEATURES_H */
> > diff --git a/parser/kernel_interface.h b/parser/kernel_interface.h
> > index 6dcd3ca..8e210d1 100644
> > --- a/parser/kernel_interface.h
> > +++ b/parser/kernel_interface.h
> > @@ -19,6 +19,8 @@
> >  #ifndef __AA_KERNEL_INTERFACE_H
> >  #define __AA_KERNEL_INTERFACE_H
> >  
> > +#include <sys/apparmor.h>
> > +
> >  #include "features.h"
> >  
> >  typedef struct aa_kernel_interface aa_kernel_interface;
> > 
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20150312/35a71be1/attachment-0001.pgp>


More information about the AppArmor mailing list