diff --git a/libraries/libapparmor/include/sys/apparmor.h b/libraries/libapparmor/include/sys/apparmor.h index c715040ab..99ce36b96 100644 --- a/libraries/libapparmor/include/sys/apparmor.h +++ b/libraries/libapparmor/include/sys/apparmor.h @@ -139,6 +139,19 @@ int aa_kernel_interface_remove_policy(aa_kernel_interface *kernel_interface, const char *fqname); int aa_kernel_interface_write_policy(int fd, const char *buffer, size_t size); +typedef struct aa_policy_cache aa_policy_cache; +int aa_policy_cache_new(aa_policy_cache **policy_cache, + aa_features *kernel_features, const char *path, + bool create); +aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache); +void aa_policy_cache_unref(aa_policy_cache *policy_cache); + +bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache); +int aa_policy_cache_create(aa_policy_cache *policy_cache); +int aa_policy_cache_remove(const char *path); +int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, + aa_kernel_interface *kernel_interface); + __END_DECLS #endif /* sys/apparmor.h */ diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am index 54adc845a..505d1f70b 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.c scanner.c private.c features.c kernel_interface.c +libapparmor_la_SOURCES = grammar.y libaalogparse.c kernel.c scanner.c private.c features.c kernel_interface.c policy_cache.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/libapparmor.map b/libraries/libapparmor/src/libapparmor.map index 0fdbd7707..3f434941f 100644 --- a/libraries/libapparmor/src/libapparmor.map +++ b/libraries/libapparmor/src/libapparmor.map @@ -73,6 +73,13 @@ APPARMOR_2.10 { aa_kernel_interface_replace_policy_from_fd; aa_kernel_interface_remove_policy; aa_kernel_interface_write_policy; + aa_policy_cache_new; + aa_policy_cache_ref; + aa_policy_cache_unref; + aa_policy_cache_is_valid; + aa_policy_cache_create; + aa_policy_cache_remove; + aa_policy_cache_replace_all; local: *; } APPARMOR_2.9; diff --git a/libraries/libapparmor/src/policy_cache.c b/libraries/libapparmor/src/policy_cache.c new file mode 100644 index 000000000..d9ec4a128 --- /dev/null +++ b/libraries/libapparmor/src/policy_cache.c @@ -0,0 +1,279 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private.h" + +struct aa_policy_cache { + unsigned int ref_count; + aa_features *features; + aa_features *kernel_features; + char *path; + char *features_path; +}; + +static int clear_cache_cb(DIR *dir, const char *path, struct stat *st, + void *data unused) +{ + /* remove regular files */ + if (S_ISREG(st->st_mode)) + return unlinkat(dirfd(dir), path, 0); + + /* do nothing with other file types */ + return 0; +} + +static int create_cache(aa_policy_cache *policy_cache, aa_features *features) +{ + struct stat stat_file; + autofclose FILE * f = NULL; + + if (aa_policy_cache_remove(policy_cache->path)) + goto error; + +create_file: + if (aa_features_write_to_file(features, + policy_cache->features_path) == -1) + goto error; + + aa_features_unref(policy_cache->features); + policy_cache->features = aa_features_ref(features); + return 0; + +error: + /* does the dir exist? */ + if (stat(policy_cache->path, &stat_file) == -1) { + if (mkdir(policy_cache->path, 0700) == 0) + goto create_file; + PERROR("Can't create cache directory: %s\n", + policy_cache->path); + } else if (!S_ISDIR(stat_file.st_mode)) { + PERROR("File in cache directory location: %s\n", + policy_cache->path); + } else { + PERROR("Can't update cache directory: %s\n", + policy_cache->path); + } + + return -1; +} + +static int init_cache_features(aa_policy_cache *policy_cache, + aa_features *kernel_features, bool create) +{ + if (aa_features_new(&policy_cache->features, + policy_cache->features_path)) { + policy_cache->features = NULL; + if (!create || errno != ENOENT) + return -1; + + return create_cache(policy_cache, kernel_features); + } + + return 0; +} + +struct replace_all_cb_data { + aa_policy_cache *policy_cache; + aa_kernel_interface *kernel_interface; +}; + +static int replace_all_cb(DIR *dir unused, const char *name, struct stat *st, + void *cb_data) +{ + int retval = 0; + + if (!S_ISDIR(st->st_mode) && !_aa_is_blacklisted(name, NULL)) { + struct replace_all_cb_data *data; + autofree char *path = NULL; + + data = (struct replace_all_cb_data *) cb_data; + if (asprintf(&path, "%s/%s", + data->policy_cache->path, name) < 0) { + path = NULL; + errno = ENOMEM; + return -1; + } + retval = aa_kernel_interface_replace_policy_from_file(data->kernel_interface, + path); + } + + return retval; +} + +/** + * aa_policy_cache_new - create a new policy_cache from a path + * @policy_cache: will point to the address of an allocated and initialized + * aa_policy_cache_new object upon success + * @kernel_features: features representing the currently running kernel + * @path: path to the policy cache + * @create: true if the cache should be created if it doesn't already exist + * + * Returns: 0 on success, -1 on error with errno set and *@policy_cache + * pointing to NULL + */ +int aa_policy_cache_new(aa_policy_cache **policy_cache, + aa_features *kernel_features, const char *path, + bool create) +{ + aa_policy_cache *pc; + + *policy_cache = NULL; + + if (!path) { + errno = EINVAL; + return -1; + } + + pc = (aa_policy_cache *) calloc(1, sizeof(*pc)); + if (!pc) { + errno = ENOMEM; + return -1; + } + aa_policy_cache_ref(pc); + + pc->path = strdup(path); + if (!pc->path) { + aa_policy_cache_unref(pc); + errno = ENOMEM; + return -1; + } + + if (asprintf(&pc->features_path, "%s/.features", pc->path) == -1) { + pc->features_path = NULL; + aa_policy_cache_unref(pc); + errno = ENOMEM; + return -1; + } + + if (init_cache_features(pc, kernel_features, create)) { + int save = errno; + + aa_policy_cache_unref(pc); + errno = save; + return -1; + } + + pc->kernel_features = aa_features_ref(kernel_features); + *policy_cache = pc; + + return 0; +} + +/** + * aa_policy_cache_ref - increments the ref count of a policy_cache + * @policy_cache: the policy_cache + * + * Returns: the policy_cache + */ +aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache) +{ + atomic_inc(&policy_cache->ref_count); + return policy_cache; +} + +/** + * aa_policy_cache_unref - decrements the ref count and frees the policy_cache when 0 + * @policy_cache: the policy_cache (can be NULL) + */ +void aa_policy_cache_unref(aa_policy_cache *policy_cache) +{ + if (policy_cache && atomic_dec_and_test(&policy_cache->ref_count)) { + free(policy_cache->features_path); + free(policy_cache->path); + free(policy_cache); + } +} + +/** + * aa_policy_cache_is_valid - checks if the policy_cache is valid for the currently running kernel + * @policy_cache: the policy_cache + * + * Returns: true if the policy_cache is valid for the currently running kernel, + * false if not + */ +bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache) +{ + return aa_features_is_equal(policy_cache->features, + policy_cache->kernel_features); +} + +/** + * aa_policy_cache_create - creates a valid policy_cache for the currently running kernel + * @policy_cache: the policy_cache + * + * Returns: 0 on success, -1 on error with errno set and features pointing to + * NULL + */ +int aa_policy_cache_create(aa_policy_cache *policy_cache) +{ + return create_cache(policy_cache, policy_cache->kernel_features); +} + +/** + * aa_policy_cache_remove - removes all policy cache files under a path + * @path: the path to a policy cache directory + * + * Returns: 0 on success, -1 on error with errno set + */ +int aa_policy_cache_remove(const char *path) +{ + return _aa_dirat_for_each(NULL, path, NULL, clear_cache_cb); +} + +/** + * aa_policy_cache_replace_all - performs a kernel policy replacement of all cached policies + * @policy_cache: the policy_cache + * @kernel_interface: the kernel interface to use when doing the replacement + * + * Returns: 0 on success, -1 on error with errno set and features pointing to + * NULL + */ +int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, + aa_kernel_interface *kernel_interface) +{ + struct replace_all_cb_data cb_data; + int retval; + + if (kernel_interface) { + aa_kernel_interface_ref(kernel_interface); + } else if (aa_kernel_interface_new(&kernel_interface, + policy_cache->kernel_features, + NULL) == -1) { + kernel_interface = NULL; + return -1; + } + + cb_data.policy_cache = policy_cache; + cb_data.kernel_interface = kernel_interface; + retval = _aa_dirat_for_each(NULL, policy_cache->path, &cb_data, + replace_all_cb); + + aa_kernel_interface_unref(kernel_interface); + + return retval; +} diff --git a/parser/policy_cache.c b/parser/policy_cache.c index c28a98186..fc4912edd 100644 --- a/parser/policy_cache.c +++ b/parser/policy_cache.c @@ -32,14 +32,6 @@ #define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x))) -struct aa_policy_cache { - unsigned int ref_count; - aa_features *features; - aa_features *kernel_features; - char *path; - char *features_path; -}; - const char header_string[] = "\004\010\000version\000\002"; #define HEADER_STRING_SIZE 12 bool valid_cached_file_version(const char *cachename) @@ -96,52 +88,6 @@ void update_mru_tstamp(FILE *file, const char *name) } } -static int clear_cache_cb(DIR *dir, const char *path, struct stat *st, - void *data unused) -{ - /* remove regular files */ - if (S_ISREG(st->st_mode)) - return unlinkat(dirfd(dir), path, 0); - - /* do nothing with other file types */ - return 0; -} - -static int create_cache(aa_policy_cache *policy_cache, aa_features *features) -{ - struct stat stat_file; - autofclose FILE * f = NULL; - - if (aa_policy_cache_remove(policy_cache->path)) - goto error; - -create_file: - if (aa_features_write_to_file(features, - policy_cache->features_path) == -1) - goto error; - - aa_features_unref(policy_cache->features); - policy_cache->features = aa_features_ref(features); - return 0; - -error: - /* does the dir exist? */ - if (stat(policy_cache->path, &stat_file) == -1) { - if (mkdir(policy_cache->path, 0700) == 0) - goto create_file; - PERROR("Can't create cache directory: %s\n", - policy_cache->path); - } else if (!S_ISDIR(stat_file.st_mode)) { - PERROR("File in cache directory location: %s\n", - policy_cache->path); - } else { - PERROR("Can't update cache directory: %s\n", - policy_cache->path); - } - - return -1; -} - char *cache_filename(const char *cachedir, const char *basename) { char *cachename; @@ -222,199 +168,3 @@ void install_cache(const char *cachetmpname, const char *cachename) } } } - -static int init_cache_features(aa_policy_cache *policy_cache, - aa_features *kernel_features, bool create) -{ - if (aa_features_new(&policy_cache->features, - policy_cache->features_path)) { - policy_cache->features = NULL; - if (!create || errno != ENOENT) - return -1; - - return create_cache(policy_cache, kernel_features); - } - - return 0; -} - -struct replace_all_cb_data { - aa_policy_cache *policy_cache; - aa_kernel_interface *kernel_interface; -}; - -static int replace_all_cb(DIR *dir unused, const char *name, struct stat *st, - void *cb_data) -{ - int retval = 0; - - if (!S_ISDIR(st->st_mode) && !is_blacklisted(name, NULL)) { - struct replace_all_cb_data *data; - autofree char *path = NULL; - - data = (struct replace_all_cb_data *) cb_data; - if (asprintf(&path, "%s/%s", - data->policy_cache->path, name) < 0) { - path = NULL; - errno = ENOMEM; - return -1; - } - retval = aa_kernel_interface_replace_policy_from_file(data->kernel_interface, - path); - } - - return retval; -} - -/** - * aa_policy_cache_new - create a new policy_cache from a path - * @policy_cache: will point to the address of an allocated and initialized - * aa_policy_cache_new object upon success - * @kernel_features: features representing the currently running kernel - * @path: path to the policy cache - * @create: true if the cache should be created if it doesn't already exist - * - * Returns: 0 on success, -1 on error with errno set and *@policy_cache - * pointing to NULL - */ -int aa_policy_cache_new(aa_policy_cache **policy_cache, - aa_features *kernel_features, const char *path, - bool create) -{ - aa_policy_cache *pc; - - *policy_cache = NULL; - - if (!path) { - errno = EINVAL; - return -1; - } - - pc = (aa_policy_cache *) calloc(1, sizeof(*pc)); - if (!pc) { - errno = ENOMEM; - return -1; - } - aa_policy_cache_ref(pc); - - pc->path = strdup(path); - if (!pc->path) { - aa_policy_cache_unref(pc); - errno = ENOMEM; - return -1; - } - - if (asprintf(&pc->features_path, "%s/.features", pc->path) == -1) { - pc->features_path = NULL; - aa_policy_cache_unref(pc); - errno = ENOMEM; - return -1; - } - - if (init_cache_features(pc, kernel_features, create)) { - int save = errno; - - aa_policy_cache_unref(pc); - errno = save; - return -1; - } - - pc->kernel_features = aa_features_ref(kernel_features); - *policy_cache = pc; - - return 0; -} - -/** - * aa_policy_cache_ref - increments the ref count of a policy_cache - * @policy_cache: the policy_cache - * - * Returns: the policy_cache - */ -aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache) -{ - atomic_inc(&policy_cache->ref_count); - return policy_cache; -} - -/** - * aa_policy_cache_unref - decrements the ref count and frees the policy_cache when 0 - * @policy_cache: the policy_cache (can be NULL) - */ -void aa_policy_cache_unref(aa_policy_cache *policy_cache) -{ - if (policy_cache && atomic_dec_and_test(&policy_cache->ref_count)) { - free(policy_cache->features_path); - free(policy_cache->path); - free(policy_cache); - } -} - -/** - * aa_policy_cache_is_valid - checks if the policy_cache is valid for the currently running kernel - * @policy_cache: the policy_cache - * - * Returns: true if the policy_cache is valid for the currently running kernel, - * false if not - */ -bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache) -{ - return aa_features_is_equal(policy_cache->features, - policy_cache->kernel_features); -} - -/** - * aa_policy_cache_create - creates a valid policy_cache for the currently running kernel - * @policy_cache: the policy_cache - * - * Returns: 0 on success, -1 on error with errno set and features pointing to - * NULL - */ -int aa_policy_cache_create(aa_policy_cache *policy_cache) -{ - return create_cache(policy_cache, policy_cache->kernel_features); -} - -/** - * aa_policy_cache_remove - removes all policy cache files under a path - * @path: the path to a policy cache directory - * - * Returns: 0 on success, -1 on error with errno set - */ -int aa_policy_cache_remove(const char *path) -{ - return dirat_for_each(NULL, path, NULL, clear_cache_cb); -} - -/** - * aa_policy_cache_replace_all - performs a kernel policy replacement of all cached policies - * @policy_cache: the policy_cache - * @kernel_interface: the kernel interface to use when doing the replacement - * - * Returns: 0 on success, -1 on error with errno set and features pointing to - * NULL - */ -int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, - aa_kernel_interface *kernel_interface) -{ - struct replace_all_cb_data cb_data; - int retval; - - if (kernel_interface) { - aa_kernel_interface_ref(kernel_interface); - } else if (aa_kernel_interface_new(&kernel_interface, - policy_cache->kernel_features, - NULL) == -1) { - kernel_interface = NULL; - return -1; - } - - cb_data.policy_cache = policy_cache; - cb_data.kernel_interface = kernel_interface; - retval = dirat_for_each(NULL, policy_cache->path, &cb_data, - replace_all_cb); - - aa_kernel_interface_unref(kernel_interface); - - return retval; -} diff --git a/parser/policy_cache.h b/parser/policy_cache.h index 6b222da19..3c3e85d59 100644 --- a/parser/policy_cache.h +++ b/parser/policy_cache.h @@ -19,8 +19,6 @@ #ifndef __AA_POLICY_CACHE_H #define __AA_POLICY_CACHE_H -#include "features.h" - extern struct timespec mru_tstamp; /* returns true if time is more recent than mru_tstamp */ @@ -47,18 +45,4 @@ int cache_hit(const char *cachename); int setup_cache_tmp(const char **cachetmpname, const char *cachename); void install_cache(const char *cachetmpname, const char *cachename); -typedef struct aa_policy_cache aa_policy_cache; - -int aa_policy_cache_new(aa_policy_cache **policy_cache, - aa_features *kernel_features, const char *path, - bool create); -aa_policy_cache *aa_policy_cache_ref(aa_policy_cache *policy_cache); -void aa_policy_cache_unref(aa_policy_cache *policy_cache); -bool aa_policy_cache_is_valid(aa_policy_cache *policy_cache); -int aa_policy_cache_create(aa_policy_cache *policy_cache); -int aa_policy_cache_remove(const char *path); -int aa_policy_cache_replace_all(aa_policy_cache *policy_cache, - aa_kernel_interface *kernel_interface); - - #endif /* __AA_POLICY_CACHE_H */