From deec20512b049ca1d5060732b2d6095bdfa47583 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 25 Mar 2015 17:09:27 -0500 Subject: [PATCH] libapparmor: Move over the lib functions needed by cache loading code The function names must be prepended with "_aa_" since they're going to be exported from libapparmor. The code bases using the _aa_autofree(), _aa_autoclose(), and _aa_autofclose() will need to internally alias those functions to the previously used autofree, autoclose, and autofclose names. Signed-off-by: Tyler Hicks Acked-by: Seth Arnold Acked-by: John Johansen --- .../include/sys/apparmor_private.h | 11 ++ libraries/libapparmor/src/Makefile.am | 2 +- libraries/libapparmor/src/libapparmor.map | 4 + libraries/libapparmor/src/private.c | 145 ++++++++++++++++++ libraries/libapparmor/src/private.h | 10 ++ libraries/libapparmor/src/tst_aalogmisc.c | 8 +- parser/lib.c | 140 +---------------- parser/lib.h | 11 +- 8 files changed, 182 insertions(+), 149 deletions(-) diff --git a/libraries/libapparmor/include/sys/apparmor_private.h b/libraries/libapparmor/include/sys/apparmor_private.h index 6138b2cb7..5cf4c25c7 100644 --- a/libraries/libapparmor/include/sys/apparmor_private.h +++ b/libraries/libapparmor/include/sys/apparmor_private.h @@ -17,10 +17,21 @@ #ifndef _SYS_APPARMOR_PRIVATE_H #define _SYS_APPARMOR_PRIVATE_H 1 +#include +#include +#include + __BEGIN_DECLS int _aa_is_blacklisted(const char *name, const char *path); +void _aa_autofree(void *p); +void _aa_autoclose(int *fd); +void _aa_autofclose(FILE **f); + +int _aa_dirat_for_each(DIR *dir, const char *name, void *data, + int (* cb)(DIR *, const char *, struct stat *, void *)); + __END_DECLS #endif /* sys/apparmor_private.h */ diff --git a/libraries/libapparmor/src/Makefile.am b/libraries/libapparmor/src/Makefile.am index e1d1fac37..42934d0fe 100644 --- a/libraries/libapparmor/src/Makefile.am +++ b/libraries/libapparmor/src/Makefile.am @@ -46,7 +46,7 @@ af_protos.h: /usr/include/netinet/in.h LC_ALL=C sed -n -e "/IPPROTO_MAX/d" -e "s/^\#define[ \\t]\\+IPPROTO_\\([A-Z0-9_]\\+\\)\\(.*\\)$$/AA_GEN_PROTO_ENT(\\UIPPROTO_\\1, \"\\L\\1\")/p" $< > $@ lib_LTLIBRARIES = libapparmor.la -noinst_HEADERS = grammar.h parser.h scanner.h af_protos.h +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_LDFLAGS = -version-info $(AA_LIB_CURRENT):$(AA_LIB_REVISION):$(AA_LIB_AGE) -XCClinker -dynamic -pthread \ diff --git a/libraries/libapparmor/src/libapparmor.map b/libraries/libapparmor/src/libapparmor.map index c7bc60686..1ea221f7d 100644 --- a/libraries/libapparmor/src/libapparmor.map +++ b/libraries/libapparmor/src/libapparmor.map @@ -55,6 +55,10 @@ APPARMOR_2.9 { PRIVATE { global: _aa_is_blacklisted; + _aa_autofree; + _aa_autoclose; + _aa_autofclose; + _aa_dirat_for_each; local: *; }; diff --git a/libraries/libapparmor/src/private.c b/libraries/libapparmor/src/private.c index eb3c0f8f0..6431270da 100644 --- a/libraries/libapparmor/src/private.c +++ b/libraries/libapparmor/src/private.c @@ -14,12 +14,21 @@ * along with this program. If not, see . */ +#include +#include +#include #include #include +#include #include #include #include #include +#include +#include +#include + +#include "private.h" struct ignored_suffix_t { const char * text; @@ -98,3 +107,139 @@ int _aa_is_blacklisted(const char *name, const char *path) return 0; } + +/* automaticly free allocated variables tagged with autofree on fn exit */ +void _aa_autofree(void *p) +{ + void **_p = (void**)p; + free(*_p); +} + +void _aa_autoclose(int *fd) +{ + if (*fd != -1) { + /* if close was interrupted retry */ + while(close(*fd) == -1 && errno == EINTR); + *fd = -1; + } +} + +void _aa_autofclose(FILE **f) +{ + if (*f) { + fclose(*f); + *f = NULL; + } +} + +/** + * _aa_dirat_for_each: iterate over a directory calling cb for each entry + * @dir: already opened directory (MAY BE NULL) + * @name: name of the directory (MAY BE NULL) + * @data: data pointer to pass to the callback fn (MAY BE NULL) + * @cb: the callback to pass entry too (NOT NULL) + * + * Iterate over the entries in a directory calling cb for each entry. + * The directory to iterate is determined by a combination of @dir and + * @name. + * + * IF @name is a relative path it is determine relative to at @dir if it + * is specified, else it the lookup is done relative to the current + * working directory. + * + * If @name is not specified then @dir is used as the directory to iterate + * over. + * + * It is an error if both @name and @dir are null + * + * The cb function is called with the DIR in use and the name of the + * file in that directory. If the file is to be opened it should + * use the openat, fstatat, and related fns. + * + * Returns: 0 on success, else -1 and errno is set to the error code + */ +int _aa_dirat_for_each(DIR *dir, const char *name, void *data, + int (* cb)(DIR *, const char *, struct stat *, void *)) +{ + autofree struct dirent *dirent = NULL; + DIR *d = NULL; + int error; + + if (!cb || (!dir && !name)) { + errno = EINVAL; + return -1; + } + + if (dir && (!name || *name != '/')) { + dirent = (struct dirent *) + malloc(offsetof(struct dirent, d_name) + + fpathconf(dirfd(dir), _PC_NAME_MAX) + 1); + } else { + dirent = (struct dirent *) + malloc(offsetof(struct dirent, d_name) + + pathconf(name, _PC_NAME_MAX) + 1); + } + if (!dirent) { + errno = ENOMEM; + PDEBUG("could not alloc dirent: %m\n"); + return -1; + } + + if (name) { + if (dir && *name != '/') { + int fd = openat(dirfd(dir), name, O_RDONLY); + if (fd == -1) + goto fail; + d = fdopendir(fd); + } else { + d = opendir(name); + } + PDEBUG("Open dir '%s': %s\n", name, d ? "succeeded" : "failed"); + if (!(d)) + goto fail; + } else { /* dir && !name */ + PDEBUG("Recieved cache directory\n"); + d = dir; + } + + for (;;) { + struct dirent *ent; + struct stat my_stat; + + error = readdir_r(d, dirent, &ent); + if (error) { + errno = error; /* readdir_r directly returns an errno */ + PDEBUG("readdir_r failed: %m\n"); + goto fail; + } else if (!ent) { + break; + } + + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + continue; + + if (fstatat(dirfd(d), ent->d_name, &my_stat, 0)) { + PDEBUG("stat failed for '%s': %m\n", name); + goto fail; + } + + if (cb(d, ent->d_name, &my_stat, data)) { + PDEBUG("dir_for_each callback failed\n"); + goto fail; + } + } + + if (d != dir) + closedir(d); + + return 0; + +fail: + error = errno; + if (d && d != dir) + closedir(d); + errno = error; + + return -1; +} diff --git a/libraries/libapparmor/src/private.h b/libraries/libapparmor/src/private.h index a3c582df6..4a53bfdec 100644 --- a/libraries/libapparmor/src/private.h +++ b/libraries/libapparmor/src/private.h @@ -19,6 +19,10 @@ #include +#define autofree __attribute((cleanup(_aa_autofree))) +#define autoclose __attribute((cleanup(_aa_autoclose))) +#define autofclose __attribute((cleanup(_aa_autofclose))) + #if ENABLE_DEBUG_OUTPUT #define PERROR(fmt, args...) print_error(true, "libapparmor", fmt, ## args) @@ -31,6 +35,12 @@ #endif /* ENABLE_DEBUG_OUTPUT */ +#define MY_TEST(statement, error) \ + if (!(statement)) { \ + fprintf(stderr, "FAIL: %s\n", error); \ + rc = 1; \ + } + void print_error(bool honor_env_var, const char *ident, const char *fmt, ...); void print_debug(const char *fmt, ...); diff --git a/libraries/libapparmor/src/tst_aalogmisc.c b/libraries/libapparmor/src/tst_aalogmisc.c index 73aceebee..b15392fcb 100644 --- a/libraries/libapparmor/src/tst_aalogmisc.c +++ b/libraries/libapparmor/src/tst_aalogmisc.c @@ -20,13 +20,7 @@ #include #include #include "parser.h" - - -#define MY_TEST(statement, error) \ - if (!(statement)) { \ - fprintf(stderr, "FAIL: %s\n", error); \ - rc = 1; \ - } +#include "private.h" int main(void) { diff --git a/parser/lib.c b/parser/lib.c index 008027b7b..15e975da3 100644 --- a/parser/lib.c +++ b/parser/lib.c @@ -17,46 +17,18 @@ */ #include -#include -#include -#include #include -#include -#include -#include #include #include #include +#include + #include "lib.h" #include "parser.h" -/* automaticly free allocated variables tagged with autofree on fn exit */ -void __autofree(void *p) -{ - void **_p = (void**)p; - free(*_p); -} - -void __autoclose(int *fd) -{ - if (*fd != -1) { - /* if close was interrupted retry */ - while(close(*fd) == -1 && errno == EINTR); - *fd = -1; - } -} - -void __autofclose(FILE **f) -{ - if (*f) { - fclose(*f); - *f = NULL; - } -} - void atomic_inc(unsigned int *v) { __sync_add_and_fetch(v, 1); @@ -67,115 +39,15 @@ bool atomic_dec_and_test(unsigned int *v) return __sync_sub_and_fetch(v, 1) == 0; } -/** - * dirat_for_each: iterate over a directory calling cb for each entry - * @dir: already opened directory (MAY BE NULL) - * @name: name of the directory (MAY BE NULL) - * @data: data pointer to pass to the callback fn (MAY BE NULL) - * @cb: the callback to pass entry too (NOT NULL) - * - * Iterate over the entries in a directory calling cb for each entry. - * The directory to iterate is determined by a combination of @dir and - * @name. - * - * IF @name is a relative path it is determine relative to at @dir if it - * is specified, else it the lookup is done relative to the current - * working directory. - * - * If @name is not specified then @dir is used as the directory to iterate - * over. - * - * It is an error if both @name and @dir are null - * - * The cb function is called with the DIR in use and the name of the - * file in that directory. If the file is to be opened it should - * use the openat, fstatat, and related fns. - * - * Returns: 0 on success, else -1 and errno is set to the error code - */ int dirat_for_each(DIR *dir, const char *name, void *data, int (* cb)(DIR *, const char *, struct stat *, void *)) { - autofree struct dirent *dirent = NULL; - DIR *d = NULL; - int error; + int retval = _aa_dirat_for_each(dir, name, data, cb); - if (!cb || (!dir && !name)) { - errno = EINVAL; - return -1; - } + if (retval) + PDEBUG("dirat_for_each failed: %m\n"); - if (dir && (!name || *name != '/')) { - dirent = (struct dirent *) - malloc(offsetof(struct dirent, d_name) + - fpathconf(dirfd(dir), _PC_NAME_MAX) + 1); - } else { - dirent = (struct dirent *) - malloc(offsetof(struct dirent, d_name) + - pathconf(name, _PC_NAME_MAX) + 1); - } - if (!dirent) { - PDEBUG("could not alloc dirent"); - return -1; - } - - if (name) { - if (dir && *name != '/') { - int fd = openat(dirfd(dir), name, O_RDONLY); - if (fd == -1) - goto fail; - d = fdopendir(fd); - } else { - d = opendir(name); - } - PDEBUG("Open dir '%s': %s\n", name, d ? "succeeded" : "failed"); - if (!(d)) - goto fail; - } else { /* dir && !name */ - PDEBUG("Recieved cache directory\n"); - d = dir; - } - - for (;;) { - struct dirent *ent; - struct stat my_stat; - - error = readdir_r(d, dirent, &ent); - if (error) { - PDEBUG("readdir_r failed"); - errno = error; /* readdir_r directly returns an errno */ - goto fail; - } else if (!ent) { - break; - } - - if (strcmp(ent->d_name, ".") == 0 || - strcmp(ent->d_name, "..") == 0) - continue; - - if (fstatat(dirfd(d), ent->d_name, &my_stat, 0)) { - PDEBUG("stat failed for '%s'", name); - goto fail; - } - - if (cb(d, ent->d_name, &my_stat, data)) { - PDEBUG("dir_for_each callback failed\n"); - goto fail; - } - } - - if (d != dir) - closedir(d); - - return 0; - -fail: - error = errno; - if (d && d != dir) - closedir(d); - errno = error; - - return -1; + return retval; } /** diff --git a/parser/lib.h b/parser/lib.h index bfe53f816..2ec745c6a 100644 --- a/parser/lib.h +++ b/parser/lib.h @@ -1,14 +1,11 @@ #ifndef __AA_LIB_H_ #define __AA_LIB_H_ -#include +#include -#define autofree __attribute((cleanup(__autofree))) -#define autoclose __attribute((cleanup(__autoclose))) -#define autofclose __attribute((cleanup(__autofclose))) -void __autofree(void *p); -void __autoclose(int *fd); -void __autofclose(FILE **f); +#define autofree __attribute((cleanup(_aa_autofree))) +#define autoclose __attribute((cleanup(_aa_autoclose))) +#define autofclose __attribute((cleanup(_aa_autofclose))) void atomic_inc(unsigned int *v); bool atomic_dec_and_test(unsigned int *v);