diff --git a/parser/Makefile b/parser/Makefile index c6ee00dc9..7b8e85dd2 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 + af_rule.cc af_unix.cc features.c policy_cache.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 + features.h policy_cache.h TOOLS = apparmor_parser OBJECTS = $(patsubst %.cc, %.o, $(SRCS:.c=.o)) @@ -115,7 +115,8 @@ TEST_OBJECTS = $(filter-out \ parser_lex.o \ parser_yacc.o \ common_optarg.o \ - parser_main.o, ${OBJECTS}) \ + parser_main.o \ + policy_cache.o, ${OBJECTS}) \ $(AAREOBJECTS) TEST_LDFLAGS = $(AARE_LDFLAGS) @@ -187,7 +188,7 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(LIBAPPARMOR_A) parser_yacc.c parser_yacc.h: parser_yacc.y parser.h profile.h $(YACC) $(YFLAGS) -o parser_yacc.c parser_yacc.y -parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h +parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h mount.h dbus.h policy_cache.h $(LEX) ${LEXFLAGS} -o$@ $< parser_lex.o: parser_lex.c parser.h parser_yacc.h @@ -199,7 +200,7 @@ parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h cap_names.h $(APPA parser_yacc.o: parser_yacc.c parser_yacc.h $(APPARMOR_H) $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h $(APPARMOR_H) +parser_main.o: parser_main.c parser.h parser_version.h policy_cache.h libapparmor_re/apparmor_re.h $(APPARMOR_H) $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h @@ -238,6 +239,9 @@ common_optarg.o: common_optarg.c common_optarg.h parser.h libapparmor_re/apparmo 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 lib.h + $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< + lib.o: lib.c lib.h parser.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< diff --git a/parser/parser.h b/parser/parser.h index b3d48825d..12b8b86d9 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -318,9 +318,21 @@ extern void pwarn(const char *fmt, ...) __attribute__((__format__(__printf__, 1, /* from parser_main (cannot be used in tst builds) */ extern int force_complain; -extern struct timespec mru_tstamp; -extern void update_mru_tstamp(FILE *file, const char *path); extern void display_version(void); +extern int show_cache; +extern int skip_cache; +extern int skip_read_cache; +extern int write_cache; +extern int cond_clear_cache; +extern int force_clear_cache; +extern int create_cache_dir; +extern int preprocess_only; +extern int skip_mode_force; +extern int abort_on_error; +extern int skip_bad_cache_rebuild; +extern int mru_skip_cache; +extern int debug_cache; +extern struct timespec mru_tstamp; /* provided by parser_lex.l (cannot be used in tst builds) */ extern FILE *yyin; diff --git a/parser/parser_lex.l b/parser/parser_lex.l index 749ee5277..2f6f91478 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -42,6 +42,7 @@ #include "parser_include.h" #include "parser_yacc.h" #include "lib.h" +#include "policy_cache.h" #ifdef PDEBUG #undef PDEBUG diff --git a/parser/parser_main.c b/parser/parser_main.c index ac2fa4435..f075618d9 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -45,6 +45,7 @@ #include "parser_version.h" #include "parser_include.h" #include "common_optarg.h" +#include "policy_cache.h" #include "libapparmor_re/apparmor_re.h" #define OLD_MODULE_NAME "subdomain" @@ -708,69 +709,6 @@ int test_for_dir_mode(const char *basename, const char *linkdir) return rc; } -#define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x))) - -const char header_string[] = "\004\010\000version\000\002"; -#define HEADER_STRING_SIZE 12 -static bool valid_cached_file_version(const char *cachename) -{ - char buffer[16]; - FILE *f; - if (!(f = fopen(cachename, "r"))) { - PERROR(_("Error: Could not read cache file '%s', skipping...\n"), cachename); - return false; - } - size_t res = fread(buffer, 1, 16, f); - fclose(f); - if (res < 16) { - if (debug_cache) - pwarn("%s: cache file '%s' invalid size\n", progname, cachename); - return false; - } - - /* 12 byte header that is always the same and then 4 byte version # */ - if (memcmp(buffer, header_string, HEADER_STRING_SIZE) != 0) { - if (debug_cache) - pwarn("%s: cache file '%s' has wrong header\n", progname, cachename); - return false; - } - - uint32_t version = cpu_to_le32(ENCODE_VERSION(force_complain, - policy_version, - parser_abi_version, - kernel_abi_version)); - if (memcmp(buffer + 12, &version, 4) != 0) { - if (debug_cache) - pwarn("%s: cache file '%s' has wrong version\n", progname, cachename); - return false; - } - - return true; -} - -/* returns true if time is more recent than mru_tstamp */ -#define mru_t_cmp(a) \ -(((a).tv_sec == (mru_tstamp).tv_sec) ? \ - (a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec) - -void set_mru_tstamp(struct timespec t) -{ - mru_skip_cache = 0; - mru_tstamp = t; -} - -void update_mru_tstamp(FILE *file, const char *name) -{ - struct stat stat_file; - if (fstat(fileno(file), &stat_file) || (mru_tstamp.tv_sec == 0 && mru_tstamp.tv_nsec == 0)) - return; - if (mru_t_cmp(stat_file.st_mtim)) { - if (debug_cache) - pwarn("%s: file '%s' is newer than cache file\n", progname, name); - mru_skip_cache = 1; - } -} - int process_profile(int option, const char *profilename) { struct stat stat_bin; @@ -982,65 +920,6 @@ static int binary_dir_cb(DIR *dir unused, const char *name, struct stat *st, return rc; } -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 clear_cache_files(const char *path) -{ - return dirat_for_each(NULL, path, NULL, clear_cache_cb); -} - -static int create_cache(const char *cachedir, const char *path, - const char *features) -{ - struct stat stat_file; - FILE * f = NULL; - - if (clear_cache_files(cacheloc) != 0) - goto error; - -create_file: - f = fopen(path, "w"); - if (f) { - if (fwrite(features, strlen(features), 1, f) != 1 ) - goto error; - - fclose(f); - - - return 0; - } - -error: - /* does the dir exist? */ - if (stat(cachedir, &stat_file) == -1 && create_cache_dir) { - if (mkdir(cachedir, 0700) == 0) - goto create_file; - if (show_cache) - PERROR(_("Can't create cache directory: %s\n"), cachedir); - } else if (!S_ISDIR(stat_file.st_mode)) { - if (show_cache) - PERROR(_("File in cache directory location: %s\n"), cachedir); - } else { - if (show_cache) - PERROR(_("Can't update cache directory: %s\n"), cachedir); - } - - if (show_cache) - PERROR("Cache write disabled: cannot create %s\n", path); - write_cache = 0; - - return -1; -} - static void setup_flags(void) { char *cache_features_path = NULL; diff --git a/parser/policy_cache.c b/parser/policy_cache.c new file mode 100644 index 000000000..f2909b9b1 --- /dev/null +++ b/parser/policy_cache.c @@ -0,0 +1,151 @@ +/* + * 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 +#include +#define _(s) gettext(s) + +#include "lib.h" +#include "parser.h" +#include "policy_cache.h" + +#define le16_to_cpu(x) ((uint16_t)(le16toh (*(uint16_t *) x))) + +const char header_string[] = "\004\010\000version\000\002"; +#define HEADER_STRING_SIZE 12 +bool valid_cached_file_version(const char *cachename) +{ + char buffer[16]; + FILE *f; + if (!(f = fopen(cachename, "r"))) { + PERROR(_("Error: Could not read cache file '%s', skipping...\n"), cachename); + return false; + } + size_t res = fread(buffer, 1, 16, f); + fclose(f); + if (res < 16) { + if (debug_cache) + pwarn("%s: cache file '%s' invalid size\n", progname, cachename); + return false; + } + + /* 12 byte header that is always the same and then 4 byte version # */ + if (memcmp(buffer, header_string, HEADER_STRING_SIZE) != 0) { + if (debug_cache) + pwarn("%s: cache file '%s' has wrong header\n", progname, cachename); + return false; + } + + uint32_t version = cpu_to_le32(ENCODE_VERSION(force_complain, + policy_version, + parser_abi_version, + kernel_abi_version)); + if (memcmp(buffer + 12, &version, 4) != 0) { + if (debug_cache) + pwarn("%s: cache file '%s' has wrong version\n", progname, cachename); + return false; + } + + return true; +} + + +void set_mru_tstamp(struct timespec t) +{ + mru_skip_cache = 0; + mru_tstamp = t; +} + +void update_mru_tstamp(FILE *file, const char *name) +{ + struct stat stat_file; + if (fstat(fileno(file), &stat_file) || (mru_tstamp.tv_sec == 0 && mru_tstamp.tv_nsec == 0)) + return; + if (mru_t_cmp(stat_file.st_mtim)) { + if (debug_cache) + pwarn("%s: file '%s' is newer than cache file\n", progname, name); + mru_skip_cache = 1; + } +} + +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; +} + +int clear_cache_files(const char *path) +{ + return dirat_for_each(NULL, path, NULL, clear_cache_cb); +} + +int create_cache(const char *cachedir, const char *path, const char *features) +{ + struct stat stat_file; + FILE * f = NULL; + + if (clear_cache_files(cachedir) != 0) + goto error; + +create_file: + f = fopen(path, "w"); + if (f) { + if (fwrite(features, strlen(features), 1, f) != 1 ) + goto error; + + fclose(f); + + + return 0; + } + +error: + /* does the dir exist? */ + if (stat(cachedir, &stat_file) == -1 && create_cache_dir) { + if (mkdir(cachedir, 0700) == 0) + goto create_file; + if (show_cache) + PERROR(_("Can't create cache directory: %s\n"), cachedir); + } else if (!S_ISDIR(stat_file.st_mode)) { + if (show_cache) + PERROR(_("File in cache directory location: %s\n"), cachedir); + } else { + if (show_cache) + PERROR(_("Can't update cache directory: %s\n"), cachedir); + } + + if (show_cache) + PERROR("Cache write disabled: cannot create %s\n", path); + write_cache = 0; + + return -1; +} diff --git a/parser/policy_cache.h b/parser/policy_cache.h new file mode 100644 index 000000000..2b9a5dce8 --- /dev/null +++ b/parser/policy_cache.h @@ -0,0 +1,45 @@ +/* + * 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_POLICY_CACHE_H +#define __AA_POLICY_CACHE_H + +extern struct timespec mru_tstamp; + +/* returns true if time is more recent than mru_tstamp */ +#define mru_t_cmp(a) \ +(((a).tv_sec == (mru_tstamp).tv_sec) ? \ + (a).tv_nsec > (mru_tstamp).tv_nsec : (a).tv_sec > (mru_tstamp).tv_sec) + +extern int show_cache; +extern int skip_cache; +extern int skip_read_cache; +extern int write_cache; +extern int cond_clear_cache; /* only applies if write is set */ +extern int force_clear_cache; /* force clearing regargless of state */ +extern int create_cache_dir; /* create the cache dir if missing? */ +extern int mru_skip_cache; +extern int debug_cache; + +void set_mru_tstamp(struct timespec t); +void update_mru_tstamp(FILE *file, const char *path); +bool valid_cached_file_version(const char *cachename); +int clear_cache_files(const char *path); +int create_cache(const char *cachedir, const char *path, const char *features); + +#endif /* __AA_POLICY_CACHE_H */