[apparmor] [PATCH v2 36/42] libapparmor: Move the aa_features API
John Johansen
john.johansen at canonical.com
Thu Mar 12 12:03:49 UTC 2015
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
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;
>
More information about the AppArmor
mailing list