diff --git a/parser/Makefile b/parser/Makefile index 84a7a1047..cfd26a6b2 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -76,8 +76,8 @@ EXTRA_CFLAGS+=-DSUBDOMAIN_CONFDIR=\"${CONFDIR}\" SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \ parser_main.c parser_misc.c parser_merge.c parser_symtab.c \ parser_yacc.c parser_regex.c parser_variable.c parser_policy.c \ - parser_alias.c mount.c dbus.c lib.c -HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h + parser_alias.c mount.c dbus.c lib.c profile.cc +HDRS = parser.h parser_include.h immunix.h mount.h dbus.h lib.h profile.h TOOLS = apparmor_parser OBJECTS = $(SRCS:.c=.o) @@ -156,16 +156,16 @@ apparmor_parser: $(OBJECTS) $(AAREOBJECTS) $(CXX) $(LDFLAGS) $(EXTRA_CFLAGS) -o $@ $(OBJECTS) $(LIBS) \ ${LEXLIB} $(AAREOBJECTS) $(AARE_LDFLAGS) -parser_yacc.c parser_yacc.h: parser_yacc.y parser.h +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 +parser_lex.c: parser_lex.l parser_yacc.h parser.h profile.h $(LEX) ${LEXFLAGS} -o$@ $< parser_lex.o: parser_lex.c parser.h parser_yacc.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_misc.o: parser_misc.c parser.h parser_yacc.h af_names.h cap_names.h +parser_misc.o: parser_misc.c parser.h parser_yacc.h profile.h af_names.h cap_names.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< parser_yacc.o: parser_yacc.c parser_yacc.h @@ -174,28 +174,28 @@ parser_yacc.o: parser_yacc.c parser_yacc.h parser_main.o: parser_main.c parser.h parser_version.h libapparmor_re/apparmor_re.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_interface.o: parser_interface.c parser.h libapparmor_re/apparmor_re.h +parser_interface.o: parser_interface.c parser.h profile.h libapparmor_re/apparmor_re.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< parser_include.o: parser_include.c parser.h parser_include.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_merge.o: parser_merge.c parser.h +parser_merge.o: parser_merge.c parser.h profile.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_regex.o: parser_regex.c parser.h libapparmor_re/apparmor_re.h +parser_regex.o: parser_regex.c parser.h profile.h libapparmor_re/apparmor_re.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< parser_symtab.o: parser_symtab.c parser.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_variable.o: parser_variable.c parser.h +parser_variable.o: parser_variable.c parser.h profile.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_policy.o: parser_policy.c parser.h parser_yacc.h +parser_policy.o: parser_policy.c parser.h parser_yacc.h profile.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< -parser_alias.o: parser_alias.c parser.h +parser_alias.o: parser_alias.c parser.h profile.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< parser_common.o: parser_common.c parser.h @@ -210,6 +210,9 @@ lib.o: lib.c lib.h parser.h dbus.o: dbus.c dbus.h parser.h immunix.h $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< +profile.o: profile.cc profile.h parser.h + $(CXX) $(EXTRA_CFLAGS) -c -o $@ $< + parser_version.h: Makefile @echo \#define PARSER_VERSION \"$(VERSION)\" > .ver @mv -f .ver $@ diff --git a/parser/dbus.c b/parser/dbus.c index 8bb1f8e40..7996aa068 100644 --- a/parser/dbus.c +++ b/parser/dbus.c @@ -20,6 +20,7 @@ #include #include "parser.h" +#include "profile.h" #include "parser_yacc.h" #include "dbus.h" diff --git a/parser/parser.h b/parser/parser.h index e60ba55f7..8648320dd 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -33,6 +33,7 @@ using namespace std; #include +class Profile; struct mnt_ent; @@ -49,12 +50,6 @@ struct prefixes { int owner; }; -struct flagval { - int hat; - int complain; - int audit; - int path; -}; struct named_transition { int present; @@ -85,7 +80,7 @@ struct cod_entry { char *name; char *link_name; char *nt_name; - struct codomain *codomain; /* Special codomain defined + Profile *prof; /* Special profile defined * just for this executable */ int mode; /* mode is 'or' of AA_* bits */ int audit; /* audit flags for mode */ @@ -120,57 +115,6 @@ struct alt_name { struct alt_name *next; }; -struct codomain { - char *ns; - char *name; /* codomain name */ - char *attachment; - struct alt_name *altnames; - void *xmatch; - size_t xmatch_size; - int xmatch_len; - - /* char *sub_name; */ /* subdomain name or NULL */ - /* int default_deny; */ /* TRUE or FALSE */ - int local; - int local_mode; /* true if local, not hat */ - int local_audit; - - struct codomain *parent; - - struct flagval flags; - - uint64_t capabilities; - uint64_t audit_caps; - uint64_t deny_caps; - uint64_t quiet_caps; - - unsigned int *network_allowed; /* array of type masks - * indexed by AF_FAMILY */ - unsigned int *audit_network; - unsigned int *deny_network; - unsigned int *quiet_network; - - struct aa_rlimits rlimits; - - char *exec_table[AA_EXEC_COUNT]; - struct cod_entry *entries; - struct dbus_entry *dbus_ents; - struct mnt_entry *mnt_ents; - - void *hat_table; - //struct codomain *next; - - aare_ruleset_t *dfarules; - int dfarule_count; - void *dfa; - size_t dfa_size; - - aare_ruleset_t *policy_rules; - int policy_rule_count; - void *policy_dfa; - size_t policy_dfa_size; -}; - struct sd_hat { char *hat_name; unsigned int hat_magic; @@ -311,18 +255,18 @@ extern int yylex(void); extern char *basedir; /* parser_regex.c */ -extern int process_regex(struct codomain *cod); +extern int process_regex(Profile *prof); extern int post_process_entry(struct cod_entry *entry); -extern int process_dbus(struct codomain *cod); +extern int process_dbus(Profile *prof); extern void reset_regex(void); -extern int process_policydb(struct codomain *cod); +extern int process_policydb(Profile *prof); -extern int process_policy_ents(struct codomain *cod); +extern int process_policy_ents(Profile *prof); /* parser_variable.c */ -extern int process_variables(struct codomain *cod); +extern int process_variables(Profile *prof); extern struct var_string *split_out_var(char *string); extern void free_var_string(struct var_string *var); @@ -353,13 +297,16 @@ extern struct aa_network_entry *network_entry(const char *family, const char *protocol); extern size_t get_af_max(void); -extern void debug_cod_list(struct codomain *list); /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */ extern int str_to_boolean(const char* str); extern struct cod_entry *copy_cod_entry(struct cod_entry *cod); extern void free_cod_entries(struct cod_entry *list); extern void free_mnt_entries(struct mnt_entry *list); extern void free_dbus_entries(struct dbus_entry *list); +extern void __debug_capabilities(uint64_t capset, const char *name); +void __debug_network(unsigned int *array, const char *name); +void debug_cod_entries(struct cod_entry *list); + /* parser_symtab.c */ struct set_value {; @@ -378,72 +325,41 @@ void free_symtabs(void); /* parser_alias.c */ extern int new_alias(const char *from, const char *to); -extern void replace_aliases(struct codomain *cod); +extern int replace_profile_aliases(Profile *prof); extern void free_aliases(void); /* parser_merge.c */ -extern int codomain_merge_rules(struct codomain *cod); +extern int profile_merge_rules(Profile *prof); /* parser_interface.c */ typedef struct __sdserialize sd_serialize; -extern int load_codomain(int option, struct codomain *cod); -extern int sd_serialize_profile(sd_serialize *p, struct codomain *cod, +extern int load_profile(int option, Profile *prof); +extern int sd_serialize_profile(sd_serialize *p, Profile *prof, int flatten); extern int sd_load_buffer(int option, char *buffer, int size); extern int cache_fd; /* parser_policy.c */ -extern void add_to_list(struct codomain *codomain); -extern void add_hat_to_policy(struct codomain *policy, struct codomain *hat); -extern void add_entry_to_policy(struct codomain *policy, struct cod_entry *entry); -extern void post_process_file_entries(struct codomain *cod); -extern void post_process_mnt_entries(struct codomain *cod); +extern void add_to_list(Profile *profile); +extern void add_hat_to_policy(Profile *policy, Profile *hat); +extern void add_entry_to_policy(Profile *policy, struct cod_entry *entry); +extern void post_process_file_entries(Profile *prof); +extern void post_process_mnt_entries(Profile *prof); extern int post_process_policy(int debug_only); -extern int process_hat_regex(struct codomain *cod); -extern int process_hat_dbus(struct codomain *cod); -extern int process_hat_variables(struct codomain *cod); -extern int process_hat_policydb(struct codomain *cod); +extern int process_profile_regex(Profile *prof); +extern int process_profile_variables(Profile *prof); +extern int process_profile_policydb(Profile *prof); extern int post_merge_rules(void); -extern int merge_hat_rules(struct codomain *cod); -extern struct codomain *merge_policy(struct codomain *a, struct codomain *b); +extern int merge_hat_rules(Profile *prof); +extern Profile *merge_policy(Profile *a, Profile *b); extern int load_policy(int option); -extern int load_hats(sd_serialize *p, struct codomain *cod); -extern int load_flattened_hats(struct codomain *cod); -extern void free_policy(struct codomain *cod); -extern void dump_policy(void); -extern void dump_policy_hats(struct codomain *cod); +extern int load_hats(sd_serialize *p, Profile *prof); +extern int load_flattened_hats(Profile *prof, int option); +extern void dump_policy_hats(Profile *prof); extern void dump_policy_names(void); +void dump_policy(void); void free_policies(void); -#ifdef UNIT_TEST -/* For the unit-test builds, we must include function stubs for stuff that - * only exists in the excluded object files; everything else should live - * in parser_common.c. - */ - -/* parser_yacc.y */ -void yyerror(const char *msg, ...) -{ - va_list arg; - char buf[PATH_MAX]; - - va_start(arg, msg); - vsnprintf(buf, sizeof(buf), msg, arg); - va_end(arg); - - PERROR(_("AppArmor parser error: %s\n"), buf); - - exit(1); -} - -#define MY_TEST(statement, error) \ - if (!(statement)) { \ - PERROR("FAIL: %s\n", error); \ - rc = 1; \ - } - -#endif - #endif /** __AA_PARSER_H */ diff --git a/parser/parser_alias.c b/parser/parser_alias.c index aee882ef6..aea9f1af4 100644 --- a/parser/parser_alias.c +++ b/parser/parser_alias.c @@ -25,6 +25,7 @@ #include "immunix.h" #include "parser.h" +#include "profile.h" struct alias_rule { char *from; @@ -105,7 +106,7 @@ static char *do_alias(struct alias_rule *alias, const char *target) return n; } -static struct codomain *target_cod; +static Profile *target_prof; static struct cod_entry *target_list; static void process_entries(const void *nodep, VISIT value, int __unused level) { @@ -155,7 +156,7 @@ static void process_entries(const void *nodep, VISIT value, int __unused level) static void process_name(const void *nodep, VISIT value, int __unused level) { struct alias_rule **t = (struct alias_rule **) nodep; - struct codomain *cod = target_cod; + Profile *prof = target_prof; char *name; int len; @@ -164,10 +165,10 @@ static void process_name(const void *nodep, VISIT value, int __unused level) len = strlen((*t)->from); - if (cod->attachment) - name = cod->attachment; + if (prof->attachment) + name = prof->attachment; else - name = cod->name; + name = prof->name; if (name && strncmp((*t)->from, name, len) == 0) { struct alt_name *alt; @@ -179,21 +180,23 @@ static void process_name(const void *nodep, VISIT value, int __unused level) if (!alt) return; alt->name = n; - alt->next = cod->altnames; - cod->altnames = alt; + alt->next = prof->altnames; + prof->altnames = alt; } } -void replace_aliases(struct codomain *cod) +int replace_profile_aliases(Profile *prof) { - target_cod = cod; + target_prof = prof; twalk(alias_table, process_name); - if (cod->entries) { - target_list = cod->entries; - target_cod = cod; + if (prof->entries) { + target_list = prof->entries; + target_prof = prof; twalk(alias_table, process_entries); } + + return 0; } static void free_alias(void *nodep) diff --git a/parser/parser_interface.c b/parser/parser_interface.c index 0e6a3ea05..ebc709fcb 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -25,6 +25,7 @@ #define _(s) gettext(s) #include "parser.h" +#include "profile.h" #include "libapparmor_re/apparmor_re.h" #include @@ -59,7 +60,7 @@ #define SUBDOMAIN_INTERFACE_DFA_VERSION 5 -int sd_serialize_codomain(int option, struct codomain *cod); +int __sd_serialize_profile(int option, Profile *prof); static void print_error(int error) { @@ -100,30 +101,30 @@ static void print_error(int error) } } -int load_codomain(int option, struct codomain *cod) +int load_profile(int option, Profile *prof) { int retval = 0; int error = 0; - PDEBUG("Serializing policy for %s.\n", cod->name); - retval = sd_serialize_codomain(option, cod); + PDEBUG("Serializing policy for %s.\n", prof->name); + retval = __sd_serialize_profile(option, prof); if (retval < 0) { error = retval; /* yeah, we'll just report the last error */ switch (option) { case OPTION_ADD: PERROR(_("%s: Unable to add \"%s\". "), - progname, cod->name); + progname, prof->name); print_error(error); break; case OPTION_REPLACE: PERROR(_("%s: Unable to replace \"%s\". "), - progname, cod->name); + progname, prof->name); print_error(error); break; case OPTION_REMOVE: PERROR(_("%s: Unable to remove \"%s\". "), - progname, cod->name); + progname, prof->name); print_error(error); break; case OPTION_STDOUT: @@ -144,15 +145,15 @@ int load_codomain(int option, struct codomain *cod) switch (option) { case OPTION_ADD: printf(_("Addition succeeded for \"%s\".\n"), - cod->name); + prof->name); break; case OPTION_REPLACE: printf(_("Replacement succeeded for \"%s\".\n"), - cod->name); + prof->name); break; case OPTION_REMOVE: printf(_("Removal succeeded for \"%s\".\n"), - cod->name); + prof->name); break; case OPTION_STDOUT: case OPTION_OFILE: @@ -544,7 +545,7 @@ int count_tailglob_ents(struct cod_entry *list) return count; } -int sd_serialize_profile(sd_serialize *p, struct codomain *profile, +int sd_serialize_profile(sd_serialize *p, Profile *profile, int flattened) { uint64_t allowed_caps; @@ -608,12 +609,12 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile, #define low_caps(X) ((u32) ((X) & 0xffffffff)) #define high_caps(X) ((u32) (((X) >> 32) & 0xffffffff)) - allowed_caps = (profile->capabilities) & ~profile->deny_caps; + allowed_caps = (profile->caps.allow) & ~profile->caps.deny; if (!sd_write32(p, low_caps(allowed_caps))) return 0; - if (!sd_write32(p, low_caps(allowed_caps & profile->audit_caps))) + if (!sd_write32(p, low_caps(allowed_caps & profile->caps.audit))) return 0; - if (!sd_write32(p, low_caps(profile->deny_caps & profile->quiet_caps))) + if (!sd_write32(p, low_caps(profile->caps.deny & profile->caps.quiet))) return 0; if (!sd_write32(p, 0)) return 0; @@ -622,9 +623,9 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile, return 0; if (!sd_write32(p, high_caps(allowed_caps))) return 0; - if (!sd_write32(p, high_caps(allowed_caps & profile->audit_caps))) + if (!sd_write32(p, high_caps(allowed_caps & profile->caps.audit))) return 0; - if (!sd_write32(p, high_caps(profile->deny_caps & profile->quiet_caps))) + if (!sd_write32(p, high_caps(profile->caps.deny & profile->caps.quiet))) return 0; if (!sd_write32(p, 0)) return 0; @@ -634,36 +635,36 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile, if (!sd_serialize_rlimits(p, &profile->rlimits)) return 0; - if (profile->network_allowed && kernel_supports_network) { + if (profile->net.allow && kernel_supports_network) { size_t i; if (!sd_write_array(p, "net_allowed_af", get_af_max())) return 0; for (i = 0; i < get_af_max(); i++) { - u16 allowed = profile->network_allowed[i] & - ~profile->deny_network[i]; + u16 allowed = profile->net.allow[i] & + ~profile->net.deny[i]; if (!sd_write16(p, allowed)) return 0; - if (!sd_write16(p, allowed & profile->audit_network[i])) + if (!sd_write16(p, allowed & profile->net.audit[i])) return 0; - if (!sd_write16(p, profile->deny_network[i] & profile->quiet_network[i])) + if (!sd_write16(p, profile->net.deny[i] & profile->net.quiet[i])) return 0; } if (!sd_write_arrayend(p)) return 0; - } else if (profile->network_allowed) + } else if (profile->net.allow) pwarn(_("profile %s network rules not enforced\n"), profile->name); - if (profile->policy_dfa) { + if (profile->policy.dfa) { if (!sd_write_struct(p, "policydb")) return 0; - if (!sd_serialize_dfa(p, profile->policy_dfa, profile->policy_dfa_size)) + if (!sd_serialize_dfa(p, profile->policy.dfa, profile->policy.size)) return 0; if (!sd_write_structend(p)) return 0; } /* either have a single dfa or lists of different entry types */ - if (!sd_serialize_dfa(p, profile->dfa, profile->dfa_size)) + if (!sd_serialize_dfa(p, profile->dfa.dfa, profile->dfa.size)) return 0; if (!sd_serialize_xtable(p, profile->exec_table)) @@ -675,7 +676,7 @@ int sd_serialize_profile(sd_serialize *p, struct codomain *profile, return 1; } -int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile) +int sd_serialize_top_profile(sd_serialize *p, Profile *profile) { int version; @@ -699,7 +700,7 @@ int sd_serialize_top_profile(sd_serialize *p, struct codomain *profile) } int cache_fd = -1; -int sd_serialize_codomain(int option, struct codomain *cod) +int __sd_serialize_profile(int option, Profile *prof) { int fd = -1; int error = -ENOMEM, size, wsize; @@ -754,34 +755,34 @@ int sd_serialize_codomain(int option, struct codomain *cod) if (profile_ns) { len += strlen(profile_ns) + 2; ns = profile_ns; - } else if (cod->ns) { - len += strlen(cod->ns) + 2; - ns = cod->ns; + } else if (prof->ns) { + len += strlen(prof->ns) + 2; + ns = prof->ns; } - if (cod->parent) { - name = (char *) malloc(strlen(cod->name) + 3 + - strlen(cod->parent->name) + len); + if (prof->parent) { + name = (char *) malloc(strlen(prof->name) + 3 + + strlen(prof->parent->name) + len); if (!name) { - PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), cod->name); + PERROR(_("Memory Allocation Error: Unable to remove ^%s\n"), prof->name); error = -errno; goto exit; } if (ns) sprintf(name, ":%s:%s//%s", ns, - cod->parent->name, cod->name); + prof->parent->name, prof->name); else - sprintf(name, "%s//%s", cod->parent->name, - cod->name); + sprintf(name, "%s//%s", prof->parent->name, + prof->name); } else if (ns) { - name = (char *) malloc(len + strlen(cod->name) + 1); + name = (char *) malloc(len + strlen(prof->name) + 1); if (!name) { - PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, cod->name); + PERROR(_("Memory Allocation Error: Unable to remove %s:%s."), ns, prof->name); error = -errno; goto exit; } - sprintf(name, ":%s:%s", ns, cod->name); + sprintf(name, ":%s:%s", ns, prof->name); } else { - name = cod->name; + name = prof->name; } size = strlen(name) + 1; if (kernel_load) { @@ -789,7 +790,7 @@ int sd_serialize_codomain(int option, struct codomain *cod) if (wsize < 0) error = -errno; } - if (cod->parent || ns) + if (prof->parent || ns) free(name); } else { @@ -801,11 +802,11 @@ int sd_serialize_codomain(int option, struct codomain *cod) goto exit; } - if (!sd_serialize_top_profile(work_area, cod)) { + if (!sd_serialize_top_profile(work_area, prof)) { close(fd); free_sd_serial(work_area); PERROR(_("unable to serialize profile %s\n"), - cod->name); + prof->name); goto exit; } @@ -835,8 +836,8 @@ int sd_serialize_codomain(int option, struct codomain *cod) close(fd); - if (cod->hat_table && option != OPTION_REMOVE) { - if (load_flattened_hats(cod) != 0) + if (!prof->hat_table.empty() && option != OPTION_REMOVE) { + if (load_flattened_hats(prof, option) == 0) return 0; } diff --git a/parser/parser_lex.l b/parser/parser_lex.l index 07315886d..7093759dc 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -37,6 +37,7 @@ #define _(s) gettext(s) #include "parser.h" +#include "profile.h" #include "parser_include.h" #include "parser_yacc.h" #include "lib.h" diff --git a/parser/parser_merge.c b/parser/parser_merge.c index c57ebe519..2852e2499 100644 --- a/parser/parser_merge.c +++ b/parser/parser_merge.c @@ -25,7 +25,7 @@ #define _(s) gettext(s) #include "parser.h" - +#include "profile.h" static int file_comp(const void *c1, const void *c2) { @@ -74,35 +74,35 @@ static int file_comp(const void *c1, const void *c2) return strcmp((*e1)->name, (*e2)->name); } -static int process_file_entries(struct codomain *cod) +static int process_file_entries(Profile *prof) { struct cod_entry *cur, *next; struct cod_entry **table; int n, count = 0; - for (cur = cod->entries; cur; cur = cur->next) + for (cur = prof->entries; cur; cur = cur->next) count++; if (count < 2) - return 1; + return 0; table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1)); if (!table) { PERROR(_("Couldn't merge entries. Out of Memory\n")); - return 0; + return ENOMEM; } - for (cur = cod->entries, n = 0; cur; cur = cur->next, n++) + for (cur = prof->entries, n = 0; cur; cur = cur->next, n++) table[n] = cur; qsort(table, count, sizeof(struct cod_entry *), file_comp); table[count] = NULL; for (n = 0; n < count; n++) table[n]->next = table[n + 1]; - cod->entries = table[0]; + prof->entries = table[0]; free(table); /* walk the sorted table merging similar entries */ - for (cur = cod->entries, next = cur->next; next; next = cur->next) { + for (cur = prof->entries, next = cur->next; next; next = cur->next) { if (file_comp(&cur, &next) != 0) { cur = next; continue; @@ -111,8 +111,8 @@ static int process_file_entries(struct codomain *cod) /* check for merged x consistency */ if (!is_merged_x_consistent(cur->mode, next->mode)) { PERROR(_("profile %s: has merged rule %s with conflicting x modifiers\n"), - cod->name, cur->name); - return 0; + prof->name, cur->name); + return -1; } cur->mode |= next->mode; cur->audit |= next->audit; @@ -122,18 +122,10 @@ static int process_file_entries(struct codomain *cod) free_cod_entries(next); } - return 1; -} - -int codomain_merge_rules(struct codomain *cod) -{ - if (!process_file_entries(cod)) - goto fail; - - /* XXX return error from this */ - merge_hat_rules(cod); - - return 1; -fail: return 0; } + +int profile_merge_rules(Profile *prof) +{ + return process_file_entries(prof); +} diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 153ffe73a..1f8dc7631 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -36,6 +36,7 @@ #include #include "parser.h" +#include "profile.h" #include "parser_yacc.h" #include "mount.h" #include "dbus.h" @@ -952,23 +953,6 @@ void debug_cod_entries(struct cod_entry *list) } } -void debug_flags(struct codomain *cod) -{ - printf("Profile Mode:\t"); - - if (cod->flags.complain) - printf("Complain"); - else - printf("Enforce"); - - if (cod->flags.audit) - printf(", Audit"); - - if (cod->flags.hat) - printf(", Hat"); - - printf("\n"); -} static const char *capnames[] = { "chown", @@ -1029,17 +1013,6 @@ void __debug_capabilities(uint64_t capset, const char *name) } printf("\n"); } -void debug_capabilities(struct codomain *cod) -{ - if (cod->capabilities != 0ull) - __debug_capabilities(cod->capabilities, "Capabilities"); - if (cod->audit_caps != 0ull) - __debug_capabilities(cod->audit_caps, "Audit Caps"); - if (cod->deny_caps != 0ull) - __debug_capabilities(cod->deny_caps, "Deny Caps"); - if (cod->quiet_caps != 0ull) - __debug_capabilities(cod->quiet_caps, "Quiet Caps"); -} /* Bleah C++ doesn't have non-trivial designated initializers so we just * have to make sure these are in order. This means we are more brittle @@ -1129,44 +1102,6 @@ void __debug_network(unsigned int *array, const char *name) printf("\n"); } -void debug_network(struct codomain *cod) -{ - if (cod->network_allowed) - __debug_network(cod->network_allowed, "Network"); - if (cod->audit_network) - __debug_network(cod->audit_network, "Audit Net"); - if (cod->deny_network) - __debug_network(cod->deny_network, "Deny Net"); - if (cod->quiet_network) - __debug_network(cod->quiet_network, "Quiet Net"); - -} - -void debug_cod_list(struct codomain *cod) -{ - if (cod->ns) - printf("Ns:\t\t%s\n", cod->ns); - - if (cod->name) - printf("Name:\t\t%s\n", cod->name); - else - printf("Name:\t\tNULL\n"); - - if (cod->local) - printf("Local To:\t%s\n", cod->parent->name); - - debug_flags(cod); - - debug_capabilities(cod); - - debug_network(cod); - - if (cod->entries) - debug_cod_entries(cod->entries); - - printf("\n"); - dump_policy_hats(cod); -} struct value_list *new_value_list(char *value) { @@ -1274,6 +1209,9 @@ void print_cond_entry(struct cond_entry *ent) } #ifdef UNIT_TEST + +#include "unit_test.h" + int test_str_to_boolean(void) { int rc = 0; diff --git a/parser/parser_policy.c b/parser/parser_policy.c index 22bd2688c..90bf982cb 100644 --- a/parser/parser_policy.c +++ b/parser/parser_policy.c @@ -31,6 +31,7 @@ #define _(s) gettext(s) #include "parser.h" +#include "profile.h" #include "mount.h" #include "dbus.h" #include "parser_yacc.h" @@ -43,70 +44,40 @@ #endif #define NPDEBUG(fmt, args...) /* Do nothing */ -void *policy_list = NULL; -static int codomain_compare(const void *a, const void *b) +ProfileList policy_list; + + +void add_to_list(Profile *prof) { - struct codomain *A = (struct codomain *) a; - struct codomain *B = (struct codomain *) b; - - int res = 0; - if (A->ns) { - if (B->ns) - res = strcmp(A->ns, B->ns); - else - res = -1; - } else if (B->ns) - res = 1; - if (res) - return res; - return strcmp(A->name, B->name); -} - -void add_to_list(struct codomain *codomain) -{ - struct codomain **result; - - result = (struct codomain **) tsearch(codomain, &policy_list, codomain_compare); - if (!result) { - PERROR("Memory allocation error\n"); - exit(1); - } - - if (*result != codomain) { + pair res = policy_list.insert(prof); + if (!res.second) { PERROR("Multiple definitions for profile %s exist," - "bailing out.\n", codomain->name); + "bailing out.\n", prof->name); exit(1); } } -void add_hat_to_policy(struct codomain *cod, struct codomain *hat) +void add_hat_to_policy(Profile *prof, Profile *hat) { - struct codomain **result; + hat->parent = prof; - hat->parent = cod; - - result = (struct codomain **) tsearch(hat, &(cod->hat_table), codomain_compare); - if (!result) { - PERROR("Memory allocation error\n"); - exit(1); - } - - if (*result != hat) { + pair res = prof->hat_table.insert(hat); + if (!res.second) { PERROR("Multiple definitions for hat %s in profile %s exist," - "bailing out.\n", hat->name, cod->name); + "bailing out.\n", hat->name, prof->name); exit(1); } } -static int add_entry_to_x_table(struct codomain *cod, char *name) +static int add_entry_to_x_table(Profile *prof, char *name) { int i; for (i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) { - if (!cod->exec_table[i]) { - cod->exec_table[i] = name; + if (!prof->exec_table[i]) { + prof->exec_table[i] = name; return i; - } else if (strcmp(cod->exec_table[i], name) == 0) { + } else if (strcmp(prof->exec_table[i], name) == 0) { /* name already in table */ free(name); return i; @@ -116,7 +87,7 @@ static int add_entry_to_x_table(struct codomain *cod, char *name) return 0; } -static int add_named_transition(struct codomain *cod, struct cod_entry *entry) +static int add_named_transition(Profile *prof, struct cod_entry *entry) { char *name = NULL; @@ -125,7 +96,7 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry) char *sub = strstr(entry->nt_name, "//"); /* does the subprofile name match the rule */ - if (sub && strncmp(cod->name, sub, sub - entry->nt_name) && + if (sub && strncmp(prof->name, sub, sub - entry->nt_name) && strcmp(sub + 2, entry->name) == 0) { free(entry->nt_name); entry->nt_name = NULL; @@ -140,13 +111,13 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry) return AA_EXEC_LOCAL >> 10; } /* specified as cix so profile name is implicit */ - name = (char *) malloc(strlen(cod->name) + strlen(entry->nt_name) + name = (char *) malloc(strlen(prof->name) + strlen(entry->nt_name) + 3); if (!name) { PERROR("Memory allocation error\n"); exit(1); } - sprintf(name, "%s//%s", cod->name, entry->nt_name); + sprintf(name, "%s//%s", prof->name, entry->nt_name); free(entry->nt_name); entry->nt_name = name; } @@ -166,26 +137,26 @@ static int add_named_transition(struct codomain *cod, struct cod_entry *entry) name = entry->nt_name; } - return add_entry_to_x_table(cod, name); + return add_entry_to_x_table(prof, name); } -void add_entry_to_policy(struct codomain *cod, struct cod_entry *entry) +void add_entry_to_policy(Profile *prof, struct cod_entry *entry) { - entry->next = cod->entries; - cod->entries = entry; + entry->next = prof->entries; + prof->entries = entry; } -void post_process_file_entries(struct codomain *cod) +void post_process_file_entries(Profile *prof) { struct cod_entry *entry; int cp_mode = 0; - list_for_each(cod->entries, entry) { + list_for_each(prof->entries, entry) { if (entry->nt_name) { int mode = 0; - int n = add_named_transition(cod, entry); + int n = add_named_transition(prof, entry); if (!n) { - PERROR("Profile %s has too many specified profile transitions.\n", cod->name); + PERROR("Profile %s has too many specified profile transitions.\n", prof->name); exit(1); } if (entry->mode & AA_USER_EXEC) @@ -217,20 +188,20 @@ void post_process_file_entries(struct codomain *cod) PERROR("Memory allocation error\n"); exit(1); } - add_entry_to_policy(cod, new_ent); + add_entry_to_policy(prof, new_ent); } } -void post_process_mnt_entries(struct codomain *cod) +void post_process_mnt_entries(Profile *prof) { struct mnt_entry *entry; - list_for_each(cod->mnt_ents, entry) { + list_for_each(prof->mnt_ents, entry) { if (entry->trans) { unsigned int mode = 0; - int n = add_entry_to_x_table(cod, entry->trans); + int n = add_entry_to_x_table(prof, entry->trans); if (!n) { - PERROR("Profile %s has too many specified profile transitions.\n", cod->name); + PERROR("Profile %s has too many specified profile transitions.\n", prof->name); exit(1); } @@ -247,335 +218,90 @@ void post_process_mnt_entries(struct codomain *cod) } -static void __merge_rules(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - if (!codomain_merge_rules(*t)) { - PERROR(_("ERROR merging rules for profile %s, failed to load\n"), - (*t)->name); - exit(1); - } -} - -int post_merge_rules(void) -{ - twalk(policy_list, __merge_rules); - return 0; -} - -int merge_hat_rules(struct codomain *cod) -{ - twalk(cod->hat_table, __merge_rules); - return 0; -} - -static void __process_regex(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - if (process_regex(*t) != 0) { - PERROR(_("ERROR processing regexs for profile %s, failed to load\n"), - (*t)->name); - exit(1); - } -} - -int post_process_regex(void) -{ - twalk(policy_list, __process_regex); - return 0; -} - -int process_hat_regex(struct codomain *cod) -{ - twalk(cod->hat_table, __process_regex); - return 0; -} - -static void __process_policydb(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - if (process_policydb(*t) != 0) { - PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"), - (*t)->name); - exit(1); - } -} - -int post_process_policydb(void) -{ - twalk(policy_list, __process_policydb); - return 0; -} - -int process_hat_policydb(struct codomain *cod) -{ - twalk(cod->hat_table, __process_policydb); - return 0; -} - -static void __process_variables(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - if (process_variables(*t) != 0) { - PERROR(_("ERROR expanding variables for profile %s, failed to load\n"), - (*t)->name); - exit(1); - } -} - -int post_process_variables(void) -{ - twalk(policy_list, __process_variables); - return 0; -} - -int process_hat_variables(struct codomain *cod) -{ - twalk(cod->hat_table, __process_variables); - return 0; -} - - -static void __process_alias(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - replace_aliases((*t)); - - if ((*t)->hat_table) - twalk((*t)->hat_table, __process_alias); -} - -int post_process_alias(void) -{ - twalk(policy_list, __process_alias); - return 0; -} - #define CHANGEHAT_PATH "/proc/[0-9]*/attr/current" /* add file rules to access /proc files to call change_hat() */ -static void __add_hat_rules_parent(const void *nodep, const VISIT value, - const int __unused depth) +static int profile_add_hat_rules(Profile *prof) { - struct codomain **t = (struct codomain **) nodep; struct cod_entry *entry; - if (value == preorder || value == endorder) - return; - - /* don't add hat rules if a parent profile with no hats */ - if (!(*t)->hat_table && !(*t)->parent) - return; - - /* don't add hat rules for local_profiles */ - if ((*t)->local) - return; + /* TODO: ??? fix logic for when to add to hat/base vs. local */ + /* don't add hat rules for local_profiles or base profiles */ + if (prof->local || prof->hat_table.empty()) + return 0; + /* add entry to hat */ entry = new_entry(NULL, strdup(CHANGEHAT_PATH), AA_MAY_WRITE, NULL); - if (!entry) { - PERROR(_("ERROR adding hat access rule for profile %s\n"), - (*t)->name); - exit(1); - } - add_entry_to_policy(*t, entry); + if (!entry) + return ENOMEM; - twalk((*t)->hat_table, __add_hat_rules_parent); -} - -static int add_hat_rules(void) -{ - twalk(policy_list, __add_hat_rules_parent); + add_entry_to_policy(prof, entry); return 0; } -/* Yuck, is their no other way to pass arguments to a twalk action */ -static int __load_option; -static int __load_error; - -static void __load_policy(const void *nodep, const VISIT value, - const int __unused depth) +int load_policy_list(ProfileList &list, int option) { - struct codomain **t = (struct codomain **) nodep; + int res = 0; - if (value == preorder || value == endorder || __load_error) - return; - - if (load_codomain(__load_option, *t) != 0) { - __load_error = -EINVAL; + for (ProfileList::iterator i = list.begin(); i != list.end(); i++) { + res = load_profile(option, *i); + if (res != 0) + break; } + + return res; +} + +int load_flattened_hats(Profile *prof, int option) +{ + return load_policy_list(prof->hat_table, option); } int load_policy(int option) { - __load_option = option; - __load_error = 0; - twalk(policy_list, __load_policy); - return __load_error; + return load_policy_list(policy_list, option); } -/* Yuck, is their no other way to pass arguments to a twalk action */ -static sd_serialize *__p; - -static int __load_hat_error; -static void __load_hat(const void *nodep, const VISIT value, - const int __unused depth) +int load_hats(sd_serialize *p, Profile *prof) { - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder || __load_hat_error) - return; - - if (!sd_serialize_profile(__p, *t, 0)) { - PERROR(_("ERROR in profile %s, failed to load\n"), - (*t)->name); - __load_hat_error = -EINVAL; + for (ProfileList::iterator i = prof->hat_table.begin(); i != prof->hat_table.end(); i++) { + if (!sd_serialize_profile(p, *i, 0)) { + PERROR(_("ERROR in profile %s, failed to load\n"), + (*i)->name); + return -EINVAL; + } } + + return 0; } -static int __load_flattened_hat_error; -static void __load_flattened_hat(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder || __load_flattened_hat_error) - return; - - if (load_codomain(__load_option, *t) != 0) { - __load_flattened_hat_error = -EINVAL; - } -} - -int load_flattened_hats(struct codomain *cod) -{ - __load_flattened_hat_error = 0; - twalk(cod->hat_table, __load_flattened_hat); - return __load_flattened_hat_error; -} - -int load_hats(sd_serialize *p, struct codomain *cod) -{ - __p = p; - __load_hat_error = 0; - twalk(cod->hat_table, __load_hat); - return __load_hat_error; -} - -static void __dump_policy(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - debug_cod_list(*t); -} void dump_policy(void) { - twalk(policy_list, __dump_policy); -} - -void dump_policy_hats(struct codomain *cod) -{ - twalk(cod->hat_table, __dump_policy); -} - -/* Gar */ -static struct codomain *__dump_policy_name; - -static void __dump_policy_hatnames(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - printf("%s//%s\n", __dump_policy_name->name, (*t)->name); -} - -void dump_policy_hatnames(struct codomain *cod) -{ - __dump_policy_name = cod; - twalk(cod->hat_table, __dump_policy_hatnames); -} - -static void __dump_policy_names(const void *nodep, const VISIT value, - const int __unused depth) -{ - struct codomain **t = (struct codomain **) nodep; - - if (value == preorder || value == endorder) - return; - - printf("%s\n", (*t)->name); - dump_policy_hatnames(*t); + policy_list.dump(); } void dump_policy_names(void) { - twalk(policy_list, __dump_policy_names); + policy_list.dump_profile_names(true); } -/* gar, more global arguments */ -struct codomain *__hat_merge_policy; - -static void __merge_hat(const void *nodep, const VISIT value, - const int __unused depth) +/* merge_hats: merges hat_table into hat_table owned by prof */ +static void merge_hats(Profile *prof, ProfileList &hats) { - struct codomain **t = (struct codomain **) nodep; + for (ProfileList::iterator i = hats.begin(); i != hats.end(); ) { + ProfileList::iterator cur = i++; + add_hat_to_policy(prof, *cur); + hats.erase(cur); + } - if (value == preorder || value == endorder) - return; - add_hat_to_policy(__hat_merge_policy, (*t)); } -/* merge_hats: merges hat_table into hat_table owned by cod */ -static void merge_hats(struct codomain *cod, void *hats) +Profile *merge_policy(Profile *a, Profile *b) { - __hat_merge_policy = cod; - twalk(hats, __merge_hat); -} - -/* don't want to free the hat entries in the table, as they were pushed - * onto the other table. */ -static void empty_destroy(void __unused *nodep) -{ - return; -} - -struct codomain *merge_policy(struct codomain *a, struct codomain *b) -{ - struct codomain *ret = a; + Profile *ret = a; struct cod_entry *last; if (!a) { @@ -603,131 +329,109 @@ struct codomain *merge_policy(struct codomain *a, struct codomain *b) a->flags.complain = a->flags.complain || b->flags.complain; a->flags.audit = a->flags.audit || b->flags.audit; - a->capabilities |= b->capabilities; - a->audit_caps |= b->audit_caps; - a->deny_caps |= b->deny_caps; - a->quiet_caps |= b->quiet_caps; + a->caps.allow |= b->caps.allow; + a->caps.audit |= b->caps.audit; + a->caps.deny |= b->caps.deny; + a->caps.quiet |= b->caps.quiet; - if (a->network_allowed) { + if (a->net.allow) { size_t i; for (i = 0; i < get_af_max(); i++) { - a->network_allowed[i] |= b->network_allowed[i]; - a->audit_network[i] |= b->audit_network[i]; - a->deny_network[i] |= b->deny_network[i]; - a->quiet_network[i] |= b->quiet_network[i]; + a->net.allow[i] |= b->net.allow[i]; + a->net.audit[i] |= b->net.audit[i]; + a->net.deny[i] |= b->net.deny[i]; + a->net.quiet[i] |= b->net.quiet[i]; } } merge_hats(a, b->hat_table); - tdestroy(b->hat_table, &empty_destroy); - b->hat_table = NULL; - - free_policy(b); + delete b; out: return ret; } +int process_profile_rules(Profile *profile) +{ + int error; + + error = process_profile_regex(profile); + if (error) { + PERROR(_("ERROR processing regexs for profile %s, failed to load\n"), profile->name); + exit(1); + return error; + } + + error = process_profile_policydb(profile); + if (error) { + PERROR(_("ERROR processing policydb rules for profile %s, failed to load\n"), + (profile)->name); + exit(1); + return error; + } + + return 0; +} + +int post_process_policy_list(ProfileList &list, int debug_only); +int post_process_profile(Profile *profile, int debug_only) +{ + int error = 0; + + error = profile_add_hat_rules(profile); + if (error) { + PERROR(_("ERROR adding hat access rule for profile %s\n"), + profile->name); + return error; + } + + error = process_profile_variables(profile); + if (error) { + PERROR(_("ERROR expanding variables for profile %s, failed to load\n"), profile->name); + exit(1); + return error; + } + + error = replace_profile_aliases(profile); + if (error) { + PERROR(_("ERROR replacing aliases for profile %s, failed to load\n"), profile->name); + return error; + } + + error = profile_merge_rules(profile); + if (error) { + PERROR(_("ERROR merging rules for profile %s, failed to load\n"), profile->name); + exit(1); + return error; + } + + if (!debug_only) { + error = process_profile_rules(profile); + if (error) + return error; + } + + error = post_process_policy_list(profile->hat_table, debug_only); + return error; +} + +int post_process_policy_list(ProfileList &list, int debug_only) +{ + int error = 0; + for (ProfileList::iterator i = list.begin(); i != list.end(); i++) { + error = post_process_profile(*i, debug_only); + if (error) + break; + } + + return error; +} + int post_process_policy(int debug_only) { - int retval = 0; - - retval = add_hat_rules(); - if (retval != 0) { - PERROR(_("%s: Errors found during postprocessing. Aborting.\n"), - progname); - return retval; - } - - retval = post_process_variables(); - if (retval != 0) { - PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"), - progname); - return retval; - } - - retval = post_process_alias(); - if (retval != 0) { - PERROR(_("%s: Errors found during postprocess. Aborting.\n"), - progname); - return retval; - } - - retval = post_merge_rules(); - if (retval != 0) { - PERROR(_("%s: Errors found in combining rules postprocessing. Aborting.\n"), - progname); - return retval; - } - - if (!debug_only) { - retval = post_process_regex(); - if (retval != 0) { - PERROR(_("%s: Errors found during regex postprocess. Aborting.\n"), - progname); - return retval; - } - } - - if (!debug_only) { - retval = post_process_policydb(); - if (retval != 0) { - PERROR(_("%s: Errors found during policydb postprocess. Aborting.\n"), - progname); - return retval; - } - } - - return retval; -} - -void free_hat_entry(void *nodep) -{ - struct codomain *t = (struct codomain *)nodep; - free_policy(t); -} - -void free_hat_table(void *hat_table) -{ - if (hat_table) - tdestroy(hat_table, &free_hat_entry); -} - -void free_policy(struct codomain *cod) -{ - if (!cod) - return; - free_hat_table(cod->hat_table); - free_cod_entries(cod->entries); - free_mnt_entries(cod->mnt_ents); - free_dbus_entries(cod->dbus_ents); - if (cod->dfarules) - aare_delete_ruleset(cod->dfarules); - if (cod->dfa) - free(cod->dfa); - if (cod->policy_rules) - aare_delete_ruleset(cod->policy_rules); - if (cod->policy_dfa) - free(cod->policy_dfa); - if (cod->name) - free(cod->name); - if (cod->attachment) - free(cod->attachment); - if (cod->ns) - free(cod->ns); - if (cod->network_allowed) - free(cod->network_allowed); - if (cod->audit_network) - free(cod->audit_network); - if (cod->deny_network) - free(cod->deny_network); - if (cod->quiet_network) - free(cod->quiet_network); - free(cod); + return post_process_policy_list(policy_list, debug_only); } void free_policies(void) { - if (policy_list) - tdestroy(policy_list, (__free_fn_t)&free_policy); - policy_list = NULL; + policy_list.clear(); } diff --git a/parser/parser_regex.c b/parser/parser_regex.c index aa6a8ca1b..eba01d2b4 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -26,6 +26,7 @@ /* #define DEBUG */ #include "parser.h" +#include "profile.h" #include "libapparmor_re/apparmor_re.h" #include "libapparmor_re/aare_rules.h" #include "mount.h" @@ -384,30 +385,30 @@ static const char *local_name(const char *name) return name; } -static int process_profile_name_xmatch(struct codomain *cod) +static int process_profile_name_xmatch(Profile *prof) { char tbuf[PATH_MAX + 3]; /* +3 for ^, $ and \0 */ pattern_t ptype; const char *name; /* don't filter_slashes for profile names */ - if (cod->attachment) - name = cod->attachment; + if (prof->attachment) + name = prof->attachment; else - name = local_name(cod->name); + name = local_name(prof->name); ptype = convert_aaregex_to_pcre(name, 0, tbuf, PATH_MAX + 3, - &cod->xmatch_len); + &prof->xmatch_len); if (ptype == ePatternBasic) - cod->xmatch_len = strlen(name); + prof->xmatch_len = strlen(name); if (ptype == ePatternInvalid) { PERROR(_("%s: Invalid profile name '%s' - bad regular expression\n"), progname, name); return FALSE; - } else if (ptype == ePatternBasic && !(cod->altnames || cod->attachment)) { + } else if (ptype == ePatternBasic && !(prof->altnames || prof->attachment)) { /* no regex so do not set xmatch */ - cod->xmatch = NULL; - cod->xmatch_len = 0; - cod->xmatch_size = 0; + prof->xmatch = NULL; + prof->xmatch_len = 0; + prof->xmatch_size = 0; } else { /* build a dfa */ aare_ruleset_t *rule = aare_new_ruleset(0); @@ -417,9 +418,9 @@ static int process_profile_name_xmatch(struct codomain *cod) aare_delete_ruleset(rule); return FALSE; } - if (cod->altnames) { + if (prof->altnames) { struct alt_name *alt; - list_for_each(cod->altnames, alt) { + list_for_each(prof->altnames, alt) { int len; ptype = convert_aaregex_to_pcre(alt->name, 0, tbuf, @@ -427,18 +428,18 @@ static int process_profile_name_xmatch(struct codomain *cod) &len); if (ptype == ePatternBasic) len = strlen(alt->name); - if (len < cod->xmatch_len) - cod->xmatch_len = len; + if (len < prof->xmatch_len) + prof->xmatch_len = len; if (!aare_add_rule(rule, tbuf, 0, AA_MAY_EXEC, 0, dfaflags)) { aare_delete_ruleset(rule); return FALSE; } } } - cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size, + prof->xmatch = aare_create_dfa(rule, &prof->xmatch_size, dfaflags); aare_delete_ruleset(rule); - if (!cod->xmatch) + if (!prof->xmatch) return FALSE; } @@ -550,70 +551,54 @@ static int process_dfa_entry(aare_ruleset_t *dfarules, struct cod_entry *entry) return TRUE; } -int post_process_entries(struct codomain *cod) +int post_process_entries(Profile *prof) { int ret = TRUE; struct cod_entry *entry; int count = 0; - list_for_each(cod->entries, entry) { - if (!process_dfa_entry(cod->dfarules, entry)) + list_for_each(prof->entries, entry) { + if (!process_dfa_entry(prof->dfa.rules, entry)) ret = FALSE; count++; } - cod->dfarule_count = count; + prof->dfa.count = count; return ret; } -int process_regex(struct codomain *cod) +int process_profile_regex(Profile *prof) { int error = -1; - if (!process_profile_name_xmatch(cod)) + if (!process_profile_name_xmatch(prof)) goto out; - cod->dfarules = aare_new_ruleset(0); - if (!cod->dfarules) + prof->dfa.rules = aare_new_ruleset(0); + if (!prof->dfa.rules) goto out; - if (!post_process_entries(cod)) + if (!post_process_entries(prof)) goto out; - if (cod->dfarule_count > 0) { - cod->dfa = aare_create_dfa(cod->dfarules, &cod->dfa_size, - dfaflags); - aare_delete_ruleset(cod->dfarules); - cod->dfarules = NULL; - if (!cod->dfa) + if (prof->dfa.count > 0) { + prof->dfa.dfa = aare_create_dfa(prof->dfa.rules, &prof->dfa.size, + dfaflags); + aare_delete_ruleset(prof->dfa.rules); + prof->dfa.rules = NULL; + if (!prof->dfa.dfa) goto out; /* - if (cod->dfa_size == 0) { + if (prof->dfa_size == 0) { PERROR(_("profile %s: has merged rules (%s) with " "multiple x modifiers\n"), - cod->name, (char *) cod->dfa); - free(cod->dfa); - cod->dfa = NULL; + prof->name, (char *) prof->dfa); + free(prof->dfa); + prof->dfa = NULL; goto out; } */ } - /* - * Post process subdomain(s): - * - * They are chained from the toplevel subdomain pointer - * thru each next pointer. - - * i.e first subdomain is list->subdomain - * second subdomain is list->subdomain->next - * - * N.B sub-subdomains are not valid so: - * if (list->subdomain) { - * assert(list->subdomain->subdomain == NULL) - * } - */ - if (process_hat_regex(cod) != 0) - goto out; error = 0; @@ -1140,76 +1125,75 @@ fail: return FALSE; } -static int post_process_mnt_ents(struct codomain *cod) +static int post_process_mnt_ents(Profile *prof) { int ret = TRUE; int count = 0; /* Add fns for rules that should be added to policydb here */ - if (cod->mnt_ents && kernel_supports_mount) { + if (prof->mnt_ents && kernel_supports_mount) { struct mnt_entry *entry; - list_for_each(cod->mnt_ents, entry) { - if (!process_mnt_entry(cod->policy_rules, entry)) + list_for_each(prof->mnt_ents, entry) { + if (!process_mnt_entry(prof->policy.rules, entry)) ret = FALSE; count++; } - } else if (cod->mnt_ents && !kernel_supports_mount) - pwarn("profile %s mount rules not enforced\n", cod->name); + } else if (prof->mnt_ents && !kernel_supports_mount) + pwarn("profile %s mount rules not enforced\n", prof->name); + + prof->policy.count += count; - cod->policy_rule_count += count; return ret; } -static int post_process_dbus_ents(struct codomain *cod) +static int post_process_dbus_ents(Profile *prof) { int ret = TRUE; struct dbus_entry *entry; int count = 0; - list_for_each(cod->dbus_ents, entry) { - if (!process_dbus_entry(cod->policy_rules, entry)) + list_for_each(prof->dbus_ents, entry) { + if (!process_dbus_entry(prof->policy.rules, entry)) ret = FALSE; count++; } - cod->policy_rule_count += count; + prof->policy.count += count; return ret; } -int post_process_policydb_ents(struct codomain *cod) +int post_process_policydb_ents(Profile *prof) { - if (!post_process_mnt_ents(cod)) + if (!post_process_mnt_ents(prof)) return FALSE; - if (!post_process_dbus_ents(cod)) + if (!post_process_dbus_ents(prof)) return FALSE; return TRUE; } -int process_policydb(struct codomain *cod) +int process_profile_policydb(Profile *prof) { int error = -1; - cod->policy_rules = aare_new_ruleset(0); - if (!cod->policy_rules) + prof->policy.rules = aare_new_ruleset(0); + if (!prof->policy.rules) goto out; - if (!post_process_policydb_ents(cod)) + if (!post_process_policydb_ents(prof)) goto out; - if (cod->policy_rule_count > 0) { - cod->policy_dfa = aare_create_dfa(cod->policy_rules, - &cod->policy_dfa_size, + if (prof->policy.count > 0) { + prof->policy.dfa = aare_create_dfa(prof->policy.rules, + &prof->policy.size, dfaflags); - aare_delete_ruleset(cod->policy_rules); - cod->policy_rules = NULL; - if (!cod->policy_dfa) + aare_delete_ruleset(prof->policy.rules); + prof->policy.rules = NULL; + if (!prof->policy.dfa) goto out; } aare_reset_matchflags(); - if (process_hat_policydb(cod) != 0) - goto out; error = 0; @@ -1223,6 +1207,9 @@ void reset_regex(void) } #ifdef UNIT_TEST + +#include "unit_test.h" + static int test_filter_slashes(void) { int rc = 0; diff --git a/parser/parser_symtab.c b/parser/parser_symtab.c index 10cf18bb6..d02e4cdf7 100644 --- a/parser/parser_symtab.c +++ b/parser/parser_symtab.c @@ -542,6 +542,9 @@ void free_symtabs(void) } #ifdef UNIT_TEST + +#include "unit_test.h" + int main(void) { int rc = 0; diff --git a/parser/parser_variable.c b/parser/parser_variable.c index fc8bf39ec..4306cf231 100644 --- a/parser/parser_variable.c +++ b/parser/parser_variable.c @@ -28,6 +28,7 @@ /* #define DEBUG */ #include "parser.h" +#include "profile.h" #include "mount.h" #include "dbus.h" @@ -137,12 +138,11 @@ static int expand_entry_variables(char **name, void *entry, int (dup_and_chain)(void *)) { struct set_value *valuelist; - int ret = TRUE; char *value; struct var_string *split_var; if (!entry) /* can happen when entry is optional */ - return ret; + return 0; while ((split_var = split_out_var(*name))) { valuelist = get_set_var(split_var->var); @@ -168,7 +168,7 @@ static int expand_entry_variables(char **name, void *entry, split_var->prefix ? split_var->prefix : "", value, split_var->suffix ? split_var->suffix : "") == -1) - return FALSE; + return -1; while ((value = get_next_set_value(&valuelist))) { if (!dup_and_chain(entry)) { @@ -181,12 +181,12 @@ static int expand_entry_variables(char **name, void *entry, if (asprintf(name, "%s%s%s", split_var->prefix ? split_var->prefix : "", value, split_var->suffix ? split_var->suffix : "") == -1) - return FALSE; + return -1; } free_var_string(split_var); } - return ret; + return 0; } int clone_and_chain_cod(void *v) @@ -229,103 +229,99 @@ int clone_and_chain_dbus(void *v) static int process_variables_in_entries(struct cod_entry *entry_list) { - int ret = TRUE, rc; + int error = 0; struct cod_entry *entry; list_for_each(entry_list, entry) { - rc = expand_entry_variables(&entry->name, entry, - clone_and_chain_cod); - if (!rc) - return FALSE; + error = expand_entry_variables(&entry->name, entry, + clone_and_chain_cod); + if (error) + return error; } - return ret; + return 0; } /* does not currently support expansion of vars in options */ static int process_variables_in_mnt_entries(struct mnt_entry *entry_list) { - int ret = TRUE, rc; + int error = 0; struct mnt_entry *entry; list_for_each(entry_list, entry) { - rc = expand_entry_variables(&entry->mnt_point, entry, - clone_and_chain_mnt); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->device, entry, - clone_and_chain_mnt); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->trans, entry, - clone_and_chain_mnt); - if (!rc) - return FALSE; + error = expand_entry_variables(&entry->mnt_point, entry, + clone_and_chain_mnt); + if (error) + return error; + error = expand_entry_variables(&entry->device, entry, + clone_and_chain_mnt); + if (error) + return error; + error = expand_entry_variables(&entry->trans, entry, + clone_and_chain_mnt); + if (error) + return error; } - return ret; + return 0; } static int process_dbus_variables(struct dbus_entry *entry_list) { - int ret = TRUE, rc; + int error = 0; struct dbus_entry *entry; list_for_each(entry_list, entry) { - rc = expand_entry_variables(&entry->bus, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->name, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->peer_label, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->path, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->interface, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; - rc = expand_entry_variables(&entry->member, entry, - clone_and_chain_dbus); - if (!rc) - return FALSE; + error = expand_entry_variables(&entry->bus, entry, + clone_and_chain_dbus); + if (error) + return error; + error = expand_entry_variables(&entry->name, entry, + clone_and_chain_dbus); + if (error) + return error; + error = expand_entry_variables(&entry->peer_label, entry, + clone_and_chain_dbus); + if (error) + return error; + error = expand_entry_variables(&entry->path, entry, + clone_and_chain_dbus); + if (error) + return error; + error = expand_entry_variables(&entry->interface, entry, + clone_and_chain_dbus); + if (error) + return error; + error = expand_entry_variables(&entry->member, entry, + clone_and_chain_dbus); + if (error) + return error; } - return ret; + return 0; } -int process_variables(struct codomain *cod) +int process_profile_variables(Profile *prof) { int error = 0; - if (!process_variables_in_entries(cod->entries)) { - error = -1; - } + error = process_variables_in_entries(prof->entries); - if (!process_variables_in_mnt_entries(cod->mnt_ents)) { - error = -1; - } + if (!error) + error = process_variables_in_mnt_entries(prof->mnt_ents); - if (!process_dbus_variables(cod->dbus_ents)) { - error = -1; - } + if (!error) + error = process_dbus_variables(prof->dbus_ents); - if (process_hat_variables(cod) != 0) { - error = -1; - } return error; } #ifdef UNIT_TEST + +#include "unit_test.h" + int test_get_var_end(void) { int rc = 0; diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 7e86dbe23..dca8fe205 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -32,6 +32,7 @@ /* #define DEBUG */ #include "parser.h" +#include "profile.h" #include "mount.h" #include "dbus.h" #include "parser_include.h" @@ -76,7 +77,7 @@ struct mnt_entry *do_mnt_rule(struct cond_entry *src_conds, char *src, struct mnt_entry *do_pivot_rule(struct cond_entry *old, char *root, char *transition); -void add_local_entry(struct codomain *cod); +void add_local_entry(Profile *prof); %} @@ -164,13 +165,13 @@ void add_local_entry(struct codomain *cod); char *flag_id; char *mode; struct aa_network_entry *network_entry; - struct codomain *cod; + Profile *prof; struct cod_net_entry *net_entry; struct cod_entry *user_entry; struct mnt_entry *mnt_entry; struct dbus_entry *dbus_entry; - struct flagval flags; + flagvals flags; int fmode; uint64_t cap; unsigned int allowed_protocol; @@ -189,12 +190,12 @@ void add_local_entry(struct codomain *cod); %type TOK_CONDLISTID %type TOK_MODE %type file_mode -%type profile_base -%type profile -%type rules -%type hat -%type local_profile -%type cond_rule +%type profile_base +%type profile +%type rules +%type hat +%type local_profile +%type cond_rule %type network_rule %type rule %type file_rule @@ -261,37 +262,37 @@ opt_id: { /* nothing */ $$ = NULL; } profile_base: TOK_ID opt_id flags TOK_OPEN rules TOK_CLOSE { - struct codomain *cod = $5; + Profile *prof = $5; - if (!cod) { + if (!prof) { yyerror(_("Memory allocation error.")); } - cod->name = $1; - cod->attachment = $2; + prof->name = $1; + prof->attachment = $2; if ($2 && $2[0] != '/') /* we don't support variables as part of the profile * name or attachment atm */ yyerror(_("Profile attachment must begin with a '/'.")); - cod->flags = $3; + prof->flags = $3; if (force_complain) - cod->flags.complain = 1; + prof->flags.complain = 1; - post_process_file_entries(cod); - post_process_mnt_entries(cod); + post_process_file_entries(prof); + post_process_mnt_entries(prof); PDEBUG("%s: flags='%s%s'\n", $2, - cod->flags.complain ? "complain, " : "", - cod->flags.audit ? "audit" : ""); + prof->flags.complain ? "complain, " : "", + prof->flags.audit ? "audit" : ""); - $$ = cod; + $$ = prof; }; profile: opt_profile_flag opt_ns profile_base { - struct codomain *cod = $3; + Profile *prof = $3; if ($2) PDEBUG("Matched: %s://%s { ... }\n", $2, $3->name); else @@ -300,31 +301,31 @@ profile: opt_profile_flag opt_ns profile_base if ($3->name[0] != '/' && !($1 || $2)) yyerror(_("Profile names must begin with a '/', namespace or keyword 'profile' or 'hat'.")); - cod->ns = $2; + prof->ns = $2; if ($1 == 2) - cod->flags.hat = 1; - $$ = cod; + prof->flags.hat = 1; + $$ = prof; }; local_profile: TOK_PROFILE profile_base { - struct codomain *cod = $2; + Profile *prof = $2; if ($2) - PDEBUG("Matched: local profile %s { ... }\n", cod->name); - cod->local = 1; - $$ = cod; + PDEBUG("Matched: local profile %s { ... }\n", prof->name); + prof->local = 1; + $$ = prof; }; hat: hat_start profile_base { - struct codomain *cod = $2; + Profile *prof = $2; if ($2) - PDEBUG("Matched: hat %s { ... }\n", cod->name); + PDEBUG("Matched: hat %s { ... }\n", prof->name); - cod->flags.hat = 1; - $$ = cod; + prof->flags.hat = 1; + $$ = prof; }; preamble: { /* nothing */ } @@ -430,7 +431,7 @@ valuelist: valuelist TOK_VALUE } flags: { /* nothing */ - struct flagval fv = { 0, 0, 0, 0 }; + flagvals fv = { 0, 0, 0, 0 }; $$ = fv; }; @@ -478,7 +479,7 @@ flagvals: flagval flagval: TOK_VALUE { - struct flagval fv = { 0, 0, 0, 0 }; + flagvals fv = { 0, 0, 0, 0 }; if (strcmp($1, "debug") == 0) { yyerror(_("Profile flag 'debug' is no longer valid.")); } else if (strcmp($1, "complain") == 0) { @@ -531,13 +532,12 @@ opt_prefix: opt_audit_flag opt_perm_mode opt_owner_flag } rules: { /* nothing */ - struct codomain *cod = NULL; - cod = (struct codomain *) calloc(1, sizeof(struct codomain)); - if (!cod) { + Profile *prof = new Profile(); + if (!prof) { yyerror(_("Memory allocation error.")); } - $$ = cod; + $$ = prof; }; rules: rules opt_prefix rule @@ -598,8 +598,8 @@ rules: rules opt_prefix TOK_OPEN rules TOK_CLOSE add_entry_to_policy($1, entry); } $4->entries = NULL; - // fix me transfer rules and free sub codomain - free_policy($4); + // fix me transfer rules and free sub profile + delete $4; $$ = $1; }; @@ -612,40 +612,40 @@ rules: rules opt_prefix network_rule yyerror(_("owner prefix not allowed")); if (!$3) yyerror(_("Assert: `network_rule' return invalid protocol.")); - if (!$1->network_allowed) { - $1->network_allowed = (unsigned int *) calloc(get_af_max(), - sizeof(unsigned int)); - $1->audit_network = (unsigned int *)calloc(get_af_max(), + if (!$1->net.allow) { + $1->net.allow = (unsigned int *) calloc(get_af_max(), + sizeof(unsigned int)); + $1->net.audit = (unsigned int *)calloc(get_af_max(), sizeof(unsigned int)); - $1->deny_network = (unsigned int *)calloc(get_af_max(), + $1->net.deny = (unsigned int *)calloc(get_af_max(), sizeof(unsigned int)); - $1->quiet_network = (unsigned int *)calloc(get_af_max(), + $1->net.quiet = (unsigned int *)calloc(get_af_max(), sizeof(unsigned int)); - if (!$1->network_allowed || !$1->audit_network || - !$1->deny_network || !$1->quiet_network) + if (!$1->net.allow || !$1->net.audit || + !$1->net.deny || !$1->net.quiet) yyerror(_("Memory allocation error.")); } list_for_each_safe($3, entry, tmp) { if (entry->type > SOCK_PACKET) { /* setting mask instead of a bit */ if ($2.deny) { - $1->deny_network[entry->family] |= entry->type; + $1->net.deny[entry->family] |= entry->type; if (!$2.audit) - $1->quiet_network[entry->family] |= entry->type; + $1->net.quiet[entry->family] |= entry->type; } else { - $1->network_allowed[entry->family] |= entry->type; + $1->net.allow[entry->family] |= entry->type; if ($2.audit) - $1->audit_network[entry->family] |= entry->type; + $1->net.audit[entry->family] |= entry->type; } } else { if ($2.deny) { - $1->deny_network[entry->family] |= 1 << entry->type; + $1->net.deny[entry->family] |= 1 << entry->type; if (!$2.audit) - $1->quiet_network[entry->family] |= 1 << entry->type; + $1->net.quiet[entry->family] |= 1 << entry->type; } else { - $1->network_allowed[entry->family] |= 1 << entry->type; + $1->net.allow[entry->family] |= 1 << entry->type; if ($2.audit) - $1->audit_network[entry->family] |= 1 << entry->type; + $1->net.audit[entry->family] |= 1 << entry->type; } } free(entry); @@ -696,12 +696,12 @@ rules: rules opt_prefix capability yyerror(_("owner prefix not allow on capability rules")); if ($2.deny) - $1->deny_caps |= $3; + $1->caps.deny |= $3; else - $1->capabilities |= $3; + $1->caps.allow |= $3; if (!$2.audit) - $1->quiet_caps |= $3; + $1->caps.quiet |= $3; $$ = $1; }; @@ -824,40 +824,40 @@ rules: rules TOK_SET TOK_RLIMIT TOK_ID TOK_LE TOK_VALUE TOK_END_OF_RULE cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE { - struct codomain *ret = NULL; + Profile *ret = NULL; PDEBUG("Matched: found conditional rules\n"); if ($2) { ret = $4; } else { - free_policy($4); + delete $4; } $$ = ret; } cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE TOK_OPEN rules TOK_CLOSE { - struct codomain *ret = NULL; + Profile *ret = NULL; PDEBUG("Matched: found conditional else rules\n"); if ($2) { ret = $4; - free_policy($8); + delete $8; } else { ret = $8; - free_policy($4); + delete $4; } $$ = ret; } cond_rule: TOK_IF expr TOK_OPEN rules TOK_CLOSE TOK_ELSE cond_rule { - struct codomain *ret = NULL; + Profile *ret = NULL; PDEBUG("Matched: found conditional else-if rules\n"); if ($2) { ret = $4; - free_policy($7); + delete $7; } else { ret = $7; - free_policy($4); + delete $4; } $$ = ret; } @@ -1307,25 +1307,25 @@ struct cod_entry *do_file_rule(char *ns, char *id, int mode, /* Note: NOT currently in use, used for * /foo x -> { /bah, } style transitions */ -void add_local_entry(struct codomain *cod) +void add_local_entry(Profile *prof) { /* ugh this has to be called after the hat is attached to its parent */ - if (cod->local_mode) { + if (prof->local_mode) { struct cod_entry *entry; - char *trans = (char *) malloc(strlen(cod->parent->name) + - strlen(cod->name) + 3); - char *name = strdup(cod->name); + char *trans = (char *) malloc(strlen(prof->parent->name) + + strlen(prof->name) + 3); + char *name = strdup(prof->name); if (!trans) yyerror(_("Memory allocation error.")); - sprintf(name, "%s//%s", cod->parent->name, cod->name); + sprintf(name, "%s//%s", prof->parent->name, prof->name); - entry = new_entry(NULL, name, cod->local_mode, NULL); - entry->audit = cod->local_audit; + entry = new_entry(NULL, name, prof->local_mode, NULL); + entry->audit = prof->local_audit; entry->nt_name = trans; if (!entry) yyerror(_("Memory allocation error.")); - add_entry_to_policy(cod, entry); + add_entry_to_policy(prof, entry); } } diff --git a/parser/profile.cc b/parser/profile.cc new file mode 100644 index 000000000..0914a53ea --- /dev/null +++ b/parser/profile.cc @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 + * 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. + */ + +#include "profile.h" + +#include +#include + +bool deref_profileptr_lt::operator()(Profile * const &lhs, Profile * const &rhs) const +{ + return *lhs < *rhs; +}; + +pair ProfileList::insert(Profile *p) +{ + return list.insert(p); +} + +void ProfileList::erase(ProfileList::iterator pos) +{ + list.erase(pos); +} + +void ProfileList::clear(void) +{ + for(ProfileList::iterator i = list.begin(); i != list.end(); ) { + ProfileList::iterator k = i++; + delete *k; + list.erase(k); + } +} + +void ProfileList::dump(void) +{ + for(ProfileList::iterator i = list.begin(); i != list.end(); i++) { + (*i)->dump(); + } +} + +void ProfileList::dump_profile_names(bool children) +{ + for (ProfileList::iterator i = list.begin(); i != list.end();i++) { + (*i)->dump_name(true); + printf("\n"); + if (children && !(*i)->hat_table.empty()) + (*i)->hat_table.dump_profile_names(children); + } +} + +Profile::~Profile() +{ + hat_table.clear(); + free_cod_entries(entries); + free_mnt_entries(mnt_ents); + free_dbus_entries(dbus_ents); + if (dfa.rules) + aare_delete_ruleset(dfa.rules); + if (dfa.dfa) + free(dfa.dfa); + if (policy.rules) + aare_delete_ruleset(policy.rules); + if (policy.dfa) + free(policy.dfa); + if (name) + free(name); + if (attachment) + free(attachment); + if (ns) + free(ns); + if (net.allow) + free(net.allow); + if (net.audit) + free(net.audit); + if (net.deny) + free(net.deny); + if (net.quiet) + free(net.quiet); +} + diff --git a/parser/profile.h b/parser/profile.h new file mode 100644 index 000000000..3bfa6557e --- /dev/null +++ b/parser/profile.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2012 + * 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. + */ +#ifndef __AA_PROFILE_H +#define __AA_PROFILE_H + +#include + +#include "parser.h" + +class Profile; + +class block { +public: + +}; + + +struct deref_profileptr_lt { + bool operator()(Profile * const &lhs, Profile * const &rhs) const; +}; + +class ProfileList { +public: + set list; + + typedef set::iterator iterator; + iterator begin() { return list.begin(); } + iterator end() { return list.end(); } + + ProfileList() { }; + virtual ~ProfileList() { clear(); } + virtual bool empty(void) { return list.empty(); } + virtual pair insert(Profile *); + virtual void erase(ProfileList::iterator pos); + void clear(void); + void dump(void); + void dump_profile_names(bool children); +}; + + + +class flagvals { +public: + int hat; + int complain; + int audit; + int path; + + void dump(void) + { + printf("Profile Mode:\t"); + + if (complain) + printf("Complain"); + else + printf("Enforce"); + + if (audit) + printf(", Audit"); + + if (hat) + printf(", Hat"); + + printf("\n"); + } +}; + +struct capabilities { + uint64_t allow; + uint64_t audit; + uint64_t deny; + uint64_t quiet; + + capabilities(void) { allow = audit = deny = quiet; } + + void dump() + { + if (allow != 0ull) + __debug_capabilities(allow, "Capabilities"); + if (audit != 0ull) + __debug_capabilities(audit, "Audit Caps"); + if (deny != 0ull) + __debug_capabilities(deny, "Deny Caps"); + if (quiet != 0ull) + __debug_capabilities(quiet, "Quiet Caps"); + }; +}; + +struct network { + unsigned int *allow; /* array of type masks + * indexed by AF_FAMILY */ + unsigned int *audit; + unsigned int *deny; + unsigned int *quiet; + + network(void) { allow = audit = deny = quiet = NULL; } + + void dump(void) { + if (allow) + __debug_network(allow, "Network"); + if (audit) + __debug_network(audit, "Audit Net"); + if (deny) + __debug_network(deny, "Deny Net"); + if (quiet) + __debug_network(quiet, "Quiet Net"); + } +}; + +struct dfa_stuff { + aare_ruleset_t *rules; + int count; + void *dfa; + size_t size; + + dfa_stuff(void): rules(NULL), count(0), dfa(NULL), size(0) { } +}; + +class Profile { +public: + char *ns; + char *name; + char *attachment; + struct alt_name *altnames; + void *xmatch; + size_t xmatch_size; + int xmatch_len; + + /* char *sub_name; */ /* subdomain name or NULL */ + /* int default_deny; */ /* TRUE or FALSE */ + int local; + int local_mode; /* true if local, not hat */ + int local_audit; + + Profile *parent; + + struct flagvals flags; + struct capabilities caps; + struct network net; + + struct aa_rlimits rlimits; + + char *exec_table[AA_EXEC_COUNT]; + struct cod_entry *entries; + struct mnt_entry *mnt_ents; + struct dbus_entry *dbus_ents; + + ProfileList hat_table; + + struct dfa_stuff dfa; + struct dfa_stuff policy; + + Profile(void) + { + ns = name = attachment = NULL; + altnames = NULL; + xmatch = NULL; + xmatch_size = 0; + xmatch_len = 0; + + local = local_mode = local_audit = 0; + + parent = NULL; + + flags = { 0, 0, 0, 0}; + rlimits = { 0 }; + + std::fill(exec_table, exec_table + AA_EXEC_COUNT, (char *)NULL); + + entries = NULL; + mnt_ents = NULL; + dbus_ents = NULL; + + }; + + virtual ~Profile(); + + bool operator<(Profile const &rhs)const + { + if (ns) { + if (rhs.ns) { + int res = strcmp(ns, rhs.ns); + if (res != 0) + return res < 0; + } else + return false; + } else if (rhs.ns) + return true; + return strcmp(name, rhs.name) < 0; + } + + void dump(void) + { + if (ns) + printf("Ns:\t\t%s\n", ns); + + if (name) + printf("Name:\t\t%s\n", name); + else + printf("Name:\t\t\n"); + + if (local) { + if (parent) + printf("Local To:\t%s\n", parent->name); + else + printf("Local To:\t\n"); + } + + flags.dump(); + caps.dump(); + net.dump(); + + if (entries) + debug_cod_entries(entries); + + printf("\n"); + hat_table.dump(); + } + + void dump_name(bool fqp) + { + if (fqp && parent) { + parent->dump_name(fqp); + printf("//%s", name); + } else + printf("%s", name); + } +}; + + +#endif /* __AA_PROFILE_H */ diff --git a/parser/unit_test.h b/parser/unit_test.h new file mode 100644 index 000000000..ac94c98b5 --- /dev/null +++ b/parser/unit_test.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 + * 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_UNIT_TEST_H +#define __AA_UNIT_TEST_H + +#ifdef UNIT_TEST +/* For the unit-test builds, we must include function stubs for stuff that + * only exists in the excluded object files; everything else should live + * in parser_common.c. + */ + +#include +#include +#include + +#undef _ +#define _(s) (s) + +/* parser_yacc.y */ +void yyerror(const char *msg, ...) +{ + va_list arg; + char buf[PATH_MAX]; + + va_start(arg, msg); + vsnprintf(buf, sizeof(buf), msg, arg); + va_end(arg); + + PERROR(_("AppArmor parser error: %s\n"), buf); + + exit(1); +} + +#define MY_TEST(statement, error) \ + if (!(statement)) { \ + PERROR("FAIL: %s\n", error); \ + rc = 1; \ + } + +#endif /* UNIT_TEST */ + +#endif /* __AA_UNIT_TEST_H */