From dbca8ebb896124bd444f862a49a22e7990dffe75 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 3 Jul 2023 01:41:43 -0700 Subject: [PATCH 01/14] parser: Improve the rule skip test. Rules can be marked as being deleted/merged, and should be skipped on further processing. Signed-off-by: John Johansen --- parser/parser_regex.c | 2 +- parser/parser_variable.c | 2 +- parser/profile.cc | 2 +- parser/rule.h | 6 ++++++ 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/parser/parser_regex.c b/parser/parser_regex.c index deb704f36..dfab8328a 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -848,7 +848,7 @@ int clear_and_convert_entry(std::string& buffer, char *entry) int post_process_policydb_ents(Profile *prof) { for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) { - if ((*i)->flags & RULE_FLAG_DELETED) + if ((*i)->skip_processing()) continue; if ((*i)->gen_policy_re(*prof) == RULE_ERROR) return FALSE; diff --git a/parser/parser_variable.c b/parser/parser_variable.c index 15978538b..4f3e8f2f0 100644 --- a/parser/parser_variable.c +++ b/parser/parser_variable.c @@ -267,7 +267,7 @@ static int process_variables_in_entries(struct cod_entry *entry_list) static int process_variables_in_rules(Profile &prof) { for (RuleList::iterator i = prof.rule_ents.begin(); i != prof.rule_ents.end(); i++) { - if ((*i)->flags & RULE_FLAG_DELETED) + if ((*i)->skip_processing()) continue; int error = (*i)->expand_variables(); if (error) diff --git a/parser/profile.cc b/parser/profile.cc index 27fe570ee..e16546450 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -318,7 +318,7 @@ void post_process_file_entries(Profile *prof) void post_process_rule_entries(Profile *prof) { for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) { - if ((*i)->flags & RULE_FLAG_DELETED) + if ((*i)->skip_processing()) continue; (*i)->post_parse_profile(*prof); } diff --git a/parser/rule.h b/parser/rule.h index 469b91580..f4931a890 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -58,6 +58,12 @@ public: bool is_type(int type) { return rule_type == type; } + // rule has been marked as should be skipped by regular processing + bool skip_processing() + { + return (flags == RULE_FLAG_DELETED || + flags == RULE_FLAG_MERGED); + } //virtual bool operator<(rule_t const &rhs)const = 0; virtual std::ostream &dump(std::ostream &os) = 0; From 7d9958890f4a1bf4975140776c25e639bd2dafb2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 3 Jul 2023 23:52:57 -0700 Subject: [PATCH 02/14] parser: finish basic infrastructure for rule merging Currently only file rules get merged. Finish adding basic support for rule merging and make the default the behavior to dedup merge rules that are exact matches. Signed-off-by: John Johansen --- parser/parser.h | 4 ++ parser/parser_merge.c | 15 ++++- parser/parser_misc.c | 65 +++++++++++++++++++ parser/parser_regex.c | 2 +- parser/parser_variable.c | 2 +- parser/profile.cc | 41 ++++++------ parser/profile.h | 2 +- parser/rule.h | 133 +++++++++++++++++++++++++++++++++------ 8 files changed, 220 insertions(+), 44 deletions(-) diff --git a/parser/parser.h b/parser/parser.h index 0399db8be..e5b785480 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -99,6 +99,8 @@ struct value_list { struct value_list *next; }; +int cmp_value_list(value_list *lhs, value_list *rhs); + struct cond_entry { char *name; int eq; /* where equals was used in specifying list */ @@ -454,6 +456,8 @@ extern struct cod_entry *new_entry(char *id, perms_t perms, char *link_id); /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */ extern int str_to_boolean(const char* str); +extern int null_strcmp(const char *s1, const char *s2); +extern bool strcomp (const char *lhs, const char *rhs); extern struct cod_entry *copy_cod_entry(struct cod_entry *cod); extern void free_cod_entries(struct cod_entry *list); void debug_cod_entries(struct cod_entry *list); diff --git a/parser/parser_merge.c b/parser/parser_merge.c index 77c295e19..b8041ebb5 100644 --- a/parser/parser_merge.c +++ b/parser/parser_merge.c @@ -72,7 +72,7 @@ static int process_file_entries(Profile *prof) table = (struct cod_entry **) malloc(sizeof(struct cod_entry *) * (count + 1)); if (!table) { PERROR(_("Couldn't merge entries. Out of Memory\n")); - return ENOMEM; + return -ENOMEM; } for (cur = prof->entries, n = 0; cur; cur = cur->next, n++) @@ -84,6 +84,7 @@ static int process_file_entries(Profile *prof) prof->entries = table[0]; free(table); + count = 0; /* walk the sorted table merging similar entries */ for (cur = prof->entries, next = cur->next; next; next = cur->next) { if (file_comp(&cur, &next) != 0) { @@ -102,12 +103,20 @@ static int process_file_entries(Profile *prof) next->next = NULL; free_cod_entries(next); + count++; } - return 0; + return count; } int profile_merge_rules(Profile *prof) { - return process_file_entries(prof); + int res, tmp = process_file_entries(prof); + if (tmp < 0) + return -tmp; + res = prof->merge_rules(); + if (res < 0) + return -res; + // TODO: output message eliminated rules res + tmp; + return 0; } diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 651b4ce98..ed80d068f 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -34,6 +34,8 @@ #include #include +#include + #include "capability.h" #include "lib.h" #include "parser.h" @@ -271,6 +273,25 @@ static const char *strn_token(const char *str, size_t &len) return start; } +int null_strcmp(const char *s1, const char *s2) +{ + if (s1) { + if (s2) + return strcmp(s1, s2); + return 1; + } else if (s2) { + return -1; + } + + // both null + return 0; +} + +bool strcomp (const char *lhs, const char *rhs) +{ + return null_strcmp(lhs, rhs) < 0; +} + /* * Returns: -1: error * 0: no change - capability already in table @@ -1065,6 +1086,50 @@ void debug_cod_entries(struct cod_entry *list) } } +// these need to move to stl +int ordered_cmp_value_list(value_list *lhs, value_list *rhs) +{ + std::vector lhstable; + std::vector rhstable; + + struct value_list *entry; + list_for_each(lhs, entry) { + lhstable.push_back(entry->value); + } + list_for_each(rhs, entry) { + rhstable.push_back(entry->value); + } + + int res = lhstable.size() - rhstable.size(); + if (res) + return res; + + std::sort(lhstable.begin(), lhstable.end(), strcomp); + std::sort(rhstable.begin(), rhstable.end(), strcomp); + + for (unsigned long i = 0; i < lhstable.size(); i++) { + res = null_strcmp(lhstable[i], rhstable[i]); + if (res) + return res; + } + + return 0; +} + +int cmp_value_list(value_list *lhs, value_list *rhs) +{ + if (lhs) { + if (rhs) { + return ordered_cmp_value_list(lhs, rhs); + } + return 1; + } else if (rhs) { + return -1; + } + + return 0; +} + struct value_list *new_value_list(char *value) { struct value_list *val = (struct value_list *) calloc(1, sizeof(struct value_list)); diff --git a/parser/parser_regex.c b/parser/parser_regex.c index dfab8328a..95d018342 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -848,7 +848,7 @@ int clear_and_convert_entry(std::string& buffer, char *entry) int post_process_policydb_ents(Profile *prof) { for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) { - if ((*i)->skip_processing()) + if ((*i)->skip()) continue; if ((*i)->gen_policy_re(*prof) == RULE_ERROR) return FALSE; diff --git a/parser/parser_variable.c b/parser/parser_variable.c index 4f3e8f2f0..61cdcc3a8 100644 --- a/parser/parser_variable.c +++ b/parser/parser_variable.c @@ -267,7 +267,7 @@ static int process_variables_in_entries(struct cod_entry *entry_list) static int process_variables_in_rules(Profile &prof) { for (RuleList::iterator i = prof.rule_ents.begin(); i != prof.rule_ents.end(); i++) { - if ((*i)->skip_processing()) + if ((*i)->skip()) continue; int error = (*i)->expand_variables(); if (error) diff --git a/parser/profile.cc b/parser/profile.cc index e16546450..9eeb39018 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -121,38 +121,39 @@ Profile::~Profile() free(net.quiet); } -static bool comp (rule_t *lhs, rule_t *rhs) { return (*lhs < *rhs); } +static bool comp (rule_t *lhs, rule_t *rhs) +{ + return (*lhs < *rhs); +} -bool Profile::merge_rules(void) +// TODO: move to block rule +// returns number of rules merged +// returns negative number on error +int Profile::merge_rules(void) { int count = 0; + std::vector table; - for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); ) { - if ((*i)->is_mergeable()) - count++; + for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++) { + if ((*i)->is_mergeable() && !(*i)->skip()) + table.push_back(*i); } - if (count < 2) + if (table.size() < 2) return 0; - - std::vector table(count); - int n = 0; - for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); ) { - if ((*i)->is_mergeable()) - table[n++] = *i; - } - std::sort(table.begin(), table.end(), comp); - - for (int i = 0, j = 1; j < count; j++) { + unsigned long n = table.size(); + for (unsigned long i = 0, j = 1; j < n; j++) { + if (table[j]->skip()) + continue; if (table[i]->cmp(*table[j]) == 0) { - if (!table[i]->merge(*table[j])) - return false; + if (table[i]->merge(*table[j])) + count++; continue; } i = j; } - return true; + return count; } @@ -318,7 +319,7 @@ void post_process_file_entries(Profile *prof) void post_process_rule_entries(Profile *prof) { for (RuleList::iterator i = prof->rule_ents.begin(); i != prof->rule_ents.end(); i++) { - if ((*i)->skip_processing()) + if ((*i)->skip()) continue; (*i)->post_parse_profile(*prof); } diff --git a/parser/profile.h b/parser/profile.h index 683e97695..c73b59faf 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -249,7 +249,7 @@ public: * Requires the merged rules have customized methods * cmp(), is_mergeable() and merge() */ - virtual bool merge_rules(void); + virtual int merge_rules(void); void dump(void) { diff --git a/parser/rule.h b/parser/rule.h index f4931a890..a040333ba 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -38,6 +38,10 @@ class Profile; // RULE_TYPE_CLASS needs to be last because various class follow it #define RULE_TYPE_CLASS 3 +// rule_cast should only be used after a comparison of rule_type to ensure +// that it is valid. Change to dynamic_cast for debugging +//#define rule_cast dynamic_cast +#define rule_cast static_cast typedef enum { RULE_FLAG_NONE = 0, RULE_FLAG_DELETED = 1, // rule deleted - skip @@ -48,21 +52,38 @@ typedef enum { RULE_FLAG_NONE = 0, // added because it is implied } rule_flags_t; +inline rule_flags_t operator|(rule_flags_t a, rule_flags_t b) +{ + return static_cast(static_cast(a) | static_cast(b)); +} + +inline rule_flags_t operator&(rule_flags_t a, rule_flags_t b) +{ + return static_cast(static_cast(a) & static_cast(b)); +} + +inline rule_flags_t& operator|=(rule_flags_t &a, const rule_flags_t &b) +{ + a = a | b; + return a; +} + class rule_t { public: int rule_type; rule_flags_t flags; - rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE) { } + rule_t *removed_by; + + rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE), removed_by(NULL) { } virtual ~rule_t() { }; bool is_type(int type) { return rule_type == type; } // rule has been marked as should be skipped by regular processing - bool skip_processing() + bool skip() { - return (flags == RULE_FLAG_DELETED || - flags == RULE_FLAG_MERGED); + return (flags & RULE_FLAG_DELETED); } //virtual bool operator<(rule_t const &rhs)const = 0; virtual std::ostream &dump(std::ostream &os) = 0; @@ -81,15 +102,37 @@ public: // to support expansion in include names and profile names virtual int expand_variables(void) = 0; - // called by duplicate rule merge/elimination after final expand_vars - virtual bool is_mergeable(void) { return false; } virtual int cmp(rule_t const &rhs) const { - return rule_type < rhs.rule_type; + return rule_type - rhs.rule_type; } virtual bool operator<(rule_t const &rhs) const { return cmp(rhs) < 0; } - virtual bool merge(rule_t &rhs __attribute__ ((unused))) { return false; }; + // called by duplicate rule merge/elimination after final expand_vars + // to get default rule dedup + // child object need to provide + // - cmp, operator< + // - is_mergeable() returning true + // if a child object wants to provide merging of permissions, + // it needs to provide a custom cmp fn that doesn't include + // permissions and a merge routine that does more than flagging + // as dup as below + virtual bool is_mergeable(void) { return false; } + + // returns true if merged + virtual bool merge(rule_t &rhs) + { + if (rule_type != rhs.rule_type) + return false; + if (skip() || rhs.skip()) + return false; + // default merge is just dedup + flags |= RULE_FLAG_MERGED; + rhs.flags |= (RULE_FLAG_MERGED | RULE_FLAG_DELETED); + rhs.removed_by = this; + + return true; + }; // called late frontend to generate data for regex backend virtual int gen_policy_re(Profile &prof) = 0; @@ -162,6 +205,32 @@ public: return os; } + + int cmp(prefixes const &rhs) const { + if ((uint) audit < (uint) rhs.audit) + return -1; + if ((uint) audit > (uint) rhs.audit) + return 1; + if ((uint) rule_mode < (uint) rhs.rule_mode) + return -1; + if ((uint) rule_mode > (uint) rhs.rule_mode) + return 1; + if (owner < rhs.owner) + return -1; + if (owner > rhs.owner) + return 1; + return 0; + } + + bool operator<(prefixes const &rhs) const { + if ((uint) audit < (uint) rhs.audit) + return true; + if ((uint) rule_mode < (uint) rhs.rule_mode) + return true; + if (owner < rhs.owner) + return true; + return false; + } }; class prefix_rule_t: public rule_t, public prefixes { @@ -221,21 +290,32 @@ public: return true; } - virtual bool operator<(prefixes const &rhs) const { - if ((uint) audit < (uint) rhs.audit) - return true; - if ((uint) rule_mode < (uint) rhs.rule_mode) - return true; - if (owner < rhs.owner) - return true; - return false; + int cmp(prefixes const &rhs) const { + return prefixes::cmp(rhs); } - virtual bool operator<(prefix_rule_t const &rhs) const { + + virtual bool operator<(prefixes const &rhs) const { + const prefixes *ptr = this; + return *ptr < rhs; + } + + virtual int cmp(rule_t const &rhs) const { + int res = rule_t::cmp(rhs); + if (res) + return res; + prefix_rule_t const &pr = rule_cast(rhs); + const prefixes *lhsptr = this, *rhsptr = ≺ + return lhsptr->cmp(*rhsptr); + } + + virtual bool operator<(rule_t const &rhs) const { if (rule_type < rhs.rule_type) return true; if (rhs.rule_type < rule_type) return false; - return *this < (prefixes const &)rhs; + prefix_rule_t const &pr = rule_cast(rhs); + const prefixes *rhsptr = ≺ + return *this < *rhsptr; } virtual ostream &dump(ostream &os) { @@ -253,6 +333,16 @@ public: int aa_class(void) { return rule_type - RULE_TYPE_CLASS; } + /* inherit cmp */ + + /* we do not inherit operator< from so class_rules children + * can in herit the generic one that redirects to cmp() + * that does get overriden + */ + virtual bool operator<(rule_t const &rhs) const { + return cmp(rhs) < 0; + } + virtual ostream &dump(ostream &os) { prefix_rule_t::dump(os); @@ -267,6 +357,13 @@ class perms_rule_t: public class_rule_t { public: perms_rule_t(int c): class_rule_t(c), perms(0) { }; + virtual int cmp(rule_t const &rhs) const { + int res = class_rule_t::cmp(rhs); + if (res) + return res; + return perms - (rule_cast(rhs)).perms; + } + /* defaut perms, override/mask off if none default used */ virtual ostream &dump(ostream &os) { From 3ede2c46cfdb28cf2e578ad87180e3798c9f2ce5 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:05:23 -0700 Subject: [PATCH 03/14] parser: add rule dedup of mount rules Signed-off-by: John Johansen --- parser/mount.cc | 45 +++++++++++++++++++++++++++++++++++++++++++++ parser/mount.h | 6 ++++++ 2 files changed, 51 insertions(+) diff --git a/parser/mount.cc b/parser/mount.cc index 7b551a6fd..043864078 100644 --- a/parser/mount.cc +++ b/parser/mount.cc @@ -632,6 +632,51 @@ int mnt_rule::expand_variables(void) return 0; } +static int cmp_vec_int(std::vector const &lhs, + std::vector const &rhs) +{ + int res = lhs.size() - rhs.size(); + if (res) + return res; + + for (unsigned long i = 0; i < lhs.size(); i++) { + res = lhs[i] - rhs[i]; + if (res) + return res; + } + + return 0; +} + +int mnt_rule::cmp(rule_t const &rhs) const { + // for now don't do merging of perms, only exact match + int res = perms_rule_t::cmp(rhs); + if (res != 0) + return res; + mnt_rule const &rhs_mnt = rule_cast(rhs); + res = null_strcmp(mnt_point, rhs_mnt.mnt_point); + if (res) + return res; + res = null_strcmp(device, rhs_mnt.device); + if (res) + return res; + res = null_strcmp(trans, rhs_mnt.trans); + if (res) + return res; + + res = cmp_value_list(dev_type, rhs_mnt.dev_type); + if (res) + return res; + res = cmp_value_list(opts, rhs_mnt.opts); + if (res) + return res; + + res = cmp_vec_int(flagsv, rhs_mnt.flagsv); + if (res) + return res; + return cmp_vec_int(opt_flagsv, rhs_mnt.opt_flagsv); + } + static int build_mnt_flags(char *buffer, int size, unsigned int flags, unsigned int opt_flags) { diff --git a/parser/mount.h b/parser/mount.h index f28196c92..fa1794f87 100644 --- a/parser/mount.h +++ b/parser/mount.h @@ -21,6 +21,7 @@ #include #include +#include #include "parser.h" #include "rule.h" @@ -173,6 +174,11 @@ public: virtual int gen_policy_re(Profile &prof); virtual void post_parse_profile(Profile &prof unused); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const; + + // for now use default merge/dedup + protected: virtual void warn_once(const char *name) override; }; From 53b99a82f6424a7cf579cbfbb3a7b78e5acfdebf Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:27:03 -0700 Subject: [PATCH 04/14] parser: add rule merging for signals Signed-off-by: John Johansen --- parser/signal.cc | 29 +++++++++++++++++++++++++++++ parser/signal.h | 3 +++ 2 files changed, 32 insertions(+) diff --git a/parser/signal.cc b/parser/signal.cc index 5e3eff701..fde038525 100644 --- a/parser/signal.cc +++ b/parser/signal.cc @@ -230,6 +230,35 @@ int signal_rule::expand_variables(void) return expand_entry_variables(&peer_label); } +static int cmp_set_int(Signals const &lhs, Signals const &rhs) +{ + int res = lhs.size() - rhs.size(); + if (res) + return res; + + for (Signals::iterator i = lhs.begin(), + j = rhs.begin(); + i != lhs.end(); i++, j++) { + res = *i - *j; + if (res) + return res; + } + + return 0; +} + +int signal_rule::cmp(rule_t const &rhs) const +{ + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + signal_rule const &trhs = rule_cast(rhs); + res = null_strcmp(peer_label, trhs.peer_label); + if (res) + return res; + return cmp_set_int(signals, trhs.signals); +} + void signal_rule::warn_once(const char *name) { rule_t::warn_once(name, "signal rules not enforced"); diff --git a/parser/signal.h b/parser/signal.h index 391c8b34d..e5df3d2a7 100644 --- a/parser/signal.h +++ b/parser/signal.h @@ -57,6 +57,9 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const; + protected: virtual void warn_once(const char *name) override; }; From fd20c226e04f617a0712284dfd10c95202495970 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:32:44 -0700 Subject: [PATCH 05/14] parser: add rule merging for userns rules Signed-off-by: John Johansen --- parser/userns.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parser/userns.h b/parser/userns.h index b72577124..0c7f8a5c1 100644 --- a/parser/userns.h +++ b/parser/userns.h @@ -42,6 +42,12 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + return perms_rule_t::cmp(rhs); + }; + protected: virtual void warn_once(const char *name) override; }; From 0f660828e1aeaaffe3532a3173cc7cd623bb10ab Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:37:03 -0700 Subject: [PATCH 06/14] parser: add rule merging for ptrace rules Signed-off-by: John Johansen --- parser/ptrace.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/parser/ptrace.h b/parser/ptrace.h index 89881de91..b129c5795 100644 --- a/parser/ptrace.h +++ b/parser/ptrace.h @@ -52,6 +52,16 @@ public: return true; }; + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + return null_strcmp(peer_label, + (rule_cast(rhs)).peer_label); + }; + protected: virtual void warn_once(const char *name) override; }; From ca976bf5cbc061825ab3c8441b64ad306585b1c4 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:41:26 -0700 Subject: [PATCH 07/14] parser: add rule merging for mqueue rules Signed-off-by: John Johansen --- parser/mqueue.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/parser/mqueue.h b/parser/mqueue.h index 24265666c..da5e414b8 100644 --- a/parser/mqueue.h +++ b/parser/mqueue.h @@ -107,6 +107,22 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + mqueue_rule const &trhs = rule_cast(rhs); + res = qtype - trhs.qtype; + if (res) + return res; + res = null_strcmp(qname, trhs.qname); + if (res) + return res; + return null_strcmp(label, trhs.label); + }; + protected: virtual void warn_once(const char *name) override; void validate_qname(void); From 08a0970d1f8252bd3b734d72ddb0ea2b8aac516a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:44:55 -0700 Subject: [PATCH 08/14] parser: add io_uring rule merging Signed-off-by: John Johansen --- parser/io_uring.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/parser/io_uring.h b/parser/io_uring.h index 7644403c7..d363c5443 100644 --- a/parser/io_uring.h +++ b/parser/io_uring.h @@ -49,6 +49,16 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + return null_strcmp(label, + (rule_cast(rhs)).label); + }; + protected: virtual void warn_once(const char *name) override; }; From 00553a6dd555661707e689b357c03f95e502678a Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:52:08 -0700 Subject: [PATCH 09/14] parser: add rule mergeing for af_rules Signed-off-by: John Johansen --- parser/af_rule.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/parser/af_rule.h b/parser/af_rule.h index 8ff77e738..bc06e6193 100644 --- a/parser/af_rule.h +++ b/parser/af_rule.h @@ -76,6 +76,35 @@ public: virtual ostream &dump(ostream &os); virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof) = 0; + + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + af_rule const &trhs = (rule_cast(rhs)); + res = af - trhs.af; + if (res) + return res; + res = sock_type_n - trhs.sock_type_n; + if (res) + return res; + res = proto_n - trhs.proto_n; + if (res) + return res; + res = null_strcmp(sock_type, trhs.sock_type); + if (res) + return res; + res = null_strcmp(proto, trhs.proto); + if (res) + return res; + res = null_strcmp(label, trhs.label); + if (res) + return res; + return null_strcmp(peer_label, trhs.peer_label); + }; + }; #endif /* __AA_AF_RULE_H */ From 5e713276ca8cbc8927b15ef2b88049ce50a084cf Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 03:56:20 -0700 Subject: [PATCH 10/14] parser: add rule merging for af_unix rules this is reuired because af_rule merging does not take into account the potential af_unix addresses and could incorrectly merge af_unix rules. Signed-off-by: John Johansen --- parser/af_unix.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/parser/af_unix.h b/parser/af_unix.h index 27cb662bb..ff10565d0 100644 --- a/parser/af_unix.h +++ b/parser/af_unix.h @@ -62,6 +62,19 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + // inherit is_mergable() from af_rule + virtual int cmp(rule_t const &rhs) const + { + int res = af_rule::cmp(rhs); + if (res) + return res; + unix_rule const &trhs = (rule_cast(rhs)); + res = null_strcmp(addr, trhs.addr); + if (res) + return res; + return null_strcmp(peer_addr, trhs.peer_addr); + }; + protected: virtual void warn_once(const char *name) override; }; From c5f2fcbb956c06725bdb948cb173231506b09f58 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 04:02:29 -0700 Subject: [PATCH 11/14] parser: add rule merging for dbus rules Signed-off-by: John Johansen --- parser/dbus.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/parser/dbus.h b/parser/dbus.h index f35797e9a..a273bffe5 100644 --- a/parser/dbus.h +++ b/parser/dbus.h @@ -62,6 +62,32 @@ public: virtual int expand_variables(void); virtual int gen_policy_re(Profile &prof); + virtual bool is_mergeable(void) { return true; } + virtual int cmp(rule_t const &rhs) const + { + int res = perms_rule_t::cmp(rhs); + if (res) + return res; + dbus_rule const &trhs = (rule_cast(rhs)); + res = null_strcmp(bus, trhs.bus); + if (res) + return res; + res = null_strcmp(name, trhs.name); + if (res) + return res; + res = null_strcmp(peer_label, trhs.peer_label); + if (res) + return res; + res = null_strcmp(path, trhs.path); + if (res) + return res; + res = null_strcmp(interface, trhs.interface); + if (res) + return res; + return null_strcmp(member, trhs.member); + }; + + protected: virtual void warn_once(const char *name) override; }; From e84e48126305d2f2480b54811ed2e13dbe4918a6 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Jul 2023 16:41:56 -0700 Subject: [PATCH 12/14] parser: cleanup and rework optimization and dump flag handling In preparation for more flags (not all of the backend dfa based), rework the optimization and dump flag handling which has been exclusively around the dfa up to this point. - split dfa control and dump flags into separate fields. This gives more room for new flags in the existing DFA set - rename DFA_DUMP, and DFA_CONTROL to CONTROL_DFA and DUMP_DFA as this will provide more uniform naming for none dfa flags - group dump and control flags into a structure so they can be passed together. Signed-off-by: John Johansen --- parser/Makefile | 3 +- parser/af_unix.cc | 17 ++--- parser/common_flags.h | 31 +++++++++ parser/common_optarg.c | 100 +++++++++++++++------------- parser/common_optarg.h | 18 +++-- parser/dbus.cc | 6 +- parser/io_uring.cc | 4 +- parser/libapparmor_re/aare_rules.cc | 74 ++++++++++---------- parser/libapparmor_re/aare_rules.h | 9 +-- parser/libapparmor_re/apparmor_re.h | 65 +++++++++--------- parser/libapparmor_re/chfa.cc | 15 +++-- parser/libapparmor_re/chfa.h | 2 +- parser/libapparmor_re/expr-tree.cc | 12 ++-- parser/libapparmor_re/expr-tree.h | 2 +- parser/libapparmor_re/hfa.cc | 54 +++++++-------- parser/libapparmor_re/hfa.h | 12 ++-- parser/mount.cc | 18 ++--- parser/mqueue.cc | 8 +-- parser/parser.h | 6 +- parser/parser_common.c | 9 +-- parser/parser_main.c | 32 ++++----- parser/parser_regex.c | 58 ++++++++-------- parser/ptrace.cc | 2 +- parser/signal.cc | 2 +- parser/userns.cc | 2 +- 25 files changed, 303 insertions(+), 258 deletions(-) create mode 100644 parser/common_flags.h diff --git a/parser/Makefile b/parser/Makefile index 3280ce528..d112e0307 100644 --- a/parser/Makefile +++ b/parser/Makefile @@ -106,7 +106,8 @@ SRCS = parser_common.c parser_include.c parser_interface.c parser_lex.c \ STATIC_HDRS = af_rule.h af_unix.h capability.h common_optarg.h dbus.h \ file_cache.h immunix.h lib.h mount.h network.h parser.h \ parser_include.h parser_version.h policy_cache.h policydb.h \ - profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h + profile.h ptrace.h rule.h signal.h userns.h mqueue.h io_uring.h \ + common_flags.h SPECIAL_HDRS = parser_yacc.h unit_test.h base_cap_names.h GENERATED_HDRS = af_names.h generated_af_names.h \ diff --git a/parser/af_unix.cc b/parser/af_unix.cc index dfd7f427e..117688692 100644 --- a/parser/af_unix.cc +++ b/parser/af_unix.cc @@ -24,6 +24,7 @@ #include #include +#include "common_optarg.h" #include "network.h" #include "parser.h" #include "profile.h" @@ -203,7 +204,7 @@ void unix_rule::downgrade_rule(Profile &prof) { * restrictive and may end up denying accesses that might be * allowed by the profile. */ - if (warnflags & WARN_RULE_NOT_ENFORCED) + if (parseopts.warn & WARN_RULE_NOT_ENFORCED) rule_t::warn_once(prof.name, "deny unix socket rule not enforced, can't be downgraded to generic network rule\n"); } } @@ -321,7 +322,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (features_supports_network || features_supports_networkv8) { /* only warn if we are building against a kernel * that requires downgrading */ - if (warnflags & WARN_RULE_DOWNGRADED) + if (parseopts.warn & WARN_RULE_DOWNGRADED) rule_t::warn_once(prof.name, "downgrading extended network unix socket rule to generic network rule\n"); /* TODO: add ability to abort instead of downgrade */ return RULE_OK; @@ -337,7 +338,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_NET_CREATE), map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0), - dfaflags)) + parseopts)) goto fail; mask &= ~AA_NET_CREATE; } @@ -362,7 +363,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_NET_BIND), map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0), - dfaflags)) + parseopts)) goto fail; /* clear if auto, else generic need to generate addr below */ if (addr) @@ -387,7 +388,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(mask & local_mask), map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0), - dfaflags)) + parseopts)) goto fail; } @@ -401,7 +402,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_NET_LISTEN), map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0), - dfaflags)) + parseopts)) goto fail; } if ((mask & AA_NET_OPT) && !has_peer_conds()) { @@ -414,7 +415,7 @@ int unix_rule::gen_policy_re(Profile &prof) if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(AA_NET_OPT), map_perms(audit == AUDIT_FORCE ? AA_NET_OPT : 0), - dfaflags)) + parseopts)) goto fail; } mask &= ~AA_LOCAL_NET_PERMS | AA_NET_ACCEPT; @@ -432,7 +433,7 @@ int unix_rule::gen_policy_re(Profile &prof) goto fail; buf = buffer.str(); - if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), dfaflags)) + if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts)) goto fail; } diff --git a/parser/common_flags.h b/parser/common_flags.h new file mode 100644 index 000000000..116bfc274 --- /dev/null +++ b/parser/common_flags.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 + * 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_COMMON_FLAGS_H +#define __AA_COMMON_FLAGS_H + +typedef int optflags_t; + +typedef struct optflags { + optflags_t dfaflags; + optflags_t dfadump; + optflags_t warn; + optflags_t Werror; +} optflags; + +#endif /* __AA_COMMON_FLAGS_H */ diff --git a/parser/common_optarg.c b/parser/common_optarg.c index bd77b0b1b..c27f0205a 100644 --- a/parser/common_optarg.c +++ b/parser/common_optarg.c @@ -27,82 +27,90 @@ #include "common_optarg.h" #include "parser.h" -optflag_table_t dumpflag_table[] = { +optflag_table_t dfadumpflag_table[] = { { 1, "rule-exprs", "Dump rule to expr tree conversions", - DFA_DUMP_RULE_EXPR }, - { 1, "expr-stats", "Dump stats on expr tree", DFA_DUMP_TREE_STATS }, - { 1, "expr-tree", "Dump expression tree", DFA_DUMP_TREE }, + DUMP_DFA_RULE_EXPR }, + { 1, "expr-stats", "Dump stats on expr tree", DUMP_DFA_TREE_STATS }, + { 1, "expr-tree", "Dump expression tree", DUMP_DFA_TREE }, { 1, "expr-simplified", "Dump simplified expression tree", - DFA_DUMP_SIMPLE_TREE }, + DUMP_DFA_SIMPLE_TREE }, { 1, "stats", "Dump all compile stats", - DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS | - DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS }, + DUMP_DFA_TREE_STATS | DUMP_DFA_STATS | DUMP_DFA_TRANS_STATS | + DUMP_DFA_EQUIV_STATS | DUMP_DFA_DIFF_STATS }, { 1, "progress", "Dump progress for all compile phases", - DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS | - DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS }, + DUMP_DFA_PROGRESS | DUMP_DFA_STATS | DUMP_DFA_TRANS_PROGRESS | + DUMP_DFA_TRANS_STATS | DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS }, { 1, "dfa-progress", "Dump dfa creation as in progress", - DFA_DUMP_PROGRESS | DFA_DUMP_STATS }, - { 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS }, - { 1, "dfa-states", "Dump dfa state diagram", DFA_DUMP_STATES }, - { 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DFA_DUMP_GRAPH }, - { 1, "dfa-minimize", "Dump dfa minimization", DFA_DUMP_MINIMIZE }, + DUMP_DFA_PROGRESS | DUMP_DFA_STATS }, + { 1, "dfa-stats", "Dump dfa creation stats", DUMP_DFA_STATS }, + { 1, "dfa-states", "Dump dfa state diagram", DUMP_DFA_STATES }, + { 1, "dfa-graph", "Dump dfa dot (graphviz) graph", DUMP_DFA_GRAPH }, + { 1, "dfa-minimize", "Dump dfa minimization", DUMP_DFA_MINIMIZE }, { 1, "dfa-unreachable", "Dump dfa unreachable states", - DFA_DUMP_UNREACHABLE }, + DUMP_DFA_UNREACHABLE }, { 1, "dfa-node-map", "Dump expr node set to state mapping", - DFA_DUMP_NODE_TO_DFA }, + DUMP_DFA_NODE_TO_DFA }, { 1, "dfa-uniq-perms", "Dump unique perms", - DFA_DUMP_UNIQ_PERMS }, + DUMP_DFA_UNIQ_PERMS }, { 1, "dfa-minimize-uniq-perms", "Dump unique perms post minimization", - DFA_DUMP_MIN_UNIQ_PERMS }, + DUMP_DFA_MIN_UNIQ_PERMS }, { 1, "dfa-minimize-partitions", "Dump dfa minimization partitions", - DFA_DUMP_MIN_PARTS }, + DUMP_DFA_MIN_PARTS }, { 1, "compress-progress", "Dump progress of compression", - DFA_DUMP_TRANS_PROGRESS | DFA_DUMP_TRANS_STATS }, + DUMP_DFA_TRANS_PROGRESS | DUMP_DFA_TRANS_STATS }, { 1, "compress-stats", "Dump stats on compression", - DFA_DUMP_TRANS_STATS }, - { 1, "compressed-dfa", "Dump compressed dfa", DFA_DUMP_TRANS_TABLE }, + DUMP_DFA_TRANS_STATS }, + { 1, "compressed-dfa", "Dump compressed dfa", DUMP_DFA_TRANS_TABLE }, { 1, "equiv-stats", "Dump equivalence class stats", - DFA_DUMP_EQUIV_STATS }, - { 1, "equiv", "Dump equivalence class", DFA_DUMP_EQUIV }, + DUMP_DFA_EQUIV_STATS }, + { 1, "equiv", "Dump equivalence class", DUMP_DFA_EQUIV }, { 1, "diff-encode", "Dump differential encoding", - DFA_DUMP_DIFF_ENCODE }, + DUMP_DFA_DIFF_ENCODE }, { 1, "diff-stats", "Dump differential encoding stats", - DFA_DUMP_DIFF_STATS }, + DUMP_DFA_DIFF_STATS }, { 1, "diff-progress", "Dump progress of differential encoding", - DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS }, + DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS }, { 0, NULL, NULL, 0 }, }; -optflag_table_t optflag_table[] = { +optflag_table_t dfaoptflag_table[] = { { 2, "0", "no optimizations", - DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | - DFA_CONTROL_MINIMIZE | DFA_CONTROL_REMOVE_UNREACHABLE | - DFA_CONTROL_DIFF_ENCODE + CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | + CONTROL_DFA_MINIMIZE | CONTROL_DFA_REMOVE_UNREACHABLE | + CONTROL_DFA_DIFF_ENCODE }, - { 1, "equiv", "use equivalent classes", DFA_CONTROL_EQUIV }, + { 1, "equiv", "use equivalent classes", CONTROL_DFA_EQUIV }, { 1, "expr-normalize", "expression tree normalization", - DFA_CONTROL_TREE_NORMAL }, + CONTROL_DFA_TREE_NORMAL }, { 1, "expr-simplify", "expression tree simplification", - DFA_CONTROL_TREE_SIMPLE }, + CONTROL_DFA_TREE_SIMPLE }, { 0, "expr-left-simplify", "left simplification first", - DFA_CONTROL_TREE_LEFT }, + CONTROL_DFA_TREE_LEFT }, { 2, "expr-right-simplify", "right simplification first", - DFA_CONTROL_TREE_LEFT }, - { 1, "minimize", "dfa state minimization", DFA_CONTROL_MINIMIZE }, + CONTROL_DFA_TREE_LEFT }, + { 1, "minimize", "dfa state minimization", CONTROL_DFA_MINIMIZE }, { 1, "filter-deny", "filter out deny information from final dfa", - DFA_CONTROL_FILTER_DENY }, + CONTROL_DFA_FILTER_DENY }, { 1, "remove-unreachable", "dfa unreachable state removal", - DFA_CONTROL_REMOVE_UNREACHABLE }, + CONTROL_DFA_REMOVE_UNREACHABLE }, { 0, "compress-small", "do slower dfa transition table compression", - DFA_CONTROL_TRANS_HIGH }, + CONTROL_DFA_TRANS_HIGH }, { 2, "compress-fast", "do faster dfa transition table compression", - DFA_CONTROL_TRANS_HIGH }, + CONTROL_DFA_TRANS_HIGH }, { 1, "diff-encode", "Differentially encode transitions", - DFA_CONTROL_DIFF_ENCODE }, + CONTROL_DFA_DIFF_ENCODE }, { 0, NULL, NULL, 0 }, }; +optflags parseopts = { + .dfaflags = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE), + .dfadump = 0, + .warn = DEFAULT_WARNINGS, + .Werror = 0 +}; + + void print_flag_table(optflag_table_t *table) { int i; @@ -114,12 +122,14 @@ void print_flag_table(optflag_table_t *table) printf("%-*s \t%s\n", longest, " show", "show flags that have been set and exit"); for (i = 0; table[i].option; i++) { - printf("%5s%-*s \t%s\n", (table[i].control & 1) ? "[no-]" : "", + printf("%5s%-*s \t%s\n", + (table[i].control & OPT_FLAG_CONTROL_PREFIX_NO) ? "[no-]" : "", longest, table[i].option, table[i].desc); } } -void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags) +void print_flags(const char *prefix, optflag_table_t *table, + optflags_t flags) { int i, count = 0; @@ -137,7 +147,7 @@ void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags) } int handle_flag_table(optflag_table_t *table, const char *optarg, - dfaflags_t *flags) + optflags_t *flags) { const char *arg = optarg; int i, invert = 0; diff --git a/parser/common_optarg.h b/parser/common_optarg.h index d10e70109..4b0a16dbf 100644 --- a/parser/common_optarg.h +++ b/parser/common_optarg.h @@ -21,25 +21,33 @@ #ifndef __AA_COMMON_OPTARG_H #define __AA_COMMON_OPTARG_H +#include "common_flags.h" #include "libapparmor_re/apparmor_re.h" + /* * flag: 1 - allow no- inversion * flag: 2 - flags specified should be masked off */ +#define OPT_FLAG_CONTROL_PREFIX_NO 1 +#define OPT_FLAG_CONTROL_MASK 2 typedef struct { int control; const char *option; const char *desc; - dfaflags_t flags; + optflags_t flags; } optflag_table_t; -extern optflag_table_t dumpflag_table[]; -extern optflag_table_t optflag_table[]; +extern optflag_table_t dfadumpflag_table[]; +extern optflag_table_t dfaoptflag_table[]; -void print_flags(const char *prefix, optflag_table_t *table, dfaflags_t flags); +extern optflags parseopts; + + +void print_flags(const char *prefix, optflag_table_t *table, + optflags_t flags); int handle_flag_table(optflag_table_t *table, const char *optarg, - dfaflags_t *flags); + optflags_t *flags); void flagtable_help(const char *name, const char *header, const char *command, optflag_table_t *table); diff --git a/parser/dbus.cc b/parser/dbus.cc index 8c0b8dbee..0371f66c1 100644 --- a/parser/dbus.cc +++ b/parser/dbus.cc @@ -276,21 +276,21 @@ int dbus_rule::gen_policy_re(Profile &prof) if (perms & AA_DBUS_BIND) { if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_BIND, audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0, - 2, vec, dfaflags, false)) + 2, vec, parseopts, false)) goto fail; } if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) { if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE), audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0, - 6, vec, dfaflags, false)) + 6, vec, parseopts, false)) goto fail; } if (perms & AA_DBUS_EAVESDROP) { if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms & AA_DBUS_EAVESDROP, audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0, - 1, vec, dfaflags, false)) + 1, vec, parseopts, false)) goto fail; } diff --git a/parser/io_uring.cc b/parser/io_uring.cc index aef4b8899..3c2f88555 100644 --- a/parser/io_uring.cc +++ b/parser/io_uring.cc @@ -123,14 +123,14 @@ int io_uring_rule::gen_policy_re(Profile &prof) if (perms & AA_VALID_IO_URING_PERMS) { if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - dfaflags)) + parseopts)) goto fail; if (perms & AA_IO_URING_OVERRIDE_CREDS) { buf = buffer.str(); /* update buf to have label */ if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - dfaflags)) + parseopts)) goto fail; } diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index b250e1013..9c146363c 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -45,9 +45,9 @@ aare_rules::~aare_rules(void) } bool aare_rules::add_rule(const char *rule, int deny, uint32_t perms, - uint32_t audit, dfaflags_t flags) + uint32_t audit, optflags const &opts) { - return add_rule_vec(deny, perms, audit, 1, &rule, flags, false); + return add_rule_vec(deny, perms, audit, 1, &rule, opts, false); } void aare_rules::add_to_rules(Node *tree, Node *perms) @@ -72,7 +72,7 @@ static Node *cat_with_oob_separator(Node *l, Node *r) } bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, - int count, const char **rulev, dfaflags_t flags, + int count, const char **rulev, optflags const &opts, bool oob) { Node *tree = NULL, *accept; @@ -110,7 +110,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, accept = unique_perms.insert(deny, perms, audit, exact_match); - if (flags & DFA_DUMP_RULE_EXPR) { + if (opts.dfadump & DUMP_DFA_RULE_EXPR) { const char *separator; if (oob) separator = "\\-x01"; @@ -152,13 +152,13 @@ err: * advanced by a null character for each xattr. */ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, - dfaflags_t flags) + optflags const &opts) { Node *tree = NULL; if (regex_parse(&tree, rule)) return false; - if (flags & DFA_DUMP_RULE_EXPR) { + if (opts.dfadump & DUMP_DFA_RULE_EXPR) { cerr << "rule: "; cerr << rule; cerr << " -> "; @@ -195,7 +195,7 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, * else NULL on failure, @min_match_len set to the shortest string * that can match the dfa for determining xmatch priority. */ -void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, +void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &opts, bool filedfa) { char *buffer = NULL; @@ -204,15 +204,15 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, * set nodes */ PermExprMap::iterator i = expr_map.begin(); if (i != expr_map.end()) { - if (flags & DFA_CONTROL_TREE_SIMPLE) { - Node *tmp = simplify_tree(i->second, flags); + if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { + Node *tmp = simplify_tree(i->second, opts); root = new CatNode(tmp, i->first); } else root = new CatNode(i->second, i->first); for (i++; i != expr_map.end(); i++) { Node *tmp; - if (flags & DFA_CONTROL_TREE_SIMPLE) { - tmp = simplify_tree(i->second, flags); + if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { + tmp = simplify_tree(i->second, opts); } else tmp = i->second; root = new AltNode(root, new CatNode(tmp, i->first)); @@ -226,22 +226,22 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, * this debug dump. */ label_nodes(root); - if (flags & DFA_DUMP_TREE) { + if (opts.dfadump & DUMP_DFA_TREE) { cerr << "\nDFA: Expression Tree\n"; root->dump(cerr); cerr << "\n\n"; } - if (flags & DFA_CONTROL_TREE_SIMPLE) { + if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { /* This is old total tree, simplification point * For now just do simplification up front. It gets most * of the benefit running on the smaller chains, and is * overall faster because there are less nodes. Reevaluate * once tree simplification is rewritten */ - //root = simplify_tree(root, flags); + //root = simplify_tree(root, opts); - if (flags & DFA_DUMP_SIMPLE_TREE) { + if (opts.dfadump & DUMP_DFA_SIMPLE_TREE) { cerr << "\nDFA: Simplified Expression Tree\n"; root->dump(cerr); cerr << "\n\n"; @@ -250,19 +250,19 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, stringstream stream; try { - DFA dfa(root, flags, filedfa); - if (flags & DFA_DUMP_UNIQ_PERMS) + DFA dfa(root, opts, filedfa); + if (opts.dfadump & DUMP_DFA_UNIQ_PERMS) dfa.dump_uniq_perms("dfa"); - if (flags & DFA_CONTROL_MINIMIZE) { - dfa.minimize(flags); + if (opts.dfaflags & CONTROL_DFA_MINIMIZE) { + dfa.minimize(opts); - if (flags & DFA_DUMP_MIN_UNIQ_PERMS) + if (opts.dfadump & DUMP_DFA_MIN_UNIQ_PERMS) dfa.dump_uniq_perms("minimized dfa"); } - if (flags & DFA_CONTROL_FILTER_DENY && - flags & DFA_CONTROL_MINIMIZE && + if (opts.dfaflags & CONTROL_DFA_FILTER_DENY && + opts.dfaflags & CONTROL_DFA_MINIMIZE && dfa.apply_and_clear_deny()) { /* Do a second minimization pass as removal of deny * information has moved some states from accepting @@ -271,42 +271,42 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, * TODO: add this as a tail pass to minimization * so we don't need to do a full second pass */ - dfa.minimize(flags); + dfa.minimize(opts); - if (flags & DFA_DUMP_MIN_UNIQ_PERMS) + if (opts.dfadump & DUMP_DFA_MIN_UNIQ_PERMS) dfa.dump_uniq_perms("minimized dfa"); } - if (flags & DFA_CONTROL_REMOVE_UNREACHABLE) - dfa.remove_unreachable(flags); + if (opts.dfaflags & CONTROL_DFA_REMOVE_UNREACHABLE) + dfa.remove_unreachable(opts); - if (flags & DFA_DUMP_STATES) + if (opts.dfadump & DUMP_DFA_STATES) dfa.dump(cerr); - if (flags & DFA_DUMP_GRAPH) + if (opts.dfadump & DUMP_DFA_GRAPH) dfa.dump_dot_graph(cerr); map eq; - if (flags & DFA_CONTROL_EQUIV) { - eq = dfa.equivalence_classes(flags); + if (opts.dfaflags & CONTROL_DFA_EQUIV) { + eq = dfa.equivalence_classes(opts); dfa.apply_equivalence_classes(eq); - if (flags & DFA_DUMP_EQUIV) { + if (opts.dfadump & DUMP_DFA_EQUIV) { cerr << "\nDFA equivalence class\n"; dump_equivalence_classes(cerr, eq); } - } else if (flags & DFA_DUMP_EQUIV) + } else if (opts.dfadump & DUMP_DFA_EQUIV) cerr << "\nDFA did not generate an equivalence class\n"; - if (flags & DFA_CONTROL_DIFF_ENCODE) { - dfa.diff_encode(flags); + if (opts.dfaflags & CONTROL_DFA_DIFF_ENCODE) { + dfa.diff_encode(opts); - if (flags & DFA_DUMP_DIFF_ENCODE) + if (opts.dfadump & DUMP_DFA_DIFF_ENCODE) dfa.dump_diff_encode(cerr); } - CHFA chfa(dfa, eq, flags); - if (flags & DFA_DUMP_TRANS_TABLE) + CHFA chfa(dfa, eq, opts); + if (opts.dfadump & DUMP_DFA_TRANS_TABLE) chfa.dump(cerr); chfa.flex_table(stream, ""); } diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index ab88f0af0..71087b887 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -23,6 +23,7 @@ #include +#include "../common_optarg.h" #include "apparmor_re.h" #include "expr-tree.h" @@ -101,11 +102,11 @@ class aare_rules { ~aare_rules(); bool add_rule(const char *rule, int deny, uint32_t perms, - uint32_t audit, dfaflags_t flags); + uint32_t audit, optflags const &opts); bool add_rule_vec(int deny, uint32_t perms, uint32_t audit, int count, - const char **rulev, dfaflags_t flags, bool oob); - bool append_rule(const char *rule, bool oob, bool with_perm, dfaflags_t flags); - void *create_dfa(size_t *size, int *min_match_len, dfaflags_t flags, + const char **rulev, optflags const &opts, bool oob); + bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); + void *create_dfa(size_t *size, int *min_match_len, optflags const &opts, bool filedfa); }; diff --git a/parser/libapparmor_re/apparmor_re.h b/parser/libapparmor_re/apparmor_re.h index 8e9fd9984..eafb12203 100644 --- a/parser/libapparmor_re/apparmor_re.h +++ b/parser/libapparmor_re/apparmor_re.h @@ -19,40 +19,39 @@ #ifndef APPARMOR_RE_H #define APPARMOR_RE_H -typedef int dfaflags_t; +#include "../common_flags.h" +#define CONTROL_DFA_EQUIV (1 << 0) +#define CONTROL_DFA_TREE_NORMAL (1 << 1) +#define CONTROL_DFA_TREE_SIMPLE (1 << 2) +#define CONTROL_DFA_TREE_LEFT (1 << 3) +#define CONTROL_DFA_MINIMIZE (1 << 4) +#define CONTROL_DFA_FILTER_DENY (1 << 6) +#define CONTROL_DFA_REMOVE_UNREACHABLE (1 << 7) +#define CONTROL_DFA_TRANS_HIGH (1 << 8) +#define CONTROL_DFA_DIFF_ENCODE (1 << 9) -#define DFA_CONTROL_EQUIV (1 << 0) -#define DFA_CONTROL_TREE_NORMAL (1 << 1) -#define DFA_CONTROL_TREE_SIMPLE (1 << 2) -#define DFA_CONTROL_TREE_LEFT (1 << 3) -#define DFA_CONTROL_MINIMIZE (1 << 4) -#define DFA_CONTROL_FILTER_DENY (1 << 6) -#define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7) -#define DFA_CONTROL_TRANS_HIGH (1 << 8) -#define DFA_CONTROL_DIFF_ENCODE (1 << 9) - -#define DFA_DUMP_DIFF_PROGRESS (1 << 10) -#define DFA_DUMP_DIFF_ENCODE (1 << 11) -#define DFA_DUMP_DIFF_STATS (1 << 12) -#define DFA_DUMP_MIN_PARTS (1 << 13) -#define DFA_DUMP_UNIQ_PERMS (1 << 14) -#define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15) -#define DFA_DUMP_TREE_STATS (1 << 16) -#define DFA_DUMP_TREE (1 << 17) -#define DFA_DUMP_SIMPLE_TREE (1 << 18) -#define DFA_DUMP_PROGRESS (1 << 19) -#define DFA_DUMP_STATS (1 << 20) -#define DFA_DUMP_STATES (1 << 21) -#define DFA_DUMP_GRAPH (1 << 22) -#define DFA_DUMP_TRANS_PROGRESS (1 << 23) -#define DFA_DUMP_TRANS_STATS (1 << 24) -#define DFA_DUMP_TRANS_TABLE (1 << 25) -#define DFA_DUMP_EQUIV (1 << 26) -#define DFA_DUMP_EQUIV_STATS (1 << 27) -#define DFA_DUMP_MINIMIZE (1 << 28) -#define DFA_DUMP_UNREACHABLE (1 << 29) -#define DFA_DUMP_RULE_EXPR (1 << 30) -#define DFA_DUMP_NODE_TO_DFA (1 << 31) +#define DUMP_DFA_DIFF_PROGRESS (1 << 0) +#define DUMP_DFA_DIFF_ENCODE (1 << 1) +#define DUMP_DFA_DIFF_STATS (1 << 2) +#define DUMP_DFA_MIN_PARTS (1 << 3) +#define DUMP_DFA_UNIQ_PERMS (1 << 4) +#define DUMP_DFA_MIN_UNIQ_PERMS (1 << 5) +#define DUMP_DFA_TREE_STATS (1 << 6) +#define DUMP_DFA_TREE (1 << 7) +#define DUMP_DFA_SIMPLE_TREE (1 << 8) +#define DUMP_DFA_PROGRESS (1 << 9) +#define DUMP_DFA_STATS (1 << 10) +#define DUMP_DFA_STATES (1 << 11) +#define DUMP_DFA_GRAPH (1 << 12) +#define DUMP_DFA_TRANS_PROGRESS (1 << 13) +#define DUMP_DFA_TRANS_STATS (1 << 14) +#define DUMP_DFA_TRANS_TABLE (1 << 15) +#define DUMP_DFA_EQUIV (1 << 16) +#define DUMP_DFA_EQUIV_STATS (1 << 17) +#define DUMP_DFA_MINIMIZE (1 << 18) +#define DUMP_DFA_UNREACHABLE (1 << 19) +#define DUMP_DFA_RULE_EXPR (1 << 20) +#define DUMP_DFA_NODE_TO_DFA (1 << 21) #endif /* APPARMOR_RE_H */ diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index 235df335b..c31045866 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -49,9 +49,10 @@ void CHFA::init_free_list(vector > &free_list, /** * new Construct the transition table. */ -CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) +CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): + eq(eq) { - if (flags & DFA_DUMP_TRANS_PROGRESS) + if (opts.dfadump & DUMP_DFA_TRANS_PROGRESS) fprintf(stderr, "Compressing HFA:\r"); chfaflags = 0; @@ -82,7 +83,7 @@ CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) if (*i == dfa.start || *i == dfa.nonmatching) continue; optimal += (*i)->trans.size(); - if (flags & DFA_CONTROL_TRANS_HIGH) { + if (opts.dfaflags & CONTROL_DFA_TRANS_HIGH) { size_t range = 0; if ((*i)->trans.size()) range = @@ -116,7 +117,7 @@ CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) int count = 2; - if (!(flags & DFA_CONTROL_TRANS_HIGH)) { + if (!(opts.dfaflags & CONTROL_DFA_TRANS_HIGH)) { for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { if (*i != dfa.nonmatching && *i != dfa.start) { insert_state(free_list, *i, dfa); @@ -124,7 +125,7 @@ CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny); num.insert(make_pair(*i, num.size())); } - if (flags & (DFA_DUMP_TRANS_PROGRESS)) { + if (opts.dfadump & (DUMP_DFA_TRANS_PROGRESS)) { count++; if (count % 100 == 0) fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r", @@ -141,7 +142,7 @@ CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny); num.insert(make_pair(i->second, num.size())); } - if (flags & (DFA_DUMP_TRANS_PROGRESS)) { + if (opts.dfadump & (DUMP_DFA_TRANS_PROGRESS)) { count++; if (count % 100 == 0) fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r", @@ -150,7 +151,7 @@ CHFA::CHFA(DFA &dfa, map &eq, dfaflags_t flags): eq(eq) } } - if (flags & (DFA_DUMP_TRANS_STATS | DFA_DUMP_TRANS_PROGRESS)) { + if (opts.dfadump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) { ssize_t size = 4 * next_check.size() + 6 * dfa.states.size(); fprintf(stderr, "\033[2KCompressed trans table: states %zd, next/check %zd, optimal next/check %zd avg/state %.2f, compression %zd/%zd = %.2f %%\n", dfa.states.size(), next_check.size(), optimal, diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index d0081ae56..9548080b2 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -37,7 +37,7 @@ class CHFA { typedef vector > DefaultBase; typedef vector > NextCheck; public: - CHFA(DFA &dfa, map &eq, dfaflags_t flags); + CHFA(DFA &dfa, map &eq, optflags const &opts); void dump(ostream & os); void flex_table(ostream &os, const char *name); void init_free_list(vector > &free_list, diff --git a/parser/libapparmor_re/expr-tree.cc b/parser/libapparmor_re/expr-tree.cc index 7dc18b041..aa691db57 100644 --- a/parser/libapparmor_re/expr-tree.cc +++ b/parser/libapparmor_re/expr-tree.cc @@ -575,12 +575,12 @@ static void count_tree_nodes(Node *t, struct node_counts *counts) // simplification passes. Simplification may exit sooner if no changes // are made. #define MAX_PASSES 1 -Node *simplify_tree(Node *t, dfaflags_t flags) +Node *simplify_tree(Node *t, optflags const &opts) { bool update = true; int i; - if (flags & DFA_DUMP_TREE_STATS) { + if (opts.dfadump & DUMP_DFA_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; count_tree_nodes(t, &counts); fprintf(stderr, @@ -598,25 +598,25 @@ Node *simplify_tree(Node *t, dfaflags_t flags) // the dfa having about 7 thousands states, // and it having about 1.25 million states int dir = 1; - if (flags & DFA_CONTROL_TREE_LEFT) + if (opts.dfaflags & CONTROL_DFA_TREE_LEFT) dir = 0; for (int count = 0; count < 2; count++) { bool modified; do { modified = false; - if (flags & DFA_CONTROL_TREE_NORMAL) + if (opts.dfaflags & CONTROL_DFA_TREE_NORMAL) t->normalize(dir); t = simplify_tree_base(t, dir, modified); if (modified) update = true; } while (modified); - if (flags & DFA_CONTROL_TREE_LEFT) + if (opts.dfaflags & CONTROL_DFA_TREE_LEFT) dir++; else dir--; } } - if (flags & DFA_DUMP_TREE_STATS) { + if (opts.dfadump & DUMP_DFA_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; count_tree_nodes(t, &counts); fprintf(stderr, diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 3530eb167..2aec980d9 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -958,7 +958,7 @@ struct node_counts { extern EpsNode epsnode; int debug_tree(Node *t); -Node *simplify_tree(Node *t, dfaflags_t flags); +Node *simplify_tree(Node *t, optflags const &opts); void label_nodes(Node *root); unsigned long hash_NodeSet(NodeSet *ns); void flip_tree(Node *node); diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index e1ef1803b..e8c31ab91 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -391,12 +391,12 @@ void DFA::dump_node_to_dfa(void) cerr << " " << (*i)->label << " <= " << (*i)->proto << "\n"; } -void DFA::process_work_queue(const char *header, dfaflags_t flags) +void DFA::process_work_queue(const char *header, optflags const &opts) { int i = 0; while (!work_queue.empty()) { - if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) { + if (i % 1000 == 0 && (opts.dfadump & DUMP_DFA_PROGRESS)) { cerr << "\033[2K" << header << ": queue " << work_queue.size() << "\tstates " @@ -420,7 +420,7 @@ void DFA::process_work_queue(const char *header, dfaflags_t flags) /** * Construct a DFA from a syntax tree. */ -DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(buildfiledfa) +DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filedfa(buildfiledfa) { diffcount = 0; /* set by diff_encode */ max_range = 256; @@ -428,7 +428,7 @@ DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(b oob_range = 0; ord_range = 8; - if (flags & DFA_DUMP_PROGRESS) + if (opts.dfadump & DUMP_DFA_PROGRESS) fprintf(stderr, "Creating dfa:\r"); for (depth_first_traversal i(root); i; i++) { @@ -437,7 +437,7 @@ DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(b (*i)->compute_lastpos(); } - if (flags & DFA_DUMP_PROGRESS) + if (opts.dfadump & DUMP_DFA_PROGRESS) fprintf(stderr, "Creating dfa: followpos\r"); for (depth_first_traversal i(root); i; i++) { (*i)->compute_followpos(); @@ -457,7 +457,7 @@ DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(b * work_queue at any given time, thus reducing peak memory use. */ work_queue.push_back(start); - process_work_queue("Creating dfa", flags); + process_work_queue("Creating dfa", opts); max_range += oob_range; /* if oob_range is ever greater than 256 need to move to computing this */ if (oob_range) @@ -471,10 +471,10 @@ DFA::DFA(Node *root, dfaflags_t flags, bool buildfiledfa): root(root), filedfa(b (*i)->followpos.clear(); } - if (flags & DFA_DUMP_NODE_TO_DFA) + if (opts.dfadump & DUMP_DFA_NODE_TO_DFA) dump_node_to_dfa(); - if (flags & (DFA_DUMP_STATS)) { + if (opts.dfadump & (DUMP_DFA_STATS)) { cerr << "\033[2KCreated dfa: states " << states.size() << " proto { " @@ -540,7 +540,7 @@ void DFA::dump_uniq_perms(const char *s) } /* Remove dead or unreachable states */ -void DFA::remove_unreachable(dfaflags_t flags) +void DFA::remove_unreachable(optflags const &opts) { set reachable; @@ -571,7 +571,7 @@ void DFA::remove_unreachable(dfaflags_t flags) next = i; next++; if (reachable.find(*i) == reachable.end()) { - if (flags & DFA_DUMP_UNREACHABLE) { + if (opts.dfadump & DUMP_DFA_UNREACHABLE) { cerr << "unreachable: " << **i; if (*i == start) cerr << " <=="; @@ -586,7 +586,7 @@ void DFA::remove_unreachable(dfaflags_t flags) } } - if (count && (flags & DFA_DUMP_STATS)) + if (count && (opts.dfadump & DUMP_DFA_STATS)) cerr << "DFA: states " << states.size() << " removed " << count << " unreachable states\n"; } @@ -645,7 +645,7 @@ int DFA::apply_and_clear_deny(void) } /* minimize the number of dfa states */ -void DFA::minimize(dfaflags_t flags) +void DFA::minimize(optflags const &opts) { map, Partition *> perm_map; list partitions; @@ -680,7 +680,7 @@ void DFA::minimize(dfaflags_t flags) p->second->push_back(*i); } - if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 1000 == 0)) + if ((opts.dfadump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0)) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << partitions.size() << " (accept " << accept_count << ")\r"; @@ -692,7 +692,7 @@ void DFA::minimize(dfaflags_t flags) perm_map.clear(); int init_count = partitions.size(); - if (flags & DFA_DUMP_PROGRESS) + if (opts.dfadump & DUMP_DFA_PROGRESS) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\r"; @@ -734,7 +734,7 @@ void DFA::minimize(dfaflags_t flags) (*m)->partition = new_part; } } - if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 100 == 0)) + if ((opts.dfadump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0)) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " @@ -743,7 +743,7 @@ void DFA::minimize(dfaflags_t flags) } while (new_part_count); if (partitions.size() == states.size()) { - if (flags & DFA_DUMP_STATS) + if (opts.dfadump & DUMP_DFA_STATS) cerr << "\033[2KDfa minimization no states removed: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\n"; @@ -757,13 +757,13 @@ void DFA::minimize(dfaflags_t flags) * to states within the same partitions, however this can slow * down compressed dfa compression as there are more states, */ - if (flags & DFA_DUMP_MIN_PARTS) + if (opts.dfadump & DUMP_DFA_MIN_PARTS) cerr << "Partitions after minimization\n"; for (list::iterator p = partitions.begin(); p != partitions.end(); p++) { /* representative state for this partition */ State *rep = *((*p)->begin()); - if (flags & DFA_DUMP_MIN_PARTS) + if (opts.dfadump & DUMP_DFA_MIN_PARTS) cerr << *rep << " : "; /* update representative state's transitions */ @@ -782,17 +782,17 @@ void DFA::minimize(dfaflags_t flags) /* clear the state label for all non representative states, * and accumulate permissions */ for (Partition::iterator i = ++(*p)->begin(); i != (*p)->end(); i++) { - if (flags & DFA_DUMP_MIN_PARTS) + if (opts.dfadump & DUMP_DFA_MIN_PARTS) cerr << **i << ", "; (*i)->label = -1; rep->perms.add((*i)->perms, filedfa); } if (rep->perms.is_accept()) final_accept++; - if (flags & DFA_DUMP_MIN_PARTS) + if (opts.dfadump & DUMP_DFA_MIN_PARTS) cerr << "\n"; } - if (flags & DFA_DUMP_STATS) + if (opts.dfadump & DUMP_DFA_STATS) cerr << "\033[2KMinimized dfa: final partitions " << partitions.size() << " (accept " << final_accept << ")" << "\tinit " << init_count << " (accept " @@ -875,7 +875,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe /** * diff_encode - compress dfa by differentially encoding state transitions - * @dfa_flags: flags controlling dfa creation + * @opts: flags controlling dfa creation * * This function reduces the number of transitions that need to be stored * by encoding transitions as the difference between the state and a @@ -910,7 +910,7 @@ static int diff_partition(State *state, Partition &part, int max_range, int uppe * the state transition at most will only move 1 deeper into the DAG so for * the next state the maximum number of states traversed is 2*7. */ -void DFA::diff_encode(dfaflags_t flags) +void DFA::diff_encode(optflags const &opts) { DiffDag *dag; unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0; @@ -965,7 +965,7 @@ void DFA::diff_encode(dfaflags_t flags) } } - if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0)) + if ((opts.dfadump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0)) cerr << "\033[2KDiff Encode: " << i << " of " << tail << ". Diff states " << xcount << " Savings " << xweight << "\r"; @@ -992,7 +992,7 @@ void DFA::diff_encode(dfaflags_t flags) } } - if (flags & DFA_DUMP_DIFF_STATS) + if (opts.dfadump & DUMP_DFA_DIFF_STATS) cerr << "Diff encode states: " << diffcount << " of " << tail << " reached @ depth " << depth << ". " << aweight << " trans removed\n"; @@ -1194,7 +1194,7 @@ void DFA::dump_dot_graph(ostream & os) * Compute character equivalence classes in the DFA to save space in the * transition table. */ -map DFA::equivalence_classes(dfaflags_t flags) +map DFA::equivalence_classes(optflags const &opts) { map classes; transchar next_class = 1; @@ -1251,7 +1251,7 @@ map DFA::equivalence_classes(dfaflags_t flags) } } - if (flags & DFA_DUMP_EQUIV_STATS) + if (opts.dfadump & DUMP_DFA_EQUIV_STATS) fprintf(stderr, "Equiv class reduces to %d classes\n", next_class.c - 1); return classes; diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 451d74659..738efc076 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -305,7 +305,7 @@ class DFA { State *add_new_state(NodeSet *nodes, State *other); State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other); void update_state_transitions(State *state); - void process_work_queue(const char *header, dfaflags_t); + void process_work_queue(const char *header, optflags const &); void dump_diff_chain(ostream &os, map &relmap, Partition &chain, State *state, unsigned int &count, unsigned int &total, @@ -318,19 +318,19 @@ class DFA { list work_queue; public: - DFA(Node *root, dfaflags_t flags, bool filedfa); + DFA(Node *root, optflags const &flags, bool filedfa); virtual ~DFA(); State *match_len(State *state, const char *str, size_t len); State *match_until(State *state, const char *str, const char term); State *match(const char *str); - void remove_unreachable(dfaflags_t flags); + void remove_unreachable(optflags const &flags); bool same_mappings(State *s1, State *s2); - void minimize(dfaflags_t flags); + void minimize(optflags const &flags); int apply_and_clear_deny(void); - void diff_encode(dfaflags_t flags); + void diff_encode(optflags const &flags); void undiff_encode(void); void dump_diff_encode(ostream &os); @@ -338,7 +338,7 @@ public: void dump_dot_graph(ostream &os); void dump_uniq_perms(const char *s); - map equivalence_classes(dfaflags_t flags); + map equivalence_classes(optflags const &flags); void apply_equivalence_classes(map &eq); unsigned int diffcount; diff --git a/parser/mount.cc b/parser/mount.cc index 043864078..f61bf3435 100644 --- a/parser/mount.cc +++ b/parser/mount.cc @@ -798,7 +798,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count, * else it has full perms */ if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4, - vec, dfaflags, false)) + vec, parseopts, false)) goto fail; count++; @@ -810,7 +810,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count, vec[4] = optsbuf.c_str(); if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, (audit == AUDIT_FORCE ? perms : 0), - 5, vec, dfaflags, false)) + 5, vec, parseopts, false)) goto fail; count++; } @@ -852,7 +852,7 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count, vec[3] = flagsbuf; if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, - dfaflags, false)) + parseopts, false)) goto fail; count++; @@ -909,7 +909,7 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count, vec[3] = flagsbuf; if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, - dfaflags, false)) + parseopts, false)) goto fail; count++; @@ -952,7 +952,7 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count, vec[3] = flagsbuf; if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 4, vec, - dfaflags, false)) + parseopts, false)) goto fail; count++; @@ -1003,7 +1003,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count, } /* rule for match without required data || data MATCH_CONT */ if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, tmpperms, tmpaudit, 4, - vec, dfaflags, false)) + vec, parseopts, false)) goto fail; count++; @@ -1015,7 +1015,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count, vec[4] = optsbuf.c_str(); if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - 5, vec, dfaflags, false)) + 5, vec, parseopts, false)) goto fail; count++; } @@ -1107,7 +1107,7 @@ int mnt_rule::gen_policy_re(Profile &prof) vec[0] = mntbuf.c_str(); if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, (audit == AUDIT_FORCE ? perms : 0), 1, vec, - dfaflags, false)) + parseopts, false)) goto fail; count++; } @@ -1122,7 +1122,7 @@ int mnt_rule::gen_policy_re(Profile &prof) vec[1] = devbuf.c_str(); if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, (audit == AUDIT_FORCE ? perms : 0), 2, vec, - dfaflags, false)) + parseopts, false)) goto fail; count++; } diff --git a/parser/mqueue.cc b/parser/mqueue.cc index 86ab193ae..86c7c1d06 100644 --- a/parser/mqueue.cc +++ b/parser/mqueue.cc @@ -231,10 +231,10 @@ int mqueue_rule::gen_policy_re(Profile &prof) /* store perms at name match so label doesn't need * to be checked */ - if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, dfaflags, false)) + if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false)) goto fail; /* also provide label match with perm */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, dfaflags, false)) + if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false)) goto fail; } } @@ -266,10 +266,10 @@ int mqueue_rule::gen_policy_re(Profile &prof) } if (perms & AA_VALID_SYSV_MQ_PERMS) { - if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, dfaflags, false)) + if (!label && !prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, 1, vec, parseopts, false)) goto fail; /* also provide label match with perm */ - if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, dfaflags, false)) + if (!prof.policy.rules->add_rule_vec(rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, size, vec, parseopts, false)) goto fail; } } diff --git a/parser/parser.h b/parser/parser.h index e5b785480..95b177060 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -82,9 +82,6 @@ extern int parser_token; WARN_UNEXPECTED | WARN_FORMAT | WARN_MISSING | \ WARN_OVERRIDE | WARN_INCLUDE) -extern dfaflags_t warnflags; -extern dfaflags_t werrflags; - typedef enum pattern_t pattern_t; @@ -362,7 +359,6 @@ extern int conf_quiet; extern int names_only; extern int option; extern int current_lineno; -extern dfaflags_t dfaflags; extern const char *progname; extern char *profilename; extern char *profile_ns; @@ -374,7 +370,7 @@ extern IncludeCache_t *g_includecache; extern void pwarnf(bool werr, const char *fmt, ...) __attribute__((__format__(__printf__, 2, 3))); extern void common_warn_once(const char *name, const char *msg, const char **warned_name); -#define pwarn(F, args...) do { if (warnflags & (F)) pwarnf((werrflags & (F)), ## args); } while (0) +#define pwarn(F, args...) do { if (parseopts.warn & (F)) pwarnf((parseopts.Werror & (F)), ## args); } while (0) /* from parser_main (cannot be used in tst builds) */ extern int force_complain; diff --git a/parser/parser_common.c b/parser/parser_common.c index 75b637e19..2daa25967 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -89,9 +89,6 @@ int names_only = 0; int current_lineno = 1; int option = OPTION_ADD; -dfaflags_t dfaflags = (dfaflags_t)(DFA_CONTROL_TREE_NORMAL | DFA_CONTROL_TREE_SIMPLE | DFA_CONTROL_MINIMIZE | DFA_CONTROL_DIFF_ENCODE); -dfaflags_t warnflags = DEFAULT_WARNINGS; -dfaflags_t werrflags = 0; const char *progname = __FILE__; char *profile_ns = NULL; @@ -140,8 +137,8 @@ void pwarnf(bool werr, const char *fmt, ...) /* do we want to warn once/profile or just once per compile?? */ void common_warn_once(const char *name, const char *msg, const char **warned_name) { - if ((warnflags & WARN_RULE_NOT_ENFORCED) && *warned_name != name) { - if (werrflags & WARN_RULE_NOT_ENFORCED) + if ((parseopts.warn & WARN_RULE_NOT_ENFORCED) && *warned_name != name) { + if (parseopts.Werror & WARN_RULE_NOT_ENFORCED) cerr << "Warning converted to Error"; else cerr << "Warning"; @@ -154,6 +151,6 @@ void common_warn_once(const char *name, const char *msg, const char **warned_nam *warned_name = name; } - if (werrflags & WARN_RULE_NOT_ENFORCED) + if (parseopts.Werror & WARN_RULE_NOT_ENFORCED) exit(1); } diff --git a/parser/parser_main.c b/parser/parser_main.c index 00a8b52fb..080822da1 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -493,11 +493,11 @@ static int process_arg(int c, char *optarg) strcmp(optarg, "dump") == 0 || strcmp(optarg, "D") == 0) { flagtable_help("--dump=", DUMP_HEADER, progname, - dumpflag_table); + dfadumpflag_table); } else if (strcmp(optarg, "Optimize") == 0 || strcmp(optarg, "optimize") == 0 || strcmp(optarg, "O") == 0) { - flagtable_help("-O ", "", progname, optflag_table); + flagtable_help("-O ", "", progname, dfaoptflag_table); } else if (strcmp(optarg, "warn") == 0) { flagtable_help("--warn=", "", progname, warnflag_table); } else if (strcmp(optarg, "Werror") == 0) { @@ -568,13 +568,13 @@ static int process_arg(int c, char *optarg) if (!optarg) { dump_vars = 1; } else if (strcmp(optarg, "show") == 0) { - print_flags("dump", dumpflag_table, dfaflags); + print_flags("dump", dfadumpflag_table, parseopts.dfadump); } else if (strcmp(optarg, "variables") == 0) { dump_vars = 1; } else if (strcmp(optarg, "expanded-variables") == 0) { dump_expanded_vars = 1; - } else if (!handle_flag_table(dumpflag_table, optarg, - &dfaflags)) { + } else if (!handle_flag_table(dfadumpflag_table, optarg, + &parseopts.dfadump)) { PERROR("%s: Invalid --Dump option %s\n", progname, optarg); exit(1); @@ -582,9 +582,9 @@ static int process_arg(int c, char *optarg) break; case 'O': if (strcmp(optarg, "show") == 0) { - print_flags("Optimize", optflag_table, dfaflags); - } else if (!handle_flag_table(optflag_table, optarg, - &dfaflags)) { + print_flags("Optimize", dfaoptflag_table, parseopts.dfaflags); + } else if (!handle_flag_table(dfaoptflag_table, optarg, + &parseopts.dfaflags)) { PERROR("%s: Invalid --Optimize option %s\n", progname, optarg); exit(1); @@ -665,7 +665,7 @@ static int process_arg(int c, char *optarg) case 'q': conf_verbose = 0; conf_quiet = 1; - warnflags = 0; + parseopts.warn = 0; break; case 'v': conf_verbose = 1; @@ -723,9 +723,9 @@ static int process_arg(int c, char *optarg) break; case ARG_WARN: if (strcmp(optarg, "show") == 0) { - print_flags("warn", warnflag_table, warnflags); + print_flags("warn", warnflag_table, parseopts.warn); } else if (!handle_flag_table(warnflag_table, optarg, - &warnflags)) { + &parseopts.warn)) { PERROR("%s: Invalid --warn option %s\n", progname, optarg); exit(1); @@ -733,18 +733,18 @@ static int process_arg(int c, char *optarg) break; case ARG_WERROR: if (!optarg) { - werrflags = -1; + parseopts.Werror = -1; } else if (strcmp(optarg, "show") == 0) { - print_flags("Werror", warnflag_table, werrflags); + print_flags("Werror", warnflag_table, parseopts.Werror); } else if (optarg && !handle_flag_table(warnflag_table, optarg, - &werrflags)) { + &parseopts.Werror)) { PERROR("%s: Invalid --Werror option %s\n", progname, optarg); exit(1); } break; case ARG_DEBUG_CACHE: - warnflags |= WARN_DEBUG_CACHE; + parseopts.warn |= WARN_DEBUG_CACHE; break; case 'j': jobs = process_jobs_arg("-j", optarg); @@ -1530,7 +1530,7 @@ static bool get_kernel_features(struct aa_features **features) if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ - dfaflags &= ~DFA_CONTROL_DIFF_ENCODE; + parseopts.dfaflags &= ~CONTROL_DFA_DIFF_ENCODE; return true; } diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 95d018342..6eb1eb153 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -28,7 +28,7 @@ /* #define DEBUG */ - +#include "common_optarg.h" #include "lib.h" #include "parser.h" #include "profile.h" @@ -128,7 +128,7 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob, sptr = aare; - if (dfaflags & DFA_DUMP_RULE_EXPR) + if (parseopts.dfadump & DUMP_DFA_RULE_EXPR) fprintf(stderr, "aare: %s -> ", aare); if (anchor) @@ -427,7 +427,7 @@ out: if (ret == FALSE) ptype = ePatternInvalid; - if (dfaflags & DFA_DUMP_RULE_EXPR) + if (parseopts.dfadump & DUMP_DFA_RULE_EXPR) fprintf(stderr, "%s\n", pcre.c_str()); return ptype; @@ -507,7 +507,7 @@ static int process_profile_name_xmatch(Profile *prof) aare_rules *rules = new aare_rules(); if (!rules) return FALSE; - if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, dfaflags)) { + if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, parseopts)) { delete rules; return FALSE; } @@ -520,7 +520,7 @@ static int process_profile_name_xmatch(Profile *prof) ptype = convert_aaregex_to_pcre(alt->name, 0, glob_default, tbuf, &len); - if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, dfaflags)) { + if (!rules->add_rule(tbuf.c_str(), 0, AA_MAY_EXEC, 0, parseopts)) { delete rules; return FALSE; } @@ -562,14 +562,14 @@ static int process_profile_name_xmatch(Profile *prof) convert_aaregex_to_pcre(xattr_value, 0, glob_null, tbuf, &len); - if (!rules->append_rule(tbuf.c_str(), true, true, dfaflags)) { + if (!rules->append_rule(tbuf.c_str(), true, true, parseopts)) { delete rules; return FALSE; } } } build: - prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, dfaflags, true); + prof->xmatch = rules->create_dfa(&prof->xmatch_size, &prof->xmatch_len, parseopts, true); delete rules; if (!prof->xmatch) return FALSE; @@ -638,13 +638,13 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) !dfarules->add_rule(tbuf.c_str(), entry->rule_mode == RULE_DENY, entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE), entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0, - dfaflags)) + parseopts)) return FALSE; } else if (!is_change_profile_perms(entry->perms)) { if (!dfarules->add_rule(tbuf.c_str(), entry->rule_mode == RULE_DENY, entry->perms, entry->audit == AUDIT_FORCE ? entry->perms : 0, - dfaflags)) + parseopts)) return FALSE; } @@ -667,7 +667,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) perms |= LINK_TO_LINK_SUBSET(perms); vec[1] = "/[^/].*"; } - if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, dfaflags, false)) + if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, parseopts, false)) return FALSE; } if (is_change_profile_perms(entry->perms)) { @@ -678,7 +678,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) int index = 1; uint32_t onexec_perms = AA_ONEXEC; - if ((warnflags & WARN_RULE_DOWNGRADED) && entry->audit == AUDIT_FORCE && warn_change_profile) { + if ((parseopts.warn & WARN_RULE_DOWNGRADED) && entry->audit == AUDIT_FORCE && warn_change_profile) { /* don't have profile name here, so until this code * gets refactored just throw out a generic warning */ @@ -720,12 +720,12 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) /* regular change_profile rule */ if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, AA_CHANGE_PROFILE | onexec_perms, - 0, index - 1, &vec[1], dfaflags, false)) + 0, index - 1, &vec[1], parseopts, false)) return FALSE; /* onexec rules - both rules are needed for onexec */ if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms, - 0, 1, vec, dfaflags, false)) + 0, 1, vec, parseopts, false)) return FALSE; /** @@ -734,7 +734,7 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry) */ onexec_perms |= (entry->perms & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE)); if (!dfarules->add_rule_vec(entry->rule_mode == RULE_DENY, onexec_perms, - 0, index, vec, dfaflags, false)) + 0, index, vec, parseopts, false)) return FALSE; } return TRUE; @@ -770,7 +770,7 @@ int process_profile_regex(Profile *prof) if (prof->dfa.rules->rule_count > 0) { int xmatch_len = 0; prof->dfa.dfa = prof->dfa.rules->create_dfa(&prof->dfa.size, - &xmatch_len, dfaflags, true); + &xmatch_len, parseopts, true); delete prof->dfa.rules; prof->dfa.rules = NULL; if (!prof->dfa.dfa) @@ -875,7 +875,7 @@ static bool gen_net_rule(Profile *prof, u16 family, unsigned int type_mask, buf = buffer.str(); if (!prof->policy.rules->add_rule(buf.c_str(), deny, map_perms(AA_VALID_NET_PERMS), audit ? map_perms(AA_VALID_NET_PERMS) : 0, - dfaflags)) + parseopts)) return false; return true; @@ -969,44 +969,44 @@ int process_profile_policydb(Profile *prof) /* note: this activates fs based unix domain sockets mediation on connect */ if (kernel_abi_version > 5 && - !prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_file, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_mount && - !prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_mount, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_dbus && - !prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_dbus, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_signal && - !prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_signal, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_ptrace && - !prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_ptrace, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_networkv8 && - !prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_netv8, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_unix && - (!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, dfaflags) || - !prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, dfaflags))) + (!prof->policy.rules->add_rule(mediates_extended_net, 0, AA_MAY_READ, 0, parseopts) || + !prof->policy.rules->add_rule(mediates_net_unix, 0, AA_MAY_READ, 0, parseopts))) goto out; if (features_supports_userns && - !prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_ns, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_posix_mqueue && - !prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_posix_mqueue, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_sysv_mqueue && - !prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, AA_MAY_READ, 0, parseopts)) goto out; if (features_supports_io_uring && - !prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, dfaflags)) + !prof->policy.rules->add_rule(mediates_io_uring, 0, AA_MAY_READ, 0, parseopts)) goto out; if (prof->policy.rules->rule_count > 0) { int xmatch_len = 0; prof->policy.dfa = prof->policy.rules->create_dfa(&prof->policy.size, - &xmatch_len, dfaflags, false); + &xmatch_len, parseopts, false); delete prof->policy.rules; prof->policy.rules = NULL; diff --git a/parser/ptrace.cc b/parser/ptrace.cc index 8d16f98ca..3729b7606 100644 --- a/parser/ptrace.cc +++ b/parser/ptrace.cc @@ -134,7 +134,7 @@ int ptrace_rule::gen_policy_re(Profile &prof) buf = buffer.str(); if (perms & AA_VALID_PTRACE_PERMS) { if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - dfaflags)) + parseopts)) goto fail; } diff --git a/parser/signal.cc b/parser/signal.cc index fde038525..09e144ba0 100644 --- a/parser/signal.cc +++ b/parser/signal.cc @@ -317,7 +317,7 @@ int signal_rule::gen_policy_re(Profile &prof) buf = buffer.str(); if (perms & (AA_MAY_SEND | AA_MAY_RECEIVE)) { if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - dfaflags)) + parseopts)) goto fail; } diff --git a/parser/userns.cc b/parser/userns.cc index c868bebb0..f70f8e84e 100644 --- a/parser/userns.cc +++ b/parser/userns.cc @@ -97,7 +97,7 @@ int userns_rule::gen_policy_re(Profile &prof) if (perms & AA_VALID_USERNS_PERMS) { if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode == RULE_DENY, perms, audit == AUDIT_FORCE ? perms : 0, - dfaflags)) + parseopts)) goto fail; } From 1754b4da699c93be8bf2c40cc1a734bf3cf82bc2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 5 Jul 2023 04:33:14 -0700 Subject: [PATCH 13/14] parser: add flags to control rule merging Add the ability to control whether rule merging is done. TODO: in the furture cleanup display of flags split accross two tables Signed-off-by: John Johansen --- parser/common_flags.h | 4 ++++ parser/common_optarg.c | 7 ------- parser/common_optarg.h | 2 -- parser/io_uring.cc | 1 + parser/parser.h | 3 +++ parser/parser_common.c | 10 ++++++++++ parser/parser_main.c | 26 ++++++++++++++++++++++++-- parser/parser_merge.c | 6 +++++- 8 files changed, 47 insertions(+), 12 deletions(-) diff --git a/parser/common_flags.h b/parser/common_flags.h index 116bfc274..464cb8f64 100644 --- a/parser/common_flags.h +++ b/parser/common_flags.h @@ -24,8 +24,12 @@ typedef int optflags_t; typedef struct optflags { optflags_t dfaflags; optflags_t dfadump; + optflags_t frontflags; + optflags_t frontdump; optflags_t warn; optflags_t Werror; } optflags; +extern optflags parseopts; + #endif /* __AA_COMMON_FLAGS_H */ diff --git a/parser/common_optarg.c b/parser/common_optarg.c index c27f0205a..2ba50443a 100644 --- a/parser/common_optarg.c +++ b/parser/common_optarg.c @@ -103,13 +103,6 @@ optflag_table_t dfaoptflag_table[] = { { 0, NULL, NULL, 0 }, }; -optflags parseopts = { - .dfaflags = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE), - .dfadump = 0, - .warn = DEFAULT_WARNINGS, - .Werror = 0 -}; - void print_flag_table(optflag_table_t *table) { diff --git a/parser/common_optarg.h b/parser/common_optarg.h index 4b0a16dbf..c5c6144b2 100644 --- a/parser/common_optarg.h +++ b/parser/common_optarg.h @@ -41,8 +41,6 @@ typedef struct { extern optflag_table_t dfadumpflag_table[]; extern optflag_table_t dfaoptflag_table[]; -extern optflags parseopts; - void print_flags(const char *prefix, optflag_table_t *table, optflags_t flags); diff --git a/parser/io_uring.cc b/parser/io_uring.cc index 3c2f88555..d7715b69d 100644 --- a/parser/io_uring.cc +++ b/parser/io_uring.cc @@ -15,6 +15,7 @@ * along with this program; if not, contact or Canonical Ltd. */ +#include "common_optarg.h" #include "parser.h" #include "profile.h" #include "io_uring.h" diff --git a/parser/parser.h b/parser/parser.h index 95b177060..8c6984319 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -83,6 +83,9 @@ extern int parser_token; WARN_OVERRIDE | WARN_INCLUDE) +#define CONTROL_RULE_MERGE 0x1 +#define DUMP_RULE_MERGE 0x1 + typedef enum pattern_t pattern_t; diff --git a/parser/parser_common.c b/parser/parser_common.c index 2daa25967..9dc9b484b 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -99,6 +99,16 @@ FILE *ofile = NULL; IncludeCache_t *g_includecache; +optflags parseopts = { + .dfaflags = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE), + .dfadump = 0, + .frontflags = (optflags_t)(CONTROL_RULE_MERGE), + .frontdump = 0, + .warn = DEFAULT_WARNINGS, + .Werror = 0 +}; + + #ifdef FORCE_READ_IMPLIES_EXEC int read_implies_exec = 1; #else diff --git a/parser/parser_main.c b/parser/parser_main.c index 080822da1..e001957f3 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -82,6 +82,9 @@ int abort_on_error = 0; /* stop processing profiles if error */ int skip_bad_cache_rebuild = 0; int mru_skip_cache = 1; +bool O_rule_merge = true; +bool D_rule_merge = false; + /* for jobs_max and jobs * LONG_MAX : no limit * LONG_MIN : auto = detect system processing cores @@ -274,6 +277,16 @@ optflag_table_t warnflag_table[] = { { 0, NULL, NULL, 0 }, }; +optflag_table_t frontopts_table[] = { + { 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE}, + { 0, NULL, NULL, 0 }, +}; + +optflag_table_t frontdump_table[] = { + { 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE}, + { 0, NULL, NULL, 0 }, +}; + /* Parse comma separated cachelocations. Commas can be escaped by \, */ static int parse_cacheloc(const char *arg, const char **cacheloc, int max_size) { @@ -494,10 +507,13 @@ static int process_arg(int c, char *optarg) strcmp(optarg, "D") == 0) { flagtable_help("--dump=", DUMP_HEADER, progname, dfadumpflag_table); + flagtable_help("--dump=", DUMP_HEADER, progname, + frontopts_table); } else if (strcmp(optarg, "Optimize") == 0 || strcmp(optarg, "optimize") == 0 || strcmp(optarg, "O") == 0) { flagtable_help("-O ", "", progname, dfaoptflag_table); + flagtable_help("-O ", "", progname, frontopts_table); } else if (strcmp(optarg, "warn") == 0) { flagtable_help("--warn=", "", progname, warnflag_table); } else if (strcmp(optarg, "Werror") == 0) { @@ -569,12 +585,15 @@ static int process_arg(int c, char *optarg) dump_vars = 1; } else if (strcmp(optarg, "show") == 0) { print_flags("dump", dfadumpflag_table, parseopts.dfadump); + print_flags("dump", frontdump_table, parseopts.frontdump); } else if (strcmp(optarg, "variables") == 0) { dump_vars = 1; } else if (strcmp(optarg, "expanded-variables") == 0) { dump_expanded_vars = 1; } else if (!handle_flag_table(dfadumpflag_table, optarg, - &parseopts.dfadump)) { + &parseopts.dfadump) && + !handle_flag_table(frontdump_table, optarg, + &parseopts.frontdump)) { PERROR("%s: Invalid --Dump option %s\n", progname, optarg); exit(1); @@ -583,8 +602,11 @@ static int process_arg(int c, char *optarg) case 'O': if (strcmp(optarg, "show") == 0) { print_flags("Optimize", dfaoptflag_table, parseopts.dfaflags); + print_flags("Optimize", frontopts_table, parseopts.frontflags); } else if (!handle_flag_table(dfaoptflag_table, optarg, - &parseopts.dfaflags)) { + &parseopts.dfaflags) && + !handle_flag_table(frontopts_table, optarg, + &parseopts.frontflags)) { PERROR("%s: Invalid --Optimize option %s\n", progname, optarg); exit(1); diff --git a/parser/parser_merge.c b/parser/parser_merge.c index b8041ebb5..7f9ce297d 100644 --- a/parser/parser_merge.c +++ b/parser/parser_merge.c @@ -111,12 +111,16 @@ static int process_file_entries(Profile *prof) int profile_merge_rules(Profile *prof) { + if (!(parseopts.frontflags & CONTROL_RULE_MERGE)) + return 0; + int res, tmp = process_file_entries(prof); if (tmp < 0) return -tmp; res = prof->merge_rules(); if (res < 0) return -res; - // TODO: output message eliminated rules res + tmp; + if (parseopts.frontdump & DUMP_RULE_MERGE) + fprintf(stderr, "RULE MERGE: deleted %d file rules, %d rules\n", tmp, res); return 0; } From 501e87a3f2466f0cee6d9a16b9f823819dcc84e4 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sat, 8 Jul 2023 19:49:34 -0700 Subject: [PATCH 14/14] parser: Cleanup parser control flags, so they display as expected to user Instead of having multiple tables, since we have room post split of optimization and dump flags just move all the optimization and dump flags into a common table. We can if needed switch the flag entry size to a long in the future. Signed-off-by: John Johansen --- parser/common_flags.h | 6 ++-- parser/common_optarg.c | 4 ++- parser/common_optarg.h | 2 +- parser/libapparmor_re/aare_rules.cc | 44 ++++++++++++++--------------- parser/libapparmor_re/apparmor_re.h | 3 ++ parser/libapparmor_re/chfa.cc | 12 ++++---- parser/libapparmor_re/expr-tree.cc | 10 +++---- parser/libapparmor_re/hfa.cc | 38 ++++++++++++------------- parser/parser.h | 3 -- parser/parser_common.c | 6 ++-- parser/parser_main.c | 32 +++++---------------- parser/parser_merge.c | 4 +-- parser/parser_regex.c | 4 +-- 13 files changed, 74 insertions(+), 94 deletions(-) diff --git a/parser/common_flags.h b/parser/common_flags.h index 464cb8f64..68421a32a 100644 --- a/parser/common_flags.h +++ b/parser/common_flags.h @@ -22,10 +22,8 @@ typedef int optflags_t; typedef struct optflags { - optflags_t dfaflags; - optflags_t dfadump; - optflags_t frontflags; - optflags_t frontdump; + optflags_t control; + optflags_t dump; optflags_t warn; optflags_t Werror; } optflags; diff --git a/parser/common_optarg.c b/parser/common_optarg.c index 2ba50443a..7bf327378 100644 --- a/parser/common_optarg.c +++ b/parser/common_optarg.c @@ -27,7 +27,7 @@ #include "common_optarg.h" #include "parser.h" -optflag_table_t dfadumpflag_table[] = { +optflag_table_t dumpflag_table[] = { { 1, "rule-exprs", "Dump rule to expr tree conversions", DUMP_DFA_RULE_EXPR }, { 1, "expr-stats", "Dump stats on expr tree", DUMP_DFA_TREE_STATS }, @@ -70,6 +70,7 @@ optflag_table_t dfadumpflag_table[] = { DUMP_DFA_DIFF_STATS }, { 1, "diff-progress", "Dump progress of differential encoding", DUMP_DFA_DIFF_PROGRESS | DUMP_DFA_DIFF_STATS }, + { 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE}, { 0, NULL, NULL, 0 }, }; @@ -100,6 +101,7 @@ optflag_table_t dfaoptflag_table[] = { CONTROL_DFA_TRANS_HIGH }, { 1, "diff-encode", "Differentially encode transitions", CONTROL_DFA_DIFF_ENCODE }, + { 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE}, { 0, NULL, NULL, 0 }, }; diff --git a/parser/common_optarg.h b/parser/common_optarg.h index c5c6144b2..4e44f5b8f 100644 --- a/parser/common_optarg.h +++ b/parser/common_optarg.h @@ -38,7 +38,7 @@ typedef struct { optflags_t flags; } optflag_table_t; -extern optflag_table_t dfadumpflag_table[]; +extern optflag_table_t dumpflag_table[]; extern optflag_table_t dfaoptflag_table[]; diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 9c146363c..385e4508a 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -110,7 +110,7 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, accept = unique_perms.insert(deny, perms, audit, exact_match); - if (opts.dfadump & DUMP_DFA_RULE_EXPR) { + if (opts.dump & DUMP_DFA_RULE_EXPR) { const char *separator; if (oob) separator = "\\-x01"; @@ -158,7 +158,7 @@ bool aare_rules::append_rule(const char *rule, bool oob, bool with_perm, if (regex_parse(&tree, rule)) return false; - if (opts.dfadump & DUMP_DFA_RULE_EXPR) { + if (opts.dump & DUMP_DFA_RULE_EXPR) { cerr << "rule: "; cerr << rule; cerr << " -> "; @@ -204,14 +204,14 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o * set nodes */ PermExprMap::iterator i = expr_map.begin(); if (i != expr_map.end()) { - if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { + if (opts.control & CONTROL_DFA_TREE_SIMPLE) { Node *tmp = simplify_tree(i->second, opts); root = new CatNode(tmp, i->first); } else root = new CatNode(i->second, i->first); for (i++; i != expr_map.end(); i++) { Node *tmp; - if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { + if (opts.control & CONTROL_DFA_TREE_SIMPLE) { tmp = simplify_tree(i->second, opts); } else tmp = i->second; @@ -226,13 +226,13 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o * this debug dump. */ label_nodes(root); - if (opts.dfadump & DUMP_DFA_TREE) { + if (opts.dump & DUMP_DFA_TREE) { cerr << "\nDFA: Expression Tree\n"; root->dump(cerr); cerr << "\n\n"; } - if (opts.dfaflags & CONTROL_DFA_TREE_SIMPLE) { + if (opts.control & CONTROL_DFA_TREE_SIMPLE) { /* This is old total tree, simplification point * For now just do simplification up front. It gets most * of the benefit running on the smaller chains, and is @@ -241,7 +241,7 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o */ //root = simplify_tree(root, opts); - if (opts.dfadump & DUMP_DFA_SIMPLE_TREE) { + if (opts.dump & DUMP_DFA_SIMPLE_TREE) { cerr << "\nDFA: Simplified Expression Tree\n"; root->dump(cerr); cerr << "\n\n"; @@ -251,18 +251,18 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o stringstream stream; try { DFA dfa(root, opts, filedfa); - if (opts.dfadump & DUMP_DFA_UNIQ_PERMS) + if (opts.dump & DUMP_DFA_UNIQ_PERMS) dfa.dump_uniq_perms("dfa"); - if (opts.dfaflags & CONTROL_DFA_MINIMIZE) { + if (opts.control & CONTROL_DFA_MINIMIZE) { dfa.minimize(opts); - if (opts.dfadump & DUMP_DFA_MIN_UNIQ_PERMS) + if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS) dfa.dump_uniq_perms("minimized dfa"); } - if (opts.dfaflags & CONTROL_DFA_FILTER_DENY && - opts.dfaflags & CONTROL_DFA_MINIMIZE && + if (opts.control & CONTROL_DFA_FILTER_DENY && + opts.control & CONTROL_DFA_MINIMIZE && dfa.apply_and_clear_deny()) { /* Do a second minimization pass as removal of deny * information has moved some states from accepting @@ -273,40 +273,40 @@ void *aare_rules::create_dfa(size_t *size, int *min_match_len, optflags const &o */ dfa.minimize(opts); - if (opts.dfadump & DUMP_DFA_MIN_UNIQ_PERMS) + if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS) dfa.dump_uniq_perms("minimized dfa"); } - if (opts.dfaflags & CONTROL_DFA_REMOVE_UNREACHABLE) + if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE) dfa.remove_unreachable(opts); - if (opts.dfadump & DUMP_DFA_STATES) + if (opts.dump & DUMP_DFA_STATES) dfa.dump(cerr); - if (opts.dfadump & DUMP_DFA_GRAPH) + if (opts.dump & DUMP_DFA_GRAPH) dfa.dump_dot_graph(cerr); map eq; - if (opts.dfaflags & CONTROL_DFA_EQUIV) { + if (opts.control & CONTROL_DFA_EQUIV) { eq = dfa.equivalence_classes(opts); dfa.apply_equivalence_classes(eq); - if (opts.dfadump & DUMP_DFA_EQUIV) { + if (opts.dump & DUMP_DFA_EQUIV) { cerr << "\nDFA equivalence class\n"; dump_equivalence_classes(cerr, eq); } - } else if (opts.dfadump & DUMP_DFA_EQUIV) + } else if (opts.dump & DUMP_DFA_EQUIV) cerr << "\nDFA did not generate an equivalence class\n"; - if (opts.dfaflags & CONTROL_DFA_DIFF_ENCODE) { + if (opts.control & CONTROL_DFA_DIFF_ENCODE) { dfa.diff_encode(opts); - if (opts.dfadump & DUMP_DFA_DIFF_ENCODE) + if (opts.dump & DUMP_DFA_DIFF_ENCODE) dfa.dump_diff_encode(cerr); } CHFA chfa(dfa, eq, opts); - if (opts.dfadump & DUMP_DFA_TRANS_TABLE) + if (opts.dump & DUMP_DFA_TRANS_TABLE) chfa.dump(cerr); chfa.flex_table(stream, ""); } diff --git a/parser/libapparmor_re/apparmor_re.h b/parser/libapparmor_re/apparmor_re.h index eafb12203..243d728ae 100644 --- a/parser/libapparmor_re/apparmor_re.h +++ b/parser/libapparmor_re/apparmor_re.h @@ -30,6 +30,8 @@ #define CONTROL_DFA_REMOVE_UNREACHABLE (1 << 7) #define CONTROL_DFA_TRANS_HIGH (1 << 8) #define CONTROL_DFA_DIFF_ENCODE (1 << 9) +#define CONTROL_RULE_MERGE (1 << 10) + #define DUMP_DFA_DIFF_PROGRESS (1 << 0) #define DUMP_DFA_DIFF_ENCODE (1 << 1) @@ -53,5 +55,6 @@ #define DUMP_DFA_UNREACHABLE (1 << 19) #define DUMP_DFA_RULE_EXPR (1 << 20) #define DUMP_DFA_NODE_TO_DFA (1 << 21) +#define DUMP_RULE_MERGE (1 << 22) #endif /* APPARMOR_RE_H */ diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index c31045866..658218958 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -52,7 +52,7 @@ void CHFA::init_free_list(vector > &free_list, CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): eq(eq) { - if (opts.dfadump & DUMP_DFA_TRANS_PROGRESS) + if (opts.dump & DUMP_DFA_TRANS_PROGRESS) fprintf(stderr, "Compressing HFA:\r"); chfaflags = 0; @@ -83,7 +83,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): if (*i == dfa.start || *i == dfa.nonmatching) continue; optimal += (*i)->trans.size(); - if (opts.dfaflags & CONTROL_DFA_TRANS_HIGH) { + if (opts.control & CONTROL_DFA_TRANS_HIGH) { size_t range = 0; if ((*i)->trans.size()) range = @@ -117,7 +117,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): int count = 2; - if (!(opts.dfaflags & CONTROL_DFA_TRANS_HIGH)) { + if (!(opts.control & CONTROL_DFA_TRANS_HIGH)) { for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { if (*i != dfa.nonmatching && *i != dfa.start) { insert_state(free_list, *i, dfa); @@ -125,7 +125,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny); num.insert(make_pair(*i, num.size())); } - if (opts.dfadump & (DUMP_DFA_TRANS_PROGRESS)) { + if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { count++; if (count % 100 == 0) fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r", @@ -142,7 +142,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny); num.insert(make_pair(i->second, num.size())); } - if (opts.dfadump & (DUMP_DFA_TRANS_PROGRESS)) { + if (opts.dump & (DUMP_DFA_TRANS_PROGRESS)) { count++; if (count % 100 == 0) fprintf(stderr, "\033[2KCompressing trans table: insert state: %d/%zd\r", @@ -151,7 +151,7 @@ CHFA::CHFA(DFA &dfa, map &eq, optflags const &opts): } } - if (opts.dfadump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) { + if (opts.dump & (DUMP_DFA_TRANS_STATS | DUMP_DFA_TRANS_PROGRESS)) { ssize_t size = 4 * next_check.size() + 6 * dfa.states.size(); fprintf(stderr, "\033[2KCompressed trans table: states %zd, next/check %zd, optimal next/check %zd avg/state %.2f, compression %zd/%zd = %.2f %%\n", dfa.states.size(), next_check.size(), optimal, diff --git a/parser/libapparmor_re/expr-tree.cc b/parser/libapparmor_re/expr-tree.cc index aa691db57..53c640d4e 100644 --- a/parser/libapparmor_re/expr-tree.cc +++ b/parser/libapparmor_re/expr-tree.cc @@ -580,7 +580,7 @@ Node *simplify_tree(Node *t, optflags const &opts) bool update = true; int i; - if (opts.dfadump & DUMP_DFA_TREE_STATS) { + if (opts.dump & DUMP_DFA_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; count_tree_nodes(t, &counts); fprintf(stderr, @@ -598,25 +598,25 @@ Node *simplify_tree(Node *t, optflags const &opts) // the dfa having about 7 thousands states, // and it having about 1.25 million states int dir = 1; - if (opts.dfaflags & CONTROL_DFA_TREE_LEFT) + if (opts.control & CONTROL_DFA_TREE_LEFT) dir = 0; for (int count = 0; count < 2; count++) { bool modified; do { modified = false; - if (opts.dfaflags & CONTROL_DFA_TREE_NORMAL) + if (opts.control & CONTROL_DFA_TREE_NORMAL) t->normalize(dir); t = simplify_tree_base(t, dir, modified); if (modified) update = true; } while (modified); - if (opts.dfaflags & CONTROL_DFA_TREE_LEFT) + if (opts.control & CONTROL_DFA_TREE_LEFT) dir++; else dir--; } } - if (opts.dfadump & DUMP_DFA_TREE_STATS) { + if (opts.dump & DUMP_DFA_TREE_STATS) { struct node_counts counts = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; count_tree_nodes(t, &counts); fprintf(stderr, diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index e8c31ab91..ebb0f4b70 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -396,7 +396,7 @@ void DFA::process_work_queue(const char *header, optflags const &opts) int i = 0; while (!work_queue.empty()) { - if (i % 1000 == 0 && (opts.dfadump & DUMP_DFA_PROGRESS)) { + if (i % 1000 == 0 && (opts.dump & DUMP_DFA_PROGRESS)) { cerr << "\033[2K" << header << ": queue " << work_queue.size() << "\tstates " @@ -428,7 +428,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed oob_range = 0; ord_range = 8; - if (opts.dfadump & DUMP_DFA_PROGRESS) + if (opts.dump & DUMP_DFA_PROGRESS) fprintf(stderr, "Creating dfa:\r"); for (depth_first_traversal i(root); i; i++) { @@ -437,7 +437,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed (*i)->compute_lastpos(); } - if (opts.dfadump & DUMP_DFA_PROGRESS) + if (opts.dump & DUMP_DFA_PROGRESS) fprintf(stderr, "Creating dfa: followpos\r"); for (depth_first_traversal i(root); i; i++) { (*i)->compute_followpos(); @@ -471,10 +471,10 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed (*i)->followpos.clear(); } - if (opts.dfadump & DUMP_DFA_NODE_TO_DFA) + if (opts.dump & DUMP_DFA_NODE_TO_DFA) dump_node_to_dfa(); - if (opts.dfadump & (DUMP_DFA_STATS)) { + if (opts.dump & (DUMP_DFA_STATS)) { cerr << "\033[2KCreated dfa: states " << states.size() << " proto { " @@ -571,7 +571,7 @@ void DFA::remove_unreachable(optflags const &opts) next = i; next++; if (reachable.find(*i) == reachable.end()) { - if (opts.dfadump & DUMP_DFA_UNREACHABLE) { + if (opts.dump & DUMP_DFA_UNREACHABLE) { cerr << "unreachable: " << **i; if (*i == start) cerr << " <=="; @@ -586,7 +586,7 @@ void DFA::remove_unreachable(optflags const &opts) } } - if (count && (opts.dfadump & DUMP_DFA_STATS)) + if (count && (opts.dump & DUMP_DFA_STATS)) cerr << "DFA: states " << states.size() << " removed " << count << " unreachable states\n"; } @@ -680,7 +680,7 @@ void DFA::minimize(optflags const &opts) p->second->push_back(*i); } - if ((opts.dfadump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0)) + if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 1000 == 0)) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << partitions.size() << " (accept " << accept_count << ")\r"; @@ -692,7 +692,7 @@ void DFA::minimize(optflags const &opts) perm_map.clear(); int init_count = partitions.size(); - if (opts.dfadump & DUMP_DFA_PROGRESS) + if (opts.dump & DUMP_DFA_PROGRESS) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\r"; @@ -734,7 +734,7 @@ void DFA::minimize(optflags const &opts) (*m)->partition = new_part; } } - if ((opts.dfadump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0)) + if ((opts.dump & DUMP_DFA_PROGRESS) && (partitions.size() % 100 == 0)) cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " @@ -743,7 +743,7 @@ void DFA::minimize(optflags const &opts) } while (new_part_count); if (partitions.size() == states.size()) { - if (opts.dfadump & DUMP_DFA_STATS) + if (opts.dump & DUMP_DFA_STATS) cerr << "\033[2KDfa minimization no states removed: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\n"; @@ -757,13 +757,13 @@ void DFA::minimize(optflags const &opts) * to states within the same partitions, however this can slow * down compressed dfa compression as there are more states, */ - if (opts.dfadump & DUMP_DFA_MIN_PARTS) + if (opts.dump & DUMP_DFA_MIN_PARTS) cerr << "Partitions after minimization\n"; for (list::iterator p = partitions.begin(); p != partitions.end(); p++) { /* representative state for this partition */ State *rep = *((*p)->begin()); - if (opts.dfadump & DUMP_DFA_MIN_PARTS) + if (opts.dump & DUMP_DFA_MIN_PARTS) cerr << *rep << " : "; /* update representative state's transitions */ @@ -782,17 +782,17 @@ void DFA::minimize(optflags const &opts) /* clear the state label for all non representative states, * and accumulate permissions */ for (Partition::iterator i = ++(*p)->begin(); i != (*p)->end(); i++) { - if (opts.dfadump & DUMP_DFA_MIN_PARTS) + if (opts.dump & DUMP_DFA_MIN_PARTS) cerr << **i << ", "; (*i)->label = -1; rep->perms.add((*i)->perms, filedfa); } if (rep->perms.is_accept()) final_accept++; - if (opts.dfadump & DUMP_DFA_MIN_PARTS) + if (opts.dump & DUMP_DFA_MIN_PARTS) cerr << "\n"; } - if (opts.dfadump & DUMP_DFA_STATS) + if (opts.dump & DUMP_DFA_STATS) cerr << "\033[2KMinimized dfa: final partitions " << partitions.size() << " (accept " << final_accept << ")" << "\tinit " << init_count << " (accept " @@ -965,7 +965,7 @@ void DFA::diff_encode(optflags const &opts) } } - if ((opts.dfadump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0)) + if ((opts.dump & DUMP_DFA_DIFF_PROGRESS) && (i % 100 == 0)) cerr << "\033[2KDiff Encode: " << i << " of " << tail << ". Diff states " << xcount << " Savings " << xweight << "\r"; @@ -992,7 +992,7 @@ void DFA::diff_encode(optflags const &opts) } } - if (opts.dfadump & DUMP_DFA_DIFF_STATS) + if (opts.dump & DUMP_DFA_DIFF_STATS) cerr << "Diff encode states: " << diffcount << " of " << tail << " reached @ depth " << depth << ". " << aweight << " trans removed\n"; @@ -1251,7 +1251,7 @@ map DFA::equivalence_classes(optflags const &opts) } } - if (opts.dfadump & DUMP_DFA_EQUIV_STATS) + if (opts.dump & DUMP_DFA_EQUIV_STATS) fprintf(stderr, "Equiv class reduces to %d classes\n", next_class.c - 1); return classes; diff --git a/parser/parser.h b/parser/parser.h index 8c6984319..95b177060 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -83,9 +83,6 @@ extern int parser_token; WARN_OVERRIDE | WARN_INCLUDE) -#define CONTROL_RULE_MERGE 0x1 -#define DUMP_RULE_MERGE 0x1 - typedef enum pattern_t pattern_t; diff --git a/parser/parser_common.c b/parser/parser_common.c index 9dc9b484b..f117d2ffa 100644 --- a/parser/parser_common.c +++ b/parser/parser_common.c @@ -100,10 +100,8 @@ FILE *ofile = NULL; IncludeCache_t *g_includecache; optflags parseopts = { - .dfaflags = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE), - .dfadump = 0, - .frontflags = (optflags_t)(CONTROL_RULE_MERGE), - .frontdump = 0, + .control = (optflags_t)(CONTROL_DFA_TREE_NORMAL | CONTROL_DFA_TREE_SIMPLE | CONTROL_DFA_MINIMIZE | CONTROL_DFA_DIFF_ENCODE | CONTROL_RULE_MERGE), + .dump = 0, .warn = DEFAULT_WARNINGS, .Werror = 0 }; diff --git a/parser/parser_main.c b/parser/parser_main.c index e001957f3..d46eb8ef2 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -277,15 +277,6 @@ optflag_table_t warnflag_table[] = { { 0, NULL, NULL, 0 }, }; -optflag_table_t frontopts_table[] = { - { 1, "rule-merge", "turn on rule merging", CONTROL_RULE_MERGE}, - { 0, NULL, NULL, 0 }, -}; - -optflag_table_t frontdump_table[] = { - { 1, "rule-merge", "dump information about rule merging", DUMP_RULE_MERGE}, - { 0, NULL, NULL, 0 }, -}; /* Parse comma separated cachelocations. Commas can be escaped by \, */ static int parse_cacheloc(const char *arg, const char **cacheloc, int max_size) @@ -506,14 +497,11 @@ static int process_arg(int c, char *optarg) strcmp(optarg, "dump") == 0 || strcmp(optarg, "D") == 0) { flagtable_help("--dump=", DUMP_HEADER, progname, - dfadumpflag_table); - flagtable_help("--dump=", DUMP_HEADER, progname, - frontopts_table); + dumpflag_table); } else if (strcmp(optarg, "Optimize") == 0 || strcmp(optarg, "optimize") == 0 || strcmp(optarg, "O") == 0) { flagtable_help("-O ", "", progname, dfaoptflag_table); - flagtable_help("-O ", "", progname, frontopts_table); } else if (strcmp(optarg, "warn") == 0) { flagtable_help("--warn=", "", progname, warnflag_table); } else if (strcmp(optarg, "Werror") == 0) { @@ -584,16 +572,13 @@ static int process_arg(int c, char *optarg) if (!optarg) { dump_vars = 1; } else if (strcmp(optarg, "show") == 0) { - print_flags("dump", dfadumpflag_table, parseopts.dfadump); - print_flags("dump", frontdump_table, parseopts.frontdump); + print_flags("dump", dumpflag_table, parseopts.dump); } else if (strcmp(optarg, "variables") == 0) { dump_vars = 1; } else if (strcmp(optarg, "expanded-variables") == 0) { dump_expanded_vars = 1; - } else if (!handle_flag_table(dfadumpflag_table, optarg, - &parseopts.dfadump) && - !handle_flag_table(frontdump_table, optarg, - &parseopts.frontdump)) { + } else if (!handle_flag_table(dumpflag_table, optarg, + &parseopts.dump)) { PERROR("%s: Invalid --Dump option %s\n", progname, optarg); exit(1); @@ -601,12 +586,9 @@ static int process_arg(int c, char *optarg) break; case 'O': if (strcmp(optarg, "show") == 0) { - print_flags("Optimize", dfaoptflag_table, parseopts.dfaflags); - print_flags("Optimize", frontopts_table, parseopts.frontflags); + print_flags("Optimize", dfaoptflag_table, parseopts.control); } else if (!handle_flag_table(dfaoptflag_table, optarg, - &parseopts.dfaflags) && - !handle_flag_table(frontopts_table, optarg, - &parseopts.frontflags)) { + &parseopts.control)) { PERROR("%s: Invalid --Optimize option %s\n", progname, optarg); exit(1); @@ -1552,7 +1534,7 @@ static bool get_kernel_features(struct aa_features **features) if (!kernel_supports_diff_encode) /* clear diff_encode because it is not supported */ - parseopts.dfaflags &= ~CONTROL_DFA_DIFF_ENCODE; + parseopts.control &= ~CONTROL_DFA_DIFF_ENCODE; return true; } diff --git a/parser/parser_merge.c b/parser/parser_merge.c index 7f9ce297d..523933cab 100644 --- a/parser/parser_merge.c +++ b/parser/parser_merge.c @@ -111,7 +111,7 @@ static int process_file_entries(Profile *prof) int profile_merge_rules(Profile *prof) { - if (!(parseopts.frontflags & CONTROL_RULE_MERGE)) + if (!(parseopts.control & CONTROL_RULE_MERGE)) return 0; int res, tmp = process_file_entries(prof); @@ -120,7 +120,7 @@ int profile_merge_rules(Profile *prof) res = prof->merge_rules(); if (res < 0) return -res; - if (parseopts.frontdump & DUMP_RULE_MERGE) + if (parseopts.dump & DUMP_RULE_MERGE) fprintf(stderr, "RULE MERGE: deleted %d file rules, %d rules\n", tmp, res); return 0; } diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 6eb1eb153..578f6aa44 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -128,7 +128,7 @@ pattern_t convert_aaregex_to_pcre(const char *aare, int anchor, int glob, sptr = aare; - if (parseopts.dfadump & DUMP_DFA_RULE_EXPR) + if (parseopts.dump & DUMP_DFA_RULE_EXPR) fprintf(stderr, "aare: %s -> ", aare); if (anchor) @@ -427,7 +427,7 @@ out: if (ret == FALSE) ptype = ePatternInvalid; - if (parseopts.dfadump & DUMP_DFA_RULE_EXPR) + if (parseopts.dump & DUMP_DFA_RULE_EXPR) fprintf(stderr, "%s\n", pcre.c_str()); return ptype;