From 02b7e41ef3d89cea2bc24073938e7fdab8c29b17 Mon Sep 17 00:00:00 2001 From: fossdd Date: Sat, 3 May 2025 16:48:24 +0200 Subject: [PATCH 01/11] binutils: Fix missing include limits.h For NAME_MAX Fixes 322a98c8 ("Fix incorrect strnlen length in aa_load.c load_policy_dir") --- binutils/aa_load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/binutils/aa_load.c b/binutils/aa_load.c index 6133e899a..b7e6eca28 100644 --- a/binutils/aa_load.c +++ b/binutils/aa_load.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include From 7d5a021023f814bb7dbce65c09c75615789d2c42 Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima <2618741-e-kwsm@users.noreply.gitlab.com> Date: Sun, 4 May 2025 23:14:36 +0900 Subject: [PATCH 02/11] fix: avoid `using namespace std;` in header files using directive in a header file is a bad practice because it may lead to unexpected results. https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rs-using-directive --- parser/af_unix.cc | 2 ++ parser/file_cache.h | 6 ++--- parser/lib.c | 2 ++ parser/libapparmor_re/aare_rules.cc | 1 + parser/libapparmor_re/aare_rules.h | 10 ++++---- parser/libapparmor_re/chfa.cc | 2 ++ parser/libapparmor_re/chfa.h | 24 +++++++++---------- parser/libapparmor_re/expr-tree.cc | 2 ++ parser/libapparmor_re/expr-tree.h | 30 +++++++++++------------- parser/libapparmor_re/hfa.cc | 2 ++ parser/libapparmor_re/hfa.h | 36 ++++++++++++++--------------- parser/libapparmor_re/parse.y | 2 ++ parser/mount.cc | 2 ++ parser/parser.h | 2 -- parser/parser_interface.c | 1 + parser/parser_lex.l | 2 ++ parser/parser_misc.c | 2 ++ parser/parser_policy.c | 1 + parser/parser_yacc.y | 1 + parser/profile.cc | 2 ++ parser/profile.h | 14 +++++------ parser/rule.h | 8 +++---- parser/signal.cc | 2 ++ parser/signal.h | 2 +- 24 files changed, 87 insertions(+), 71 deletions(-) diff --git a/parser/af_unix.cc b/parser/af_unix.cc index f9b977a49..4a0039a5b 100644 --- a/parser/af_unix.cc +++ b/parser/af_unix.cc @@ -30,6 +30,8 @@ #include "profile.h" #include "af_unix.h" +using namespace std; + /* See unix(7) for autobind address definition */ #define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]"; diff --git a/parser/file_cache.h b/parser/file_cache.h index 7483be22d..81ddd7d27 100644 --- a/parser/file_cache.h +++ b/parser/file_cache.h @@ -21,14 +21,12 @@ #include #include -using namespace std; - /* TODO: have includecache be a frontend for file cache, don't just * store name. */ class IncludeCache_t { public: - set cache; + std::set cache; IncludeCache_t() = default; virtual ~IncludeCache_t() = default; @@ -39,7 +37,7 @@ public: } bool insert(const char *name) { - pair::iterator,bool> res = cache.insert(name); + std::pair::iterator,bool> res = cache.insert(name); if (res.second == false) { return false; } diff --git a/parser/lib.c b/parser/lib.c index a105fa379..a3d21f9a1 100644 --- a/parser/lib.c +++ b/parser/lib.c @@ -28,6 +28,8 @@ #include "lib.h" #include "parser.h" +using namespace std; + int dirat_for_each(int dirfd, const char *name, void *data, int (* cb)(int, const char *, struct stat *, void *)) { diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index d5546dde4..f2ddc564c 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -34,6 +34,7 @@ #include "chfa.h" #include "../immunix.h" +using namespace std; aare_rules::~aare_rules(void) { diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h index 91ae289b3..45f277f02 100644 --- a/parser/libapparmor_re/aare_rules.h +++ b/parser/libapparmor_re/aare_rules.h @@ -59,7 +59,7 @@ public: class UniquePermsCache { public: - typedef map UniquePermMap; + typedef std::map UniquePermMap; typedef UniquePermMap::iterator iterator; UniquePermMap nodes; @@ -89,7 +89,7 @@ public: node = new ExactMatchFlag(priority, perms, audit); else node = new MatchFlag(priority, perms, audit); - pair val = nodes.insert(make_pair(tmp, node)); + std::pair val = nodes.insert(std::make_pair(tmp, node)); if (val.second == false) { delete node; return val.first->second; @@ -121,17 +121,17 @@ class aare_rules { optflags const &opts, bool oob); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); CHFA *create_chfa(int *min_match_len, - vector &perms_table, + std::vector &perms_table, optflags const &opts, bool filedfa, bool extended_perms, bool prompt); void *create_dfablob(size_t *size, int *min_match_len, - vector &perms_table, + std::vector &perms_table, optflags const &opts, bool filedfa, bool extended_perms, bool prompt); void *create_welded_dfablob(aare_rules *file_rules, size_t *size, int *min_match_len, size_t *new_start, - vector &perms_table, + std::vector &perms_table, optflags const &opts, bool extended_perms, bool prompt); }; diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc index 809bcefed..d0e3a60af 100644 --- a/parser/libapparmor_re/chfa.cc +++ b/parser/libapparmor_re/chfa.cc @@ -37,6 +37,8 @@ #include "../policydb.h" #include "flex-tables.h" +using namespace std; + void CHFA::init_free_list(vector > &free_list, size_t prev, size_t start) { diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index cc36e8580..983c664e9 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -32,39 +32,37 @@ #define MATCH_FLAG_OOB_TRANSITION 0x20000000 #define base_mask_size(X) ((X) & ~BASE32_FLAGS) -using namespace std; - -typedef vector > DefaultBase; -typedef vector > NextCheck; +typedef std::vector > DefaultBase; +typedef std::vector > NextCheck; class CHFA { public: CHFA(void); - CHFA(DFA &dfa, map &eq, optflags const &opts, + CHFA(DFA &dfa, std::map &eq, optflags const &opts, bool permindex, bool prompt); void dump(ostream & os); void flex_table(ostream &os, optflags const &opts); - void init_free_list(vector > &free_list, + void init_free_list(std::vector > &free_list, size_t prev, size_t start); - bool fits_in(vector > &free_list, size_t base, + bool fits_in(std::vector > &free_list, size_t base, StateTrans &cases); - void insert_state(vector > &free_list, + void insert_state(std::vector > &free_list, State *state, DFA &dfa); void weld_file_to_policy(CHFA &file_chfa, size_t &new_start, bool accept_idx, bool prompt, - vector &policy_perms, - vector &file_perms); + std::vector &policy_perms, + std::vector &file_perms); // private: // sigh templates suck, friend declaration does not work so for now // make these public - vector accept; - vector accept2; + std::vector accept; + std::vector accept2; DefaultBase default_base; NextCheck next_check; const State *start; Renumber_Map num; - map eq; + std::map eq; unsigned int chfaflags; private: transchar max_eq; diff --git a/parser/libapparmor_re/expr-tree.cc b/parser/libapparmor_re/expr-tree.cc index 184d51515..420b7a37b 100644 --- a/parser/libapparmor_re/expr-tree.cc +++ b/parser/libapparmor_re/expr-tree.cc @@ -38,6 +38,8 @@ #include "expr-tree.h" #include "apparmor_re.h" +using namespace std; + /* Use a single static EpsNode as it carries no node specific information */ EpsNode epsnode; diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 995c51ecf..92a5cddbd 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -44,8 +44,6 @@ #include "../perms.h" #include "apparmor_re.h" -using namespace std; - /* * transchar - representative input character for state transitions * @@ -146,9 +144,9 @@ public: class Chars { public: - set chars; + std::set chars; - typedef set::iterator iterator; + typedef std::set::iterator iterator; iterator begin() { return chars.begin(); } iterator end() { return chars.end(); } @@ -166,11 +164,11 @@ public: { return chars.find(key); } - pair insert(transchar c) + std::pair insert(transchar c) { return chars.insert(c); } - pair insert(char c) + std::pair insert(char c) { transchar tmp(c); return chars.insert(tmp); @@ -181,9 +179,9 @@ public: ostream &operator<<(ostream &os, transchar c); /* Compute the union of two sets. */ -template set operator+(const set &a, const set &b) +template std::set operator+(const std::set &a, const std::set &b) { - set c(a); + std::set c(a); c.insert(b.begin(), b.end()); return c; } @@ -196,7 +194,7 @@ template set operator+(const set &a, const set &b) */ class Node; class ImportantNode; -typedef set NodeSet; +typedef std::set NodeSet; /** * Text-dump a state (for debugging). @@ -212,12 +210,12 @@ ostream &operator<<(ostream &os, const NodeSet &state); * enumerating all the explicit tranitions for default matches. */ typedef struct Cases { - typedef map::iterator iterator; + typedef std::map::iterator iterator; iterator begin() { return cases.begin(); } iterator end() { return cases.end(); } Cases(): otherwise(0) { } - map cases; + std::map cases; NodeSet *otherwise; } Cases; @@ -891,7 +889,7 @@ public: { type_flags |= NODE_TYPE_MATCHFLAG; } - ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << std::dec << '>'; } + ostream &dump(ostream &os) { return os << "< 0x" << std::hex << perms << std::dec << '>'; } int priority; perm32_t perms; @@ -925,7 +923,7 @@ public: /* Traverse the syntax tree depth-first in an iterator-like manner. */ class depth_first_traversal { - stackpos; + std::stackpos; void push_left(Node *node) { pos.push(node); @@ -1050,7 +1048,7 @@ struct deref_less_than { class NodeVecCache: public CacheStats { public: - set cache; + std::set cache; NodeVecCache(void): cache() { }; ~NodeVecCache() { clear(); }; @@ -1059,7 +1057,7 @@ public: void clear() { - for (set::iterator i = cache.begin(); + for (std::set::iterator i = cache.begin(); i != cache.end(); i++) { delete *i; } @@ -1071,7 +1069,7 @@ public: { if (!nodes) return NULL; - pair::iterator,bool> uniq; + std::pair::iterator,bool> uniq; NodeVec *nv = new NodeVec(nodes); uniq = cache.insert(nv); if (uniq.second == false) { diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 470b58871..f6f6db681 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -38,6 +38,8 @@ #include "../immunix.h" #include "../perms.h" +using namespace std; + ostream &operator<<(ostream &os, const CacheStats &cache) { /* dump the state label */ diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 02eb02223..966c2ad55 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -42,8 +42,8 @@ extern int prompt_compat_mode; class State; -typedef map StateTrans; -typedef list Partition; +typedef std::map StateTrans; +typedef std::list Partition; #include "../immunix.h" @@ -62,9 +62,9 @@ public: } ostream &dump(ostream &os) { - os << "(0x " << hex + os << "(0x " << std::hex << allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet - << ')' << dec; + << ')' << std::dec; return os; } @@ -317,11 +317,11 @@ public: class NodeMap: public CacheStats { public: - typedef map::iterator iterator; + typedef std::map::iterator iterator; iterator begin() { return cache.begin(); } iterator end() { return cache.end(); } - map cache; + std::map cache; NodeMap(void): cache() { }; ~NodeMap() { clear(); }; @@ -334,10 +334,10 @@ public: CacheStats::clear(); } - pair insert(ProtoState &proto, State *state) + std::pair insert(ProtoState &proto, State *state) { - pair uniq; - uniq = cache.insert(make_pair(proto, state)); + std::pair uniq; + uniq = cache.insert(std::make_pair(proto, state)); if (uniq.second == false) { dup++; } else { @@ -349,7 +349,7 @@ public: } }; -typedef map Renumber_Map; +typedef std::map Renumber_Map; /* Transitions in the DFA. */ class DFA { @@ -360,7 +360,7 @@ class DFA { NodeSet *nnodes, State *other); void update_state_transitions(optflags const &opts, State *state); void process_work_queue(const char *header, optflags const &); - void dump_diff_chain(ostream &os, map &relmap, + void dump_diff_chain(ostream &os, std::map &relmap, Partition &chain, State *state, unsigned int &count, unsigned int &total, unsigned int &max); @@ -369,7 +369,7 @@ class DFA { NodeVecCache anodes_cache; NodeVecCache nnodes_cache; NodeMap node_map; - list work_queue; + std::list work_queue; public: DFA(Node *root, optflags const &flags, bool filedfa); @@ -394,14 +394,14 @@ public: void dump_uniq_perms(const char *s); ostream &dump_partition(ostream &os, Partition &p); ostream &dump_partitions(ostream &os, const char *description, - list &partitions); - map equivalence_classes(optflags const &flags); - void apply_equivalence_classes(map &eq); + std::list &partitions); + std::map equivalence_classes(optflags const &flags); + void apply_equivalence_classes(std::map &eq); void compute_perms_table_ent(State *state, size_t pos, - vector &perms_table, + std::vector &perms_table, bool prompt); - void compute_perms_table(vector &perms_table, + void compute_perms_table(std::vector &perms_table, bool prompt); unsigned int diffcount; @@ -415,6 +415,6 @@ public: bool filedfa; }; -void dump_equivalence_classes(ostream &os, map &eq); +void dump_equivalence_classes(ostream &os, std::map &eq); #endif /* __LIBAA_RE_HFA_H */ diff --git a/parser/libapparmor_re/parse.y b/parser/libapparmor_re/parse.y index 4a89b81e0..ea4ec5c34 100644 --- a/parser/libapparmor_re/parse.y +++ b/parser/libapparmor_re/parse.y @@ -24,6 +24,8 @@ /* #define DEBUG_TREE */ #include "expr-tree.h" +using namespace std; + %} %union { diff --git a/parser/mount.cc b/parser/mount.cc index ce7df3731..a98f067fd 100644 --- a/parser/mount.cc +++ b/parser/mount.cc @@ -228,6 +228,8 @@ #include "profile.h" #include "mount.h" +using namespace std; + struct mnt_keyword_table { const char *keyword; unsigned int set; diff --git a/parser/parser.h b/parser/parser.h index 56fae71f2..005bbe580 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -41,8 +41,6 @@ #include -using namespace std; - #include diff --git a/parser/parser_interface.c b/parser/parser_interface.c index 5e4724812..8aa752164 100644 --- a/parser/parser_interface.c +++ b/parser/parser_interface.c @@ -41,6 +41,7 @@ #define SD_CODE_SIZE (sizeof(u8)) #define SD_STR_LEN (sizeof(u16)) +using namespace std; int __sd_serialize_profile(int option, aa_kernel_interface *kernel_interface, Profile *prof, int cache_fd); diff --git a/parser/parser_lex.l b/parser/parser_lex.l index 15f0bccd2..f7b3ff4db 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -46,6 +46,8 @@ #include "policy_cache.h" #include "file_cache.h" +using namespace std; + #ifdef PDEBUG #undef PDEBUG #endif diff --git a/parser/parser_misc.c b/parser/parser_misc.c index 897a21a5c..6f3f40895 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -66,6 +66,8 @@ void *reallocarray(void *ptr, size_t nmemb, size_t size) #define NULL nullptr #endif +using namespace std; + int is_blacklisted(const char *name, const char *path) { int retval = _aa_is_blacklisted(name); diff --git a/parser/parser_policy.c b/parser/parser_policy.c index 58d4fad01..7e0743f3d 100644 --- a/parser/parser_policy.c +++ b/parser/parser_policy.c @@ -45,6 +45,7 @@ #endif #define NPDEBUG(fmt, args...) /* Do nothing */ +using namespace std; ProfileList policy_list; diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 4d9c62762..21ff2d783 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -45,6 +45,7 @@ #include #include +using namespace std; #define CIDR_32 htonl(0xffffffff) #define CIDR_24 htonl(0xffffff00) diff --git a/parser/profile.cc b/parser/profile.cc index 2f235e587..52a195b9d 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -21,6 +21,8 @@ #include #include +using namespace std; + const char *profile_mode_table[] = { "", "enforce", diff --git a/parser/profile.h b/parser/profile.h index 207c9b57e..e7df0f90e 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -42,16 +42,16 @@ struct deref_profileptr_lt { class ProfileList { public: - set list; + std::set list; - typedef set::iterator iterator; + typedef std::set::iterator iterator; iterator begin() { return list.begin(); } iterator end() { return list.end(); } ProfileList() { }; virtual ~ProfileList() { clear(); } virtual bool empty(void) { return list.empty(); } - virtual pair insert(Profile *); + virtual std::pair insert(Profile *); virtual void erase(ProfileList::iterator pos); void clear(void); void dump(void); @@ -368,7 +368,7 @@ struct dfa_stuff { void *dfa; size_t size; size_t file_start; /* special start in welded dfa */ - vector perms_table; + std::vector perms_table; dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { } }; @@ -382,7 +382,7 @@ public: void *xmatch; size_t xmatch_size; int xmatch_len; - vector xmatch_perms_table; + std::vector xmatch_perms_table; struct cond_entry_list xattrs; /* char *sub_name; */ /* subdomain name or NULL */ @@ -477,7 +477,7 @@ public: debug_cod_entries(entries); for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++) { - (*i)->dump(cout); + (*i)->dump(std::cout); } printf("\n"); @@ -511,7 +511,7 @@ public: void dump_name(bool fqp) { - cout << get_name(fqp);; + std::cout << get_name(fqp);; } void post_parse_profile(void); diff --git a/parser/rule.h b/parser/rule.h index 64a5f471c..b26262ec2 100644 --- a/parser/rule.h +++ b/parser/rule.h @@ -25,8 +25,6 @@ #include "perms.h" #include "policydb.h" -using namespace std; - #define PROMPT_COMPAT_UNKNOWN 0 #define PROMPT_COMPAT_IGNORE 1 #define PROMPT_COMPAT_PERMSV2 2 @@ -436,9 +434,9 @@ public: class_rule_t::dump(os); if (saved) - os << "(0x" << hex << perms << "/orig " << saved << ") "; + os << "(0x" << std::hex << perms << "/orig " << saved << ") "; else - os << "(0x" << hex << perms << ") "; + os << "(0x" << std::hex << perms << ") "; return os; } @@ -464,7 +462,7 @@ public: virtual ostream &dump(ostream &os) { class_rule_t::dump(os); - os << "(0x" << hex << perms << ") "; + os << "(0x" << std::hex << perms << ") "; return os; } diff --git a/parser/signal.cc b/parser/signal.cc index 81502509b..514a5a182 100644 --- a/parser/signal.cc +++ b/parser/signal.cc @@ -30,6 +30,8 @@ #include "parser_yacc.h" #include "signal.h" +using namespace std; + #define MAXMAPPED_SIG 35 #define MINRT_SIG 128 /* base of RT sigs */ #define MAXRT_SIG 32 /* Max RT above MINRT_SIG */ diff --git a/parser/signal.h b/parser/signal.h index a670eb2c3..3524f70ff 100644 --- a/parser/signal.h +++ b/parser/signal.h @@ -29,7 +29,7 @@ #define AA_VALID_SIGNAL_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE) -typedef set Signals; +typedef std::set Signals; int find_signal_mapping(const char *sig); int parse_signal_perms(const char *str_perms, perm32_t *perms, int fail); From 9c6ae3cf5ce3b058e9052b53fdc1374ce65a98ae Mon Sep 17 00:00:00 2001 From: Eisuke Kawashima <2618741-e-kwsm@users.noreply.gitlab.com> Date: Sun, 4 May 2025 23:47:29 +0900 Subject: [PATCH 03/11] refactor(bison): replace deprecated `name-prefix` with `%define api.prefix` %name-prefix is deprecated in Bison 2.6. https://savannah.gnu.org/news/?id=7269 --- parser/libapparmor_re/parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/libapparmor_re/parse.y b/parser/libapparmor_re/parse.y index 4a89b81e0..e86370141 100644 --- a/parser/libapparmor_re/parse.y +++ b/parser/libapparmor_re/parse.y @@ -60,7 +60,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b) %lex-param {YYLEX_PARAM} %parse-param {Node **root} %parse-param {const char *text} -%name-prefix "regex_" +%define api.prefix {regex_} %token CHAR %type regex_char cset_char1 cset_char cset_charN From 17ee87ad6b678f514eabc900aece9b05241b85bf Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 5 May 2025 10:12:29 -0700 Subject: [PATCH 04/11] parser: fix if condition at the bottom of equality.sh The lack of a space after $testtype is a syntax error and was causing the equality tests on Ubuntu Xenial to be silently skipped and marked PASS. Signed-off-by: Ryan Lee --- parser/tst/equality.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser/tst/equality.sh b/parser/tst/equality.sh index 6f4ee6082..f0b90379b 100755 --- a/parser/tst/equality.sh +++ b/parser/tst/equality.sh @@ -1223,7 +1223,7 @@ done set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters -if [ $# -eq 0 -o -z $testtype] ; then +if [ $# -eq 0 -o -z "$testtype" ] ; then run_tests "$@" exit $? fi From 3389230437570a47927d87c82902c37f63c41c45 Mon Sep 17 00:00:00 2001 From: Georgia Garcia Date: Mon, 21 Apr 2025 17:32:24 -0300 Subject: [PATCH 05/11] utils: add allow keyword to list of unsupported modifiers Some classes don't support modifiers like audit and deny. Only rlimit has been checking for the allow keyword, but the others shouldn't support it as well. Since they all do the same check, refactor them into a method from BaseRule in case more modifiers are added. Signed-off-by: Georgia Garcia --- utils/apparmor/rule/__init__.py | 8 ++++++++ utils/apparmor/rule/alias.py | 7 ++----- utils/apparmor/rule/boolean.py | 7 ++----- utils/apparmor/rule/include.py | 7 ++----- utils/apparmor/rule/rlimit.py | 4 ++-- utils/apparmor/rule/variable.py | 7 ++----- 6 files changed, 18 insertions(+), 22 deletions(-) diff --git a/utils/apparmor/rule/__init__.py b/utils/apparmor/rule/__init__.py index d0fdf80bc..c25f34747 100644 --- a/utils/apparmor/rule/__init__.py +++ b/utils/apparmor/rule/__init__.py @@ -334,6 +334,14 @@ class BaseRule(metaclass=ABCMeta): return '%s%s' % (auditstr, allowstr) + def ensure_modifiers_not_supported(self): + if self.audit: + raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) + if self.deny: + raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) + if self.allow_keyword: + raise AppArmorBug('Attempt to initialize %s with allow keyword' % self.__class__.__name__) + class BaseRuleset: """Base class to handle and store a collection of rules""" diff --git a/utils/apparmor/rule/alias.py b/utils/apparmor/rule/alias.py index aca4c530a..952d1ba09 100644 --- a/utils/apparmor/rule/alias.py +++ b/utils/apparmor/rule/alias.py @@ -32,11 +32,8 @@ class AliasRule(BaseRule): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) - # aliases don't support audit or deny - if audit: - raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) - if deny: - raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) + # aliases don't support allow keyword, audit or deny + self.ensure_modifiers_not_supported() if not isinstance(orig_path, str): raise AppArmorBug('Passed unknown type for orig_path to %s: %s' % (self.__class__.__name__, orig_path)) diff --git a/utils/apparmor/rule/boolean.py b/utils/apparmor/rule/boolean.py index 7d24ddda7..c2f877907 100644 --- a/utils/apparmor/rule/boolean.py +++ b/utils/apparmor/rule/boolean.py @@ -33,11 +33,8 @@ class BooleanRule(BaseRule): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) - # boolean variables don't support audit or deny - if audit: - raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) - if deny: - raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) + # boolean variables don't support allow keyword, audit or deny + self.ensure_modifiers_not_supported() if not isinstance(varname, str): raise AppArmorBug('Passed unknown type for boolean variable to %s: %s' % (self.__class__.__name__, varname)) diff --git a/utils/apparmor/rule/include.py b/utils/apparmor/rule/include.py index 6ade58874..02ee86349 100644 --- a/utils/apparmor/rule/include.py +++ b/utils/apparmor/rule/include.py @@ -33,11 +33,8 @@ class IncludeRule(BaseRule): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) - # include doesn't support audit or deny - if audit: - raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) - if deny: - raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) + # include doesn't support allow keyword, audit or deny + self.ensure_modifiers_not_supported() if not isinstance(ifexists, bool): raise AppArmorBug('Passed unknown type for ifexists to %s: %s' % (self.__class__.__name__, ifexists)) diff --git a/utils/apparmor/rule/rlimit.py b/utils/apparmor/rule/rlimit.py index 4bc810563..12888cb82 100644 --- a/utils/apparmor/rule/rlimit.py +++ b/utils/apparmor/rule/rlimit.py @@ -54,8 +54,8 @@ class RlimitRule(BaseRule): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) - if audit or deny or allow_keyword: - raise AppArmorBug('The audit, allow or deny keywords are not allowed in rlimit rules.') + # rlimit rules don't support allow keyword, audit or deny + self.ensure_modifiers_not_supported() if isinstance(rlimit, str): if rlimit in rlimit_all: diff --git a/utils/apparmor/rule/variable.py b/utils/apparmor/rule/variable.py index 52d63dd95..85ce31263 100644 --- a/utils/apparmor/rule/variable.py +++ b/utils/apparmor/rule/variable.py @@ -35,11 +35,8 @@ class VariableRule(BaseRule): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, log_event=log_event) - # variables don't support audit or deny - if audit: - raise AppArmorBug('Attempt to initialize %s with audit flag' % self.__class__.__name__) - if deny: - raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) + # variables don't support allow keyword, audit or deny + self.ensure_modifiers_not_supported() if not isinstance(varname, str): raise AppArmorBug('Passed unknown type for varname to %s: %s' % (self.__class__.__name__, varname)) From c0fcd1698b2562f4c7cbfb3eda0c8c818b37ac57 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 9 Feb 2025 04:35:52 -0800 Subject: [PATCH 06/11] utils: add support for priority rule prefix Add basic support for the priority rules prefix. This patch does not allow the utils to set or suggest priorities. It allows parsing and retaining of the priority prefix if it already exists on rules and checking if it's in the supported range. Signed-off-by: Georgia Garcia Signed-off-by: John Johansen --- utils/apparmor/regex.py | 30 ++--- utils/apparmor/rule/__init__.py | 48 +++++++- utils/apparmor/rule/abi.py | 4 +- utils/apparmor/rule/alias.py | 8 +- utils/apparmor/rule/all.py | 8 +- utils/apparmor/rule/boolean.py | 8 +- utils/apparmor/rule/capability.py | 8 +- utils/apparmor/rule/change_profile.py | 8 +- utils/apparmor/rule/dbus.py | 9 +- utils/apparmor/rule/file.py | 8 +- utils/apparmor/rule/include.py | 8 +- utils/apparmor/rule/io_uring.py | 8 +- utils/apparmor/rule/mount.py | 13 +- utils/apparmor/rule/mqueue.py | 9 +- utils/apparmor/rule/network.py | 8 +- utils/apparmor/rule/pivot_root.py | 9 +- utils/apparmor/rule/ptrace.py | 8 +- utils/apparmor/rule/rlimit.py | 6 +- utils/apparmor/rule/signal.py | 8 +- utils/apparmor/rule/unix.py | 11 +- utils/apparmor/rule/userns.py | 9 +- utils/apparmor/rule/variable.py | 8 +- utils/test/test-alias.py | 11 +- utils/test/test-all.py | 1 + utils/test/test-baserule.py | 2 +- utils/test/test-boolean.py | 11 +- utils/test/test-capability.py | 12 ++ utils/test/test-change_profile.py | 4 + utils/test/test-dbus.py | 4 + utils/test/test-file.py | 46 ++++--- utils/test/test-include.py | 5 + utils/test/test-io_uring.py | 8 +- utils/test/test-modifiers.py | 90 ++++++++++++++ utils/test/test-mount.py | 10 +- utils/test/test-mqueue.py | 8 +- utils/test/test-network.py | 4 + utils/test/test-parser-simple-tests.py | 13 +- utils/test/test-pivot_root.py | 4 + utils/test/test-ptrace.py | 4 + utils/test/test-regex_matches.py | 158 +++++++++++++++++-------- utils/test/test-rlimit.py | 4 + utils/test/test-signal.py | 4 + utils/test/test-unix.py | 21 ++-- utils/test/test-userns.py | 8 +- utils/test/test-variable.py | 11 +- 45 files changed, 501 insertions(+), 186 deletions(-) create mode 100644 utils/test/test-modifiers.py diff --git a/utils/apparmor/regex.py b/utils/apparmor/regex.py index 256b5acb1..535918b17 100644 --- a/utils/apparmor/regex.py +++ b/utils/apparmor/regex.py @@ -21,7 +21,7 @@ from apparmor.translations import init_translation _ = init_translation() # Profile parsing Regex -RE_AUDIT_DENY = r'^\s*(?Paudit\s+)?(?Pallow\s+|deny\s+)?' # line start, optionally: leading whitespace, and /deny +RE_PRIORITY_AUDIT_DENY = r'^\s*(priority\s*=\s*(?P[+-]?[0-9]*)\s+)?(?Paudit\s+)?(?Pallow\s+|deny\s+)?' # line start, optionally: leading whitespace, = number, and /deny RE_EOL = r'\s*(?P#.*?)?\s*$' # optional whitespace, optional , optional whitespace, end of the line RE_COMMA_EOL = r'\s*,' + RE_EOL # optional whitespace, comma + RE_EOL @@ -34,8 +34,8 @@ RE_XATTRS = r'(\s+xattrs\s*=\s*\((?P([^)=]+(=[^)=]+)?\s?)+)\)\s*)?' RE_FLAGS = r'(\s+(flags\s*=\s*)?\((?P[^)]+)\))?' RE_PROFILE_END = re.compile(r'^\s*\}' + RE_EOL) -RE_PROFILE_ALL = re.compile(RE_AUDIT_DENY + r'all' + RE_COMMA_EOL) -RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + r'capability(?P(\s+\S+)+)?' + RE_COMMA_EOL) +RE_PROFILE_ALL = re.compile(RE_PRIORITY_AUDIT_DENY + r'all' + RE_COMMA_EOL) +RE_PROFILE_CAP = re.compile(RE_PRIORITY_AUDIT_DENY + r'capability(?P(\s+\S+)+)?' + RE_COMMA_EOL) RE_PROFILE_ALIAS = re.compile(r'^\s*alias\s+(?P"??.+?"??)\s+->\s*(?P"??.+?"??)' + RE_COMMA_EOL) RE_PROFILE_RLIMIT = re.compile(r'^\s*set\s+rlimit\s+(?P[a-z]+)\s*<=\s*(?P[^ ]+(\s+[a-zA-Z]+)?)' + RE_COMMA_EOL) RE_PROFILE_BOOLEAN = re.compile(r'^\s*(?P\$\{?\w*\}?)\s*=\s*(?Ptrue|false)\s*,?' + RE_EOL, flags=re.IGNORECASE) @@ -43,18 +43,18 @@ RE_PROFILE_VARIABLE = re.compile(r'^\s*(?P@\{?\w+\}?)\s*(?P\+?=)\ RE_PROFILE_CONDITIONAL = re.compile(r'^\s*if\s+(not\s+)?(\$\{?\w*\}?)\s*\{' + RE_EOL) RE_PROFILE_CONDITIONAL_VARIABLE = re.compile(r'^\s*if\s+(not\s+)?defined\s+(@\{?\w+\}?)\s*\{\s*(#.*)?$') RE_PROFILE_CONDITIONAL_BOOLEAN = re.compile(r'^\s*if\s+(not\s+)?defined\s+(\$\{?\w+\}?)\s*\{\s*(#.*)?$') -RE_PROFILE_NETWORK = re.compile(RE_AUDIT_DENY + r'network(?P
\s+.*)?' + RE_COMMA_EOL) +RE_PROFILE_NETWORK = re.compile(RE_PRIORITY_AUDIT_DENY + r'network(?P
\s+.*)?' + RE_COMMA_EOL) RE_PROFILE_CHANGE_HAT = re.compile(r'^\s*\^("??.+?"??)' + RE_COMMA_EOL) RE_PROFILE_HAT_DEF = re.compile(r'^(?P\s*)(?P\^|hat\s+)(?P"??[^)]+?"??)' + RE_FLAGS + r'\s*\{' + RE_EOL) -RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + r'(dbus\s*,|dbus(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + r'((?Pmount|remount|umount|unmount)(?P
\s+[^#]*)?\s*,)' + RE_EOL) -RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + r'(signal\s*,|signal(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_PTRACE = re.compile(RE_AUDIT_DENY + r'(ptrace\s*,|ptrace(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_PIVOT_ROOT = re.compile(RE_AUDIT_DENY + r'(pivot_root\s*,|pivot_root(?P
\s+[^#]*),)' + RE_EOL) -RE_PROFILE_UNIX = re.compile(RE_AUDIT_DENY + r'(unix\s*,|unix(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_USERNS = re.compile(RE_AUDIT_DENY + r'(userns\s*,|userns(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_MQUEUE = re.compile(RE_AUDIT_DENY + r'(mqueue\s*,|mqueue(?P
\s+[^#]*)\s*,)' + RE_EOL) -RE_PROFILE_IO_URING = re.compile(RE_AUDIT_DENY + r'(io_uring\s*,|io_uring(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_DBUS = re.compile(RE_PRIORITY_AUDIT_DENY + r'(dbus\s*,|dbus(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_MOUNT = re.compile(RE_PRIORITY_AUDIT_DENY + r'((?Pmount|remount|umount|unmount)(?P
\s+[^#]*)?\s*,)' + RE_EOL) +RE_PROFILE_SIGNAL = re.compile(RE_PRIORITY_AUDIT_DENY + r'(signal\s*,|signal(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_PTRACE = re.compile(RE_PRIORITY_AUDIT_DENY + r'(ptrace\s*,|ptrace(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_PIVOT_ROOT = re.compile(RE_PRIORITY_AUDIT_DENY + r'(pivot_root\s*,|pivot_root(?P
\s+[^#]*),)' + RE_EOL) +RE_PROFILE_UNIX = re.compile(RE_PRIORITY_AUDIT_DENY + r'(unix\s*,|unix(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_USERNS = re.compile(RE_PRIORITY_AUDIT_DENY + r'(userns\s*,|userns(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_MQUEUE = re.compile(RE_PRIORITY_AUDIT_DENY + r'(mqueue\s*,|mqueue(?P
\s+[^#]*)\s*,)' + RE_EOL) +RE_PROFILE_IO_URING = re.compile(RE_PRIORITY_AUDIT_DENY + r'(io_uring\s*,|io_uring(?P
\s+[^#]*)\s*,)' + RE_EOL) # match anything that's not " or #, or matching quotes with anything except quotes inside __re_no_or_quoted_hash = '([^#"]|"[^"]*")*' @@ -81,7 +81,7 @@ RE_PROFILE_START = re.compile( RE_PROFILE_CHANGE_PROFILE = re.compile( - RE_AUDIT_DENY + RE_PRIORITY_AUDIT_DENY + 'change_profile' + r'(\s+' + RE_SAFE_OR_UNSAFE + ')?' # optionally exec mode + r'(\s+' + RE_PROFILE_PATH_OR_VAR % 'execcond' + ')?' # optionally exec condition @@ -94,7 +94,7 @@ RE_PROFILE_CHANGE_PROFILE = re.compile( RE_PATH_PERMS = '(?P<%s>[mrwalkPUCpucix]+)' RE_PROFILE_FILE_ENTRY = re.compile( - RE_AUDIT_DENY + RE_PRIORITY_AUDIT_DENY + r'(?Powner\s+)?' # optionally: + '(' + '(?Pfile)' # bare 'file,' # noqa: E131 diff --git a/utils/apparmor/rule/__init__.py b/utils/apparmor/rule/__init__.py index c25f34747..8484efecd 100644 --- a/utils/apparmor/rule/__init__.py +++ b/utils/apparmor/rule/__init__.py @@ -41,8 +41,10 @@ class BaseRule(metaclass=ABCMeta): _match_re = None def __init__(self, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): """initialize variables needed by all rule types""" + + self._store_priority(priority) self.audit = audit self.deny = deny self.allow_keyword = allow_keyword @@ -52,6 +54,21 @@ class BaseRule(metaclass=ABCMeta): # Set only in the parse() class method self.raw_rule = None + def _store_priority(self, priority): + if priority is None: # default priority + self.priority = None + return + + try: + ipriority = int(priority) + except ValueError: + raise AppArmorException("Invalid value for priority '%s'" % priority) + + if ipriority < -1000 or ipriority > 1000: + raise AppArmorException('priority %d out of range' % (ipriority)) + + self.priority = ipriority + def _aare_or_all(self, rulepart, partname, is_path, log_event, empty_ok=False): """checks rulepart and returns - (AARE, False) if rulepart is a (non-empty) string @@ -233,7 +250,9 @@ class BaseRule(metaclass=ABCMeta): """compare if rule_obj == self Calls _is_equal_localvars() to compare rule-specific variables""" - if self.audit != rule_obj.audit or self.deny != rule_obj.deny: + if (self.priority != rule_obj.priority + or self.audit != rule_obj.audit + or self.deny != rule_obj.deny): return False if strict and ( @@ -282,6 +301,9 @@ class BaseRule(metaclass=ABCMeta): headers = [] qualifier = [] + if self.priority: + qualifier.append('priority=%s' % self.priority) + if self.audit: qualifier.append('audit') @@ -318,7 +340,12 @@ class BaseRule(metaclass=ABCMeta): raise NotImplementedError("'%s' needs to implement store_edit(), but didn't" % (str(self))) def modifiers_str(self): - """return the allow/deny and audit keyword as string, including whitespace""" + """return priority, allow/deny, and audit keyword as string, including whitespace""" + + if self.priority is not None: + prioritystr = 'priority=%s ' % self.priority + else: + prioritystr = '' if self.audit: auditstr = 'audit ' @@ -332,7 +359,7 @@ class BaseRule(metaclass=ABCMeta): else: allowstr = '' - return '%s%s' % (auditstr, allowstr) + return '%s%s%s' % (prioritystr, auditstr, allowstr) def ensure_modifiers_not_supported(self): if self.audit: @@ -341,6 +368,8 @@ class BaseRule(metaclass=ABCMeta): raise AppArmorBug('Attempt to initialize %s with deny flag' % self.__class__.__name__) if self.allow_keyword: raise AppArmorBug('Attempt to initialize %s with allow keyword' % self.__class__.__name__) + if self.priority is not None: + raise AppArmorBug('Attempt to initialize %s with priority' % self.__class__.__name__) class BaseRuleset: @@ -573,9 +602,16 @@ def parse_comment(matches): def parse_modifiers(matches): - """returns audit, deny, allow_keyword and comment from the matches object + """returns priority, audit, deny, allow_keyword and comment from the + matches object + - priority is a number or None - audit, deny and allow_keyword are True/False - comment is the comment with a leading space""" + + priority = None + if matches.group('priority'): + priority = int(matches.group('priority')) + audit = False if matches.group('audit'): audit = True @@ -594,7 +630,7 @@ def parse_modifiers(matches): comment = parse_comment(matches) - return (audit, deny, allow_keyword, comment) + return (priority, audit, deny, allow_keyword, comment) def quote_if_needed(data): diff --git a/utils/apparmor/rule/abi.py b/utils/apparmor/rule/abi.py index 586db8428..d7bd974a5 100644 --- a/utils/apparmor/rule/abi.py +++ b/utils/apparmor/rule/abi.py @@ -29,11 +29,11 @@ class AbiRule(IncludeRule): _match_re = RE_ABI def __init__(self, path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(path, ifexists, ismagic, audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) # abi doesn't support 'if exists' if ifexists: diff --git a/utils/apparmor/rule/alias.py b/utils/apparmor/rule/alias.py index 952d1ba09..d0fd440d6 100644 --- a/utils/apparmor/rule/alias.py +++ b/utils/apparmor/rule/alias.py @@ -27,12 +27,12 @@ class AliasRule(BaseRule): _match_re = RE_PROFILE_ALIAS def __init__(self, orig_path, target, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) - # aliases don't support allow keyword, audit or deny + # aliases don't support priority, allow keyword, audit or deny self.ensure_modifiers_not_supported() if not isinstance(orig_path, str): @@ -62,7 +62,7 @@ class AliasRule(BaseRule): target = strip_quotes(matches.group('target').strip()) return cls(orig_path, target, - audit=False, deny=False, allow_keyword=False, comment=comment) + audit=False, deny=False, allow_keyword=False, comment=comment, priority=None) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/all.py b/utils/apparmor/rule/all.py index 4a859cfcc..b60781ed2 100644 --- a/utils/apparmor/rule/all.py +++ b/utils/apparmor/rule/all.py @@ -29,10 +29,10 @@ class AllRule(BaseRule): _match_re = RE_PROFILE_ALL def __init__(self, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) # no localvars -> nothing more to do @@ -40,11 +40,11 @@ class AllRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) return cls(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment) + comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/boolean.py b/utils/apparmor/rule/boolean.py index c2f877907..ec1b901e8 100644 --- a/utils/apparmor/rule/boolean.py +++ b/utils/apparmor/rule/boolean.py @@ -28,12 +28,12 @@ class BooleanRule(BaseRule): _match_re = RE_PROFILE_BOOLEAN def __init__(self, varname, value, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) - # boolean variables don't support allow keyword, audit or deny + # boolean variables don't support priority, allow keyword, audit or deny self.ensure_modifiers_not_supported() if not isinstance(varname, str): @@ -63,7 +63,7 @@ class BooleanRule(BaseRule): value = matches.group('value') return cls(varname, value, - audit=False, deny=False, allow_keyword=False, comment=comment) + audit=False, deny=False, allow_keyword=False, comment=comment, priority=None) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/capability.py b/utils/apparmor/rule/capability.py index ce00eb839..0a21c6caf 100644 --- a/utils/apparmor/rule/capability.py +++ b/utils/apparmor/rule/capability.py @@ -46,10 +46,10 @@ class CapabilityRule(BaseRule): _match_re = RE_PROFILE_CAP def __init__(self, cap_list, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) # Because we support having multiple caps in one rule, # initializer needs to accept a list of caps. self.all_caps = False @@ -78,7 +78,7 @@ class CapabilityRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) if matches.group('capability'): capability = matches.group('capability').strip() @@ -88,7 +88,7 @@ class CapabilityRule(BaseRule): return cls(capability, audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment) + comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/change_profile.py b/utils/apparmor/rule/change_profile.py index 70858891b..3f3722009 100644 --- a/utils/apparmor/rule/change_profile.py +++ b/utils/apparmor/rule/change_profile.py @@ -37,11 +37,11 @@ class ChangeProfileRule(BaseRule): _match_re = RE_PROFILE_CHANGE_PROFILE def __init__(self, execmode, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): """CHANGE_PROFILE RULE = 'change_profile' [ [ EXEC MODE ] EXEC COND ] [ -> PROGRAMCHILD ]""" super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) if execmode: if execmode != 'safe' and execmode != 'unsafe': @@ -80,7 +80,7 @@ class ChangeProfileRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) execmode = matches.group('execmode') @@ -95,7 +95,7 @@ class ChangeProfileRule(BaseRule): targetprofile = cls.ALL return cls(execmode, execcond, targetprofile, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/dbus.py b/utils/apparmor/rule/dbus.py index 4a6fd5293..e493601c6 100644 --- a/utils/apparmor/rule/dbus.py +++ b/utils/apparmor/rule/dbus.py @@ -80,10 +80,10 @@ class DbusRule(BaseRule): _match_re = RE_PROFILE_DBUS def __init__(self, access, bus, path, name, interface, member, peername, peerlabel, - audit=False, deny=False, allow_keyword=False, comment='', log_event=None): + audit=False, deny=False, allow_keyword=False, comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access') if unknown_items: @@ -112,7 +112,7 @@ class DbusRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -186,7 +186,8 @@ class DbusRule(BaseRule): peerlabel = cls.ALL return cls(access, bus, path, name, interface, member, peername, peerlabel, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, + priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/file.py b/utils/apparmor/rule/file.py index 6a92a82da..17537e6d2 100644 --- a/utils/apparmor/rule/file.py +++ b/utils/apparmor/rule/file.py @@ -47,7 +47,7 @@ class FileRule(BaseRule): _match_re = RE_PROFILE_FILE_ENTRY def __init__(self, path, perms, exec_perms, target, owner, file_keyword=False, leading_perms=False, - audit=False, deny=False, allow_keyword=False, comment='', log_event=None): + audit=False, deny=False, allow_keyword=False, comment='', log_event=None, priority=None): """Initialize object Parameters: @@ -61,7 +61,7 @@ class FileRule(BaseRule): """ super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) # rulepart partperms is_path log_event self.path, self.all_paths = self._aare_or_all(path, 'path', True, log_event) # noqa: E221 @@ -138,7 +138,7 @@ class FileRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) owner = bool(matches.group('owner')) @@ -183,7 +183,7 @@ class FileRule(BaseRule): file_keyword = bool(matches.group('file_keyword')) return cls(path, perms, exec_perms, target, owner, file_keyword, leading_perms, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/include.py b/utils/apparmor/rule/include.py index 02ee86349..f786b13fd 100644 --- a/utils/apparmor/rule/include.py +++ b/utils/apparmor/rule/include.py @@ -28,12 +28,12 @@ class IncludeRule(BaseRule): _match_re = RE_INCLUDE def __init__(self, path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) - # include doesn't support allow keyword, audit or deny + # include doesn't support priority, allow keyword, audit or deny self.ensure_modifiers_not_supported() if not isinstance(ifexists, bool): @@ -59,7 +59,7 @@ class IncludeRule(BaseRule): path, ifexists, ismagic = re_match_include_parse(raw_rule, cls.rule_name) return cls(path, ifexists, ismagic, - audit=False, deny=False, allow_keyword=False, comment=comment) + audit=False, deny=False, allow_keyword=False, comment=comment, priority=None) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/io_uring.py b/utils/apparmor/rule/io_uring.py index 599f99e86..da88078c7 100644 --- a/utils/apparmor/rule/io_uring.py +++ b/utils/apparmor/rule/io_uring.py @@ -51,12 +51,12 @@ class IOUringRule(BaseRule): _match_re = RE_PROFILE_IO_URING def __init__(self, access, label, audit=False, deny=False, - allow_keyword=False, comment='', log_event=None): + allow_keyword=False, comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, priority=priority) self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access') if unknown_items: @@ -68,7 +68,7 @@ class IOUringRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -96,7 +96,7 @@ class IOUringRule(BaseRule): label = cls.ALL return cls(access, label, audit=audit, deny=deny, - allow_keyword=allow_keyword, comment=comment) + allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): '''return rule (in clean/default formatting)''' diff --git a/utils/apparmor/rule/mount.py b/utils/apparmor/rule/mount.py index 479f9ce3c..7bb3c8e01 100644 --- a/utils/apparmor/rule/mount.py +++ b/utils/apparmor/rule/mount.py @@ -112,12 +112,15 @@ class MountRule(BaseRule): rule_name = 'mount' _match_re = RE_PROFILE_MOUNT - def __init__(self, operation, fstype, options, source, dest, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): + def __init__(self, operation, fstype, options, source, dest, + audit=False, deny=False, allow_keyword=False, + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, + priority=priority) self.operation = operation @@ -164,7 +167,7 @@ class MountRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) operation = matches.group('operation') @@ -223,7 +226,9 @@ class MountRule(BaseRule): source = cls.ALL dest = cls.ALL - return cls(operation=operation, fstype=(is_fstype_equal, fstype), options=(is_options_equal, options), source=source, dest=dest, audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + return cls(operation=operation, fstype=(is_fstype_equal, fstype), options=(is_options_equal, options), + source=source, dest=dest, audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, + priority=priority) def get_clean(self, depth=0): space = ' ' * depth diff --git a/utils/apparmor/rule/mqueue.py b/utils/apparmor/rule/mqueue.py index eca5fa36e..10c397dc3 100644 --- a/utils/apparmor/rule/mqueue.py +++ b/utils/apparmor/rule/mqueue.py @@ -62,12 +62,13 @@ class MessageQueueRule(BaseRule): def __init__(self, access, mqueue_type, label, mqueue_name, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, + priority=priority) self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access') if unknown_items: @@ -92,7 +93,7 @@ class MessageQueueRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -132,7 +133,7 @@ class MessageQueueRule(BaseRule): mqueue_name = cls.ALL return cls(access, mqueue_type, label, mqueue_name, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): '''return rule (in clean/default formatting)''' diff --git a/utils/apparmor/rule/network.py b/utils/apparmor/rule/network.py index f788e1b9c..9239b6836 100644 --- a/utils/apparmor/rule/network.py +++ b/utils/apparmor/rule/network.py @@ -92,10 +92,10 @@ class NetworkRule(BaseRule): _match_re = RE_PROFILE_NETWORK def __init__(self, accesses, domain, type_or_protocol, local_expr, peer_expr, audit=False, deny=False, - allow_keyword=False, comment='', log_event=None): + allow_keyword=False, comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) if type(local_expr) is tuple: if accesses is None: @@ -159,7 +159,7 @@ class NetworkRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -191,7 +191,7 @@ class NetworkRule(BaseRule): peer_expr = cls.ALL return cls(accesses, domain, type_or_protocol, local_expr, peer_expr, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/pivot_root.py b/utils/apparmor/rule/pivot_root.py index 06f951d0a..d270c1d49 100644 --- a/utils/apparmor/rule/pivot_root.py +++ b/utils/apparmor/rule/pivot_root.py @@ -47,12 +47,13 @@ class PivotRootRule(BaseRule): _match_re = RE_PROFILE_PIVOT_ROOT # PIVOT ROOT RULE = [ QUALIFIERS ] pivot_root [ oldroot=OLD PUT FILEGLOB ] [ NEW ROOT FILEGLOB ] [ ’->’ PROFILE NAME ] - def __init__(self, oldroot, newroot, profile_name, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): + def __init__(self, oldroot, newroot, profile_name, audit=False, deny=False, allow_keyword=False, + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, priority=priority) self.oldroot, self.all_oldroots = self._aare_or_all(oldroot, 'oldroot', True, log_event) # noqa: E221 self.newroot, self.all_newroots = self._aare_or_all(newroot, 'newroot', True, log_event) # noqa: E221 @@ -66,7 +67,7 @@ class PivotRootRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -100,7 +101,7 @@ class PivotRootRule(BaseRule): profile_name = cls.ALL return cls(oldroot=oldroot, newroot=newroot, profile_name=profile_name, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): space = ' ' * depth diff --git a/utils/apparmor/rule/ptrace.py b/utils/apparmor/rule/ptrace.py index 8ec41f1a0..4b0584023 100644 --- a/utils/apparmor/rule/ptrace.py +++ b/utils/apparmor/rule/ptrace.py @@ -53,10 +53,10 @@ class PtraceRule(BaseRule): _match_re = RE_PROFILE_PTRACE def __init__(self, access, peer, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) self.access, self.all_access, unknown_items = check_and_split_list( access, access_keywords, self.ALL, type(self).__name__, 'access') @@ -69,7 +69,7 @@ class PtraceRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -98,7 +98,7 @@ class PtraceRule(BaseRule): peer = cls.ALL return cls(access, peer, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/rlimit.py b/utils/apparmor/rule/rlimit.py index 12888cb82..a4d8c8386 100644 --- a/utils/apparmor/rule/rlimit.py +++ b/utils/apparmor/rule/rlimit.py @@ -49,12 +49,12 @@ class RlimitRule(BaseRule): _match_re = RE_PROFILE_RLIMIT def __init__(self, rlimit, value, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) - # rlimit rules don't support allow keyword, audit or deny + # rlimit rules don't support priority, allow keyword, audit or deny self.ensure_modifiers_not_supported() if isinstance(rlimit, str): diff --git a/utils/apparmor/rule/signal.py b/utils/apparmor/rule/signal.py index e803ec223..4cf159f8d 100644 --- a/utils/apparmor/rule/signal.py +++ b/utils/apparmor/rule/signal.py @@ -78,10 +78,10 @@ class SignalRule(BaseRule): _match_re = RE_PROFILE_SIGNAL def __init__(self, access, signal, peer, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) self.access, self.all_access, unknown_items = check_and_split_list( access, access_keywords, self.ALL, type(self).__name__, 'access') @@ -103,7 +103,7 @@ class SignalRule(BaseRule): def _create_instance(cls, raw_rule, matches): """parse raw_rule and return instance of this class""" - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -141,7 +141,7 @@ class SignalRule(BaseRule): peer = cls.ALL return cls(access, signal, peer, - audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/apparmor/rule/unix.py b/utils/apparmor/rule/unix.py index 8be505995..e7675070b 100644 --- a/utils/apparmor/rule/unix.py +++ b/utils/apparmor/rule/unix.py @@ -65,12 +65,14 @@ class UnixRule(BaseRule): rule_name = 'unix' _match_re = RE_PROFILE_UNIX - def __init__(self, accesses, rule_conds, local_expr, peer_expr, audit=False, deny=False, allow_keyword=False, comment='', log_event=None): + def __init__(self, accesses, rule_conds, local_expr, peer_expr, audit=False, deny=False, allow_keyword=False, + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, + priority=priority) if type(rule_conds) is tuple: # This comes from the logparser, we convert it to dicts accesses = strip_parenthesis(accesses).replace(',', ' ').split() @@ -96,7 +98,7 @@ class UnixRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -124,7 +126,8 @@ class UnixRule(BaseRule): local_expr = cls.ALL peer_expr = cls.ALL - return cls(accesses=accesses, rule_conds=rule_conds, local_expr=local_expr, peer_expr=peer_expr, audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment) + return cls(accesses=accesses, rule_conds=rule_conds, local_expr=local_expr, peer_expr=peer_expr, + audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, priority=priority) def get_clean(self, depth=0): space = ' ' * depth diff --git a/utils/apparmor/rule/userns.py b/utils/apparmor/rule/userns.py index 2fc1df89b..5e3623463 100644 --- a/utils/apparmor/rule/userns.py +++ b/utils/apparmor/rule/userns.py @@ -44,12 +44,13 @@ class UserNamespaceRule(BaseRule): _match_re = RE_PROFILE_USERNS def __init__(self, access, audit=False, deny=False, - allow_keyword=False, comment='', log_event=None): + allow_keyword=False, comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, comment=comment, - log_event=log_event) + log_event=log_event, + priority=priority) self.access, self.all_access, unknown_items = check_and_split_list(access, access_keyword, self.ALL, type(self).__name__, 'access') if unknown_items: @@ -59,7 +60,7 @@ class UserNamespaceRule(BaseRule): def _create_instance(cls, raw_rule, matches): '''parse raw_rule and return instance of this class''' - audit, deny, allow_keyword, comment = parse_modifiers(matches) + priority, audit, deny, allow_keyword, comment = parse_modifiers(matches) rule_details = '' if matches.group('details'): @@ -75,7 +76,7 @@ class UserNamespaceRule(BaseRule): access = cls.ALL return cls(access, audit=audit, deny=deny, - allow_keyword=allow_keyword, comment=comment) + allow_keyword=allow_keyword, comment=comment, priority=priority) @staticmethod def hashlog_from_event(hl, e): diff --git a/utils/apparmor/rule/variable.py b/utils/apparmor/rule/variable.py index 85ce31263..a88fc42de 100644 --- a/utils/apparmor/rule/variable.py +++ b/utils/apparmor/rule/variable.py @@ -30,12 +30,12 @@ class VariableRule(BaseRule): _match_re = RE_PROFILE_VARIABLE def __init__(self, varname, mode, values, audit=False, deny=False, allow_keyword=False, - comment='', log_event=None): + comment='', log_event=None, priority=None): super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, - comment=comment, log_event=log_event) + comment=comment, log_event=log_event, priority=priority) - # variables don't support allow keyword, audit or deny + # variables don't support priority, allow keyword, audit or deny self.ensure_modifiers_not_supported() if not isinstance(varname, str): @@ -70,7 +70,7 @@ class VariableRule(BaseRule): values = separate_vars(matches.group('values')) return cls(varname, mode, values, - audit=False, deny=False, allow_keyword=False, comment=comment) + audit=False, deny=False, allow_keyword=False, comment=comment, priority=None) def get_clean(self, depth=0): """return rule (in clean/default formatting)""" diff --git a/utils/test/test-alias.py b/utils/test/test-alias.py index 74f72bcc7..ea9ed47cb 100644 --- a/utils/test/test-alias.py +++ b/utils/test/test-alias.py @@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'orig_path', 'target')) class AliasTest(AATest): def _compare_obj(self, obj, expected): - # aliases don't support the allow, audit or deny keyword + # aliases don't support the allow, audit, deny, or priority keyword self.assertEqual(False, obj.allow_keyword) self.assertEqual(False, obj.audit) self.assertEqual(False, obj.deny) + self.assertEqual(None, obj.priority) self.assertEqual(expected.orig_path, obj.orig_path) self.assertEqual(expected.target, obj.target) @@ -114,6 +115,14 @@ class InvalidAliasInit(AATest): with self.assertRaises(AppArmorBug): AliasRule('/foo', '/bar', deny=True) + def test_invalid_priority_1(self): + with self.assertRaises(AppArmorBug): + AliasRule('/foo', '/bar', priority=1) + + def test_invalid_priority_2(self): + with self.assertRaises(AppArmorBug): + AliasRule('/foo', '/bar', priority=0) + class InvalidAliasTest(AATest): def _check_invalid_rawrule(self, rawrule, matches_regex=False): diff --git a/utils/test/test-all.py b/utils/test/test-all.py index 476291df1..71eeb3267 100644 --- a/utils/test/test-all.py +++ b/utils/test/test-all.py @@ -116,6 +116,7 @@ class WriteAllTestAATest(AATest): (' deny all ,# foo bar', 'deny all, # foo bar'), (' allow all ,# foo bar', 'allow all, # foo bar'), (' allow all ,', 'allow all,'), + (' priority = -2 allow all ,', 'priority=-2 allow all,'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-baserule.py b/utils/test/test-baserule.py index 83ef17321..b3477dd21 100644 --- a/utils/test/test-baserule.py +++ b/utils/test/test-baserule.py @@ -71,7 +71,7 @@ class TestBaserule(AATest): self.ValidSubclass.match('foo') def test_parse_modifiers_invalid(self): - regex = re.compile(r'^\s*(?Paudit\s+)?(?Pallow\s+|deny\s+|invalid\s+)?') + regex = re.compile(r'^\s*(priority\s*=\s*(?P[+-]?[0-9]*)\s+)?(?Paudit\s+)?(?Pallow\s+|deny\s+|invalid\s+)?') matches = regex.search('audit invalid ') with self.assertRaises(AppArmorBug): diff --git a/utils/test/test-boolean.py b/utils/test/test-boolean.py index fc746f1b4..d6bce0e47 100644 --- a/utils/test/test-boolean.py +++ b/utils/test/test-boolean.py @@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'varname', 'value')) class BooleanTest(AATest): def _compare_obj(self, obj, expected): - # boolean variables don't support the allow, audit or deny keyword + # boolean variables don't support the allow, audit, deny, or priority keyword self.assertEqual(False, obj.allow_keyword) self.assertEqual(False, obj.audit) self.assertEqual(False, obj.deny) + self.assertEqual(None, obj.priority) self.assertEqual(expected.varname, obj.varname) self.assertEqual(expected.value, obj.value) @@ -122,6 +123,14 @@ class InvalidBooleanInit(AATest): with self.assertRaises(AppArmorBug): BooleanRule('$foo', 'true', deny=True) + def test_invalid_priority_1(self): + with self.assertRaises(AppArmorBug): + BooleanRule('$foo', 'true', priority=-100) + + def test_invalid_priority_2(self): + with self.assertRaises(AppArmorBug): + BooleanRule('$foo', 'true', priority=0) + class InvalidBooleanTest(AATest): def _check_invalid_rawrule(self, rawrule, matches_regex=False): diff --git a/utils/test/test-capability.py b/utils/test/test-capability.py index 1858df745..666f48cc8 100644 --- a/utils/test/test-capability.py +++ b/utils/test/test-capability.py @@ -314,6 +314,18 @@ class WriteCapabilityTest(AATest): self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule') self.assertEqual(expected, obj.get_raw(2), 'unexpected raw rule') + def test_write_priority_1(self): + self._check_write_rule(' priority = 923 audit capability sys_admin,', 'priority=923 audit capability sys_admin,') + + def test_write_priority_2(self): + self._check_write_rule(' priority = 0 audit capability sys_admin,', 'priority=0 audit capability sys_admin,') + + def test_write_priority_3(self): + self._check_write_rule(' priority=-12 audit capability sys_admin,', 'priority=-12 audit capability sys_admin,') + + def test_write_priority_4(self): + self._check_write_rule(' priority=+99 audit capability sys_admin,', 'priority=99 audit capability sys_admin,') + class CapabilityCoveredTest(AATest): def _is_covered(self, obj, rule_to_test): diff --git a/utils/test/test-change_profile.py b/utils/test/test-change_profile.py index 272894838..0263a6c00 100644 --- a/utils/test/test-change_profile.py +++ b/utils/test/test-change_profile.py @@ -225,6 +225,10 @@ class WriteChangeProfileTestAATest(AATest): (' allow change_profile -> /bar ,# foo bar', 'allow change_profile -> /bar, # foo bar'), (' allow change_profile unsafe /** -> /bar ,# foo bar', 'allow change_profile unsafe /** -> /bar, # foo bar'), (' allow change_profile "/fo o" -> "/b ar",', 'allow change_profile "/fo o" -> "/b ar",'), + (' priority=9 audit deny change_profile /foo -> baz,', 'priority=9 audit deny change_profile /foo -> baz,'), + (' priority = 0 audit deny change_profile /foo -> baz,', 'priority=0 audit deny change_profile /foo -> baz,'), + (' priority=-54 audit deny change_profile /foo -> baz,', 'priority=-54 audit deny change_profile /foo -> baz,'), + (' priority=+42 audit deny change_profile /foo -> baz,', 'priority=42 audit deny change_profile /foo -> baz,'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-dbus.py b/utils/test/test-dbus.py index 9273024a8..e7c8f1468 100644 --- a/utils/test/test-dbus.py +++ b/utils/test/test-dbus.py @@ -419,6 +419,10 @@ class WriteDbusTest(AATest): ('dbus receive peer=(label=foo),', 'dbus receive peer=(label=foo),'), ('dbus (send receive) peer=(name=/usr/bin/bar),', 'dbus (receive send) peer=(name=/usr/bin/bar),'), ('dbus (, receive ,,, send ,) interface=/sbin/baz,', 'dbus (receive send) interface=/sbin/baz,'), # XXX leading and trailing ',' inside (...) causes error + (' priority=123 deny dbus send interface = ( foo ),', 'priority=123 deny dbus send interface=foo,'), + (' priority=0 deny dbus send interface = ( foo ),', 'priority=0 deny dbus send interface=foo,'), + (' priority=-72 deny dbus send interface = ( foo ),', 'priority=-72 deny dbus send interface=foo,'), + (' priority=+834 deny dbus send interface = ( foo ),', 'priority=834 deny dbus send interface=foo,'), # XXX add more complex rules ) diff --git a/utils/test/test-file.py b/utils/test/test-file.py index 20b585c7b..b73990434 100644 --- a/utils/test/test-file.py +++ b/utils/test/test-file.py @@ -415,6 +415,10 @@ class WriteFileTest(AATest): (' /foo r,', '/foo r,'), (' /foo lwr,', '/foo rwl,'), (' /foo Pxrm -> bar,', '/foo mrPx -> bar,'), + (' priority=-1 /foo Pxrm -> bar,', 'priority=-1 /foo mrPx -> bar,'), + (' priority=0 /foo Pxrm -> bar,', 'priority=0 /foo mrPx -> bar,'), + (' priority=343 /foo Pxrm -> bar,', 'priority=343 /foo mrPx -> bar,'), + (' priority=+65 /foo Pxrm -> bar,', 'priority=65 /foo mrPx -> bar,'), # with leading permissions (' audit file r /foo,', 'audit file r /foo,'), @@ -432,11 +436,19 @@ class WriteFileTest(AATest): (' r /foo ,', 'r /foo,'), (' klwr /foo ,', 'rwlk /foo,'), (' Pxrm /foo -> bar,', 'mrPx /foo -> bar,'), + (' priority=1 Pxrm /foo -> bar,', 'priority=1 mrPx /foo -> bar,'), + (' priority=0 Pxrm /foo -> bar,', 'priority=0 mrPx /foo -> bar,'), + (' priority=-22 Pxrm /foo -> bar,', 'priority=-22 mrPx /foo -> bar,'), + (' priority=+78 Pxrm /foo -> bar,', 'priority=78 mrPx /foo -> bar,'), # link rules (' link /foo -> /bar,', 'link /foo -> /bar,'), (' audit deny owner link subset /foo -> /bar,', 'audit deny owner link subset /foo -> /bar,'), - (' link subset /foo -> /bar,', 'link subset /foo -> /bar,') + (' link subset /foo -> /bar,', 'link subset /foo -> /bar,'), + (' priority=0 link /foo -> /bar,', 'priority=0 link /foo -> /bar,'), + (' priority=12 link /foo -> /bar,', 'priority=12 link /foo -> /bar,'), + (' priority=-1 link /foo -> /bar,', 'priority=-1 link /foo -> /bar,'), + (' priority=+4 link /foo -> /bar,', 'priority=4 link /foo -> /bar,'), ) def test_write_manually_1(self): @@ -844,21 +856,23 @@ class FileSeverityTest(AATest): class FileLogprofHeaderTest(AATest): tests = ( # log event old perms ALL / owner - (('file,', set(), set()), [ _('Path'), _('ALL'), _('New Mode'), _('ALL')]), # noqa: E201 - (('/foo r,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'r']), # noqa: E201 - (('file /bar Px -> foo,', set(), set()), [ _('Path'), '/bar', _('New Mode'), 'Px -> foo']), # noqa: E201 - (('deny file,', set(), set()), [_('Qualifier'), 'deny', _('Path'), _('ALL'), _('New Mode'), _('ALL')]), - (('allow file /baz rwk,', set(), set()), [_('Qualifier'), 'allow', _('Path'), '/baz', _('New Mode'), 'rwk']), - (('audit file /foo mr,', set(), set()), [_('Qualifier'), 'audit', _('Path'), '/foo', _('New Mode'), 'mr']), - (('audit deny /foo wk,', set(), set()), [_('Qualifier'), 'audit deny', _('Path'), '/foo', _('New Mode'), 'wk']), - (('owner file /foo ix,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'owner ix']), # noqa: E201 - (('audit deny file /foo rlx -> /baz,', set(), set()), [_('Qualifier'), 'audit deny', _('Path'), '/foo', _('New Mode'), 'rlx -> /baz']), - (('/foo rw,', set('r'), set()), [ _('Path'), '/foo', _('Old Mode'), _('r'), _('New Mode'), 'rw']), # noqa: E201 - (('/foo rw,', set(), set('rw')), [ _('Path'), '/foo', _('Old Mode'), _('owner rw'), _('New Mode'), 'rw']), # noqa: E201 - (('/foo mrw,', set('r'), set('k')), [ _('Path'), '/foo', _('Old Mode'), _('r + owner k'), _('New Mode'), 'mrw']), # noqa: E201 - (('/foo mrw,', set('r'), set('rk')), [ _('Path'), '/foo', _('Old Mode'), _('r + owner k'), _('New Mode'), 'mrw']), # noqa: E201 - (('link /foo -> /bar,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'link -> /bar']), # noqa: E201 - (('link subset /foo -> /bar,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'link subset -> /bar']), # noqa: E201 + (('file,', set(), set()), [ _('Path'), _('ALL'), _('New Mode'), _('ALL')]), # noqa: E201 + (('/foo r,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'r']), # noqa: E201 + (('file /bar Px -> foo,', set(), set()), [ _('Path'), '/bar', _('New Mode'), 'Px -> foo']), # noqa: E201 + (('deny file,', set(), set()), [_('Qualifier'), 'deny', _('Path'), _('ALL'), _('New Mode'), _('ALL')]), + (('allow file /baz rwk,', set(), set()), [_('Qualifier'), 'allow', _('Path'), '/baz', _('New Mode'), 'rwk']), + (('audit file /foo mr,', set(), set()), [_('Qualifier'), 'audit', _('Path'), '/foo', _('New Mode'), 'mr']), + (('audit deny /foo wk,', set(), set()), [_('Qualifier'), 'audit deny', _('Path'), '/foo', _('New Mode'), 'wk']), + (('priority=1 file,', set(), set()), [_('Qualifier'), 'priority=1', _('Path'), _('ALL'), _('New Mode'), _('ALL')]), + (('priority=-1 audit file /foo mr,', set(), set()), [_('Qualifier'), 'priority=-1 audit', _('Path'), '/foo', _('New Mode'), 'mr']), + (('owner file /foo ix,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'owner ix']), # noqa: E201 + (('audit deny file /foo rlx -> /baz,', set(), set()), [_('Qualifier'), 'audit deny', _('Path'), '/foo', _('New Mode'), 'rlx -> /baz']), + (('/foo rw,', set('r'), set()), [ _('Path'), '/foo', _('Old Mode'), _('r'), _('New Mode'), 'rw']), # noqa: E201 + (('/foo rw,', set(), set('rw')), [ _('Path'), '/foo', _('Old Mode'), _('owner rw'), _('New Mode'), 'rw']), # noqa: E201 + (('/foo mrw,', set('r'), set('k')), [ _('Path'), '/foo', _('Old Mode'), _('r + owner k'), _('New Mode'), 'mrw']), # noqa: E201 + (('/foo mrw,', set('r'), set('rk')), [ _('Path'), '/foo', _('Old Mode'), _('r + owner k'), _('New Mode'), 'mrw']), # noqa: E201 + (('link /foo -> /bar,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'link -> /bar']), # noqa: E201 + (('link subset /foo -> /bar,', set(), set()), [ _('Path'), '/foo', _('New Mode'), 'link subset -> /bar']), # noqa: E201 ) def _run_test(self, params, expected): diff --git a/utils/test/test-include.py b/utils/test/test-include.py index db67adafa..9c1bf7039 100644 --- a/utils/test/test-include.py +++ b/utils/test/test-include.py @@ -37,6 +37,7 @@ class IncludeTest(AATest): self.assertEqual(False, obj.allow_keyword) # not supported in include rules, expected to be always False self.assertEqual(False, obj.audit) # not supported in include rules, expected to be always False self.assertEqual(False, obj.deny) # not supported in include rules, expected to be always False + self.assertEqual(None, obj.priority) # not supported in include rules, expected to be always None self.assertEqual(expected.comment, obj.comment) self.assertEqual(expected.path, obj.path) @@ -159,6 +160,10 @@ class InvalidIncludeInit(AATest): with self.assertRaises(AppArmorBug): IncludeRule('foo', False, False, deny=True) + def test_priority_true(self): + with self.assertRaises(AppArmorBug): + IncludeRule('foo', False, False, priority=0) + class InvalidIncludeTest(AATest): def _check_invalid_rawrule(self, rawrule, matches_regex=False): diff --git a/utils/test/test-io_uring.py b/utils/test/test-io_uring.py index f4763495c..957956d5f 100644 --- a/utils/test/test-io_uring.py +++ b/utils/test/test-io_uring.py @@ -64,10 +64,10 @@ class IOUringTestParseInvalid(AATest): IOUringRule.create_instance('foo,') def test_diff_non_iouringrule(self): - exp = namedtuple('exp', ('audit', 'deny')) + exp = namedtuple('exp', ('audit', 'deny', 'priority')) obj = IOUringRule(('sqpoll'), IOUringRule.ALL) with self.assertRaises(AppArmorBug): - obj.is_equal(exp(False, False), False) + obj.is_equal(exp(False, False, None), False) def test_diff_access(self): obj1 = IOUringRule(IOUringRule.ALL, IOUringRule.ALL) @@ -124,6 +124,10 @@ class WriteIOUringTestAATest(AATest): ('io_uring sqpoll label="tst",', 'io_uring sqpoll label="tst",'), ('io_uring (override_creds) label=bar,', 'io_uring override_creds label=bar,'), ('io_uring (sqpoll override_creds) label=/foo,', 'io_uring (override_creds sqpoll) label=/foo,'), + (' priority=1 deny io_uring override_creds ,# foo bar', 'priority=1 deny io_uring override_creds, # foo bar'), + (' priority=0 deny io_uring override_creds ,# foo bar', 'priority=0 deny io_uring override_creds, # foo bar'), + (' priority=-23 deny io_uring override_creds ,# foo bar', 'priority=-23 deny io_uring override_creds, # foo bar'), + (' priority=+21 deny io_uring override_creds ,# foo bar', 'priority=21 deny io_uring override_creds, # foo bar'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-modifiers.py b/utils/test/test-modifiers.py new file mode 100644 index 000000000..36d773e54 --- /dev/null +++ b/utils/test/test-modifiers.py @@ -0,0 +1,90 @@ +#! /usr/bin/python3 +# ------------------------------------------------------------------ +# +# Copyright (C) 2025 Canonical Ltd. +# +# 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 as 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. +# +# ---------------------------------------------------------------------- + +import unittest + +from apparmor.common import AppArmorException +from apparmor.rule.capability import CapabilityRule +from apparmor.rule.change_profile import ChangeProfileRule +from apparmor.rule.dbus import DbusRule +from apparmor.rule.file import FileRule +from apparmor.rule.io_uring import IOUringRule +from apparmor.rule.mount import MountRule +from apparmor.rule.mqueue import MessageQueueRule +from apparmor.rule.network import NetworkRule +from apparmor.rule.pivot_root import PivotRootRule +from apparmor.rule.ptrace import PtraceRule +from apparmor.rule.signal import SignalRule +from apparmor.rule.unix import UnixRule +from apparmor.rule.userns import UserNamespaceRule +from apparmor.rule.all import AllRule +from common_test import AATest, setup_all_loops + + +class TestInvalid_parse_priority(AATest): + tests = ( + ((CapabilityRule, 'priority=a capability,'), AppArmorException), + ((DbusRule, 'priority=a dbus,'), AppArmorException), + ((MountRule, 'priority=a mount,'), AppArmorException), + ((MountRule, 'priority=a umount,'), AppArmorException), + ((MountRule, 'priority=a unmount,'), AppArmorException), + ((MountRule, 'priority=a remount,'), AppArmorException), + ((SignalRule, 'priority=a signal,'), AppArmorException), + ((PtraceRule, 'priority=a ptrace,'), AppArmorException), + ((PivotRootRule, 'priority=a pivot_root,'), AppArmorException), + ((UnixRule, 'priority=a unix,'), AppArmorException), + ((NetworkRule, 'priority=a network,'), AppArmorException), + ((UserNamespaceRule, 'priority=a userns,'), AppArmorException), + ((MessageQueueRule, 'priority=a mqueue,'), AppArmorException), + ((IOUringRule, 'priority=a io_uring,'), AppArmorException), + ((ChangeProfileRule, 'priority=a change_profile,'), AppArmorException), + ((FileRule, 'priority=a file,'), AppArmorException), + ((AllRule, 'priority=a all,'), AppArmorException), + ) + + def _run_test(self, params, expected): + rule_cls, rule = params + with self.assertRaises(expected): + rule_cls.create_instance(rule) # Invalid rule + + +class TestInvalid_init_priority(AATest): + tests = ( + ((CapabilityRule, (CapabilityRule.ALL,)), AppArmorException), + ((DbusRule, (DbusRule.ALL,) * 8), AppArmorException), + ((MountRule, (MountRule.ALL,) * 5), AppArmorException), + ((SignalRule, (SignalRule.ALL,) * 3), AppArmorException), + ((PtraceRule, (PtraceRule.ALL,) * 2), AppArmorException), + ((PivotRootRule, (PivotRootRule.ALL,) * 3), AppArmorException), + ((UnixRule, (UnixRule.ALL,) * 4), AppArmorException), + ((NetworkRule, (NetworkRule.ALL,) * 5), AppArmorException), + ((UserNamespaceRule, (UserNamespaceRule.ALL,) * 1), AppArmorException), + ((MessageQueueRule, (MessageQueueRule.ALL,) * 4), AppArmorException), + ((IOUringRule, (IOUringRule.ALL,) * 2), AppArmorException), + ((ChangeProfileRule, (ChangeProfileRule.ALL,) * 3), AppArmorException), + ((FileRule, (FileRule.ALL,) * 5), AppArmorException), + ((AllRule, ()), AppArmorException), + ) + + def _run_test(self, params, expected): + rule_cls, args = params + with self.assertRaises(expected): + rule_cls(*args, priority="invalid") # ValueError + + +setup_all_loops(__name__) +if __name__ == '__main__': + unittest.main(verbosity=1) diff --git a/utils/test/test-mount.py b/utils/test/test-mount.py index 9b2aa4d9f..60676deb5 100644 --- a/utils/test/test-mount.py +++ b/utils/test/test-mount.py @@ -123,10 +123,10 @@ class MountTestParseInvalid(AATest): MountRule.create_instance('foo,') def test_diff_non_mountrule(self): - exp = namedtuple('exp', ('audit', 'deny')) + exp = namedtuple('exp', ('audit', 'deny', 'priority')) obj = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL) with self.assertRaises(AppArmorBug): - obj.is_equal(exp(False, False), False) + obj.is_equal(exp(False, False, None), False) def test_diff_invalid_fstype_equals_or_in(self): with self.assertRaises(AppArmorBug): @@ -230,6 +230,12 @@ class MountTestClean(AATest): (' umount /foo , ', 'umount /foo,'), (' remount , ', 'remount,'), (' remount /foo , ', 'remount /foo,'), + ('priority =1 mount "" -> /foo , ', 'priority=1 mount "" -> /foo,'), + ('priority=0 audit mount "/f /b" -> "/foo bar" , ', 'priority=0 audit mount "/f /b" -> "/foo bar",'), + (' priority = +10 umount , ', 'priority=10 umount,'), + (' priority=-2 deny umount /foo , ', 'priority=-2 deny umount /foo,'), + ('priority= 32 audit deny remount , ', 'priority=32 audit deny remount,'), + (' priority = -32 remount /foo , ', 'priority=-32 remount /foo,'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-mqueue.py b/utils/test/test-mqueue.py index c737726f3..1f6199c07 100644 --- a/utils/test/test-mqueue.py +++ b/utils/test/test-mqueue.py @@ -77,10 +77,10 @@ class MessageQueueTestParseInvalid(AATest): MessageQueueRule.create_instance('foo,') def test_diff_non_mqueuerule(self): - exp = namedtuple('exp', ('audit', 'deny')) + exp = namedtuple('exp', ('audit', 'deny', 'priority')) obj = MessageQueueRule(('open'), 'posix', 'bar', '/foo') with self.assertRaises(AppArmorBug): - obj.is_equal(exp(False, False), False) + obj.is_equal(exp(False, False, None), False) def test_diff_access(self): obj1 = MessageQueueRule(('open'), 'posix', 'bar', '/foo') @@ -171,6 +171,10 @@ class WriteMessageQueueTestAATest(AATest): ('mqueue wr label=tst 1234,', 'mqueue wr label=tst 1234,'), ('mqueue wr type=sysv label=tst 1234,', 'mqueue wr type=sysv label=tst 1234,'), ('mqueue wr type=posix label=tst /foo,', 'mqueue wr type=posix label=tst /foo,'), + (' priority = -82 mqueue getattr /foo,', 'priority=-82 mqueue getattr /foo,'), + (' priority = 12 audit mqueue (setattr getattr) 1234,', 'priority=12 audit mqueue (getattr setattr) 1234,'), + (' priority=0 mqueue getattr /foo,', 'priority=0 mqueue getattr /foo,'), + (' priority=+82 mqueue getattr /foo,', 'priority=82 mqueue getattr /foo,'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-network.py b/utils/test/test-network.py index db3b341e8..a74fa32c2 100644 --- a/utils/test/test-network.py +++ b/utils/test/test-network.py @@ -286,6 +286,10 @@ class WriteNetworkTestAATest(AATest): (' network stream peer = ( ip=::1 port=22 ) ,', 'network stream peer=(ip=::1 port=22),'), (' network ( bind , listen ) stream ip = ::1 port = 22 ,', 'network (bind, listen) stream ip=::1 port=22,'), (' allow network tcp ,# foo bar', 'allow network tcp, # foo bar'), + (' priority = -02 allow network tcp ,# foo bar', 'priority=-2 allow network tcp, # foo bar'), + (' priority = 0 allow network tcp ,# foo bar', 'priority=0 allow network tcp, # foo bar'), + (' priority = 43 allow network tcp ,# foo bar', 'priority=43 allow network tcp, # foo bar'), + (' priority=+123 allow network tcp ,# foo bar', 'priority=123 allow network tcp, # foo bar'), ) diff --git a/utils/test/test-parser-simple-tests.py b/utils/test/test-parser-simple-tests.py index 154c5e28d..22a7b480b 100644 --- a/utils/test/test-parser-simple-tests.py +++ b/utils/test/test-parser-simple-tests.py @@ -35,9 +35,6 @@ skip_startswith = ( # Pux and Cux (which actually mean PUx and CUx) get rejected by the tools 'generated_x/exact-', - - # don't handle rule priorities yet - 'file/priority/', ) # testcases that should raise an exception, but don't @@ -246,11 +243,16 @@ unknown_line = ( 'file/ok_other_1.sd', 'file/ok_other_2.sd', 'file/ok_other_3.sd', + 'file/priority/ok_other_1.sd', + 'file/priority/ok_other_2.sd', + 'file/priority/ok_other_3.sd', # 'unsafe' keyword 'file/file/front_perms_ok_2.sd', 'file/front_perms_ok_2.sd', 'xtrans/simple_ok_cx_1.sd', + 'file/priority/front_perms_ok_1.sd', + 'file/priority/front_perms_ok_2.sd', # owner / audit {...} blocks 'file/file/owner/ok_1.sd', @@ -355,6 +357,9 @@ syntax_failure = ( 'file/ok_5.sd', # Invalid mode UX 'file/ok_2.sd', # Invalid mode RWM 'file/ok_4.sd', # Invalid mode iX + 'file/priority/ok_5.sd', # Invalid mode UX + 'file/priority/ok_2.sd', # Invalid mode RWM + 'file/priority/ok_4.sd', # Invalid mode iX 'xtrans/simple_ok_pix_1.sd', # Invalid mode pIx 'xtrans/simple_ok_pux_1.sd', # Invalid mode rPux @@ -424,6 +429,8 @@ syntax_failure = ( 'file/ok_embedded_spaces_4.sd', # \-escaped space 'file/file/ok_embedded_spaces_4.sd', # \-escaped space 'file/ok_quoted_4.sd', # quoted string including \" + 'file/priority/ok_quoted_4.sd', # quoted string including \" + 'file/priority/ok_embedded_spaces_4.sd', # \-escaped space # mount rules with multiple 'options' or 'fstype' are not supported by the tools yet, and when writing them, only the last 'options'/'fstype' would survive. # Therefore MountRule intentionally raises an exception when parsing such a rule. diff --git a/utils/test/test-pivot_root.py b/utils/test/test-pivot_root.py index ceaf59ab7..1b6fcc816 100644 --- a/utils/test/test-pivot_root.py +++ b/utils/test/test-pivot_root.py @@ -261,6 +261,10 @@ class WritePivotRootTestAATest(AATest): (' pivot_root oldroot="/old" , # foo ', 'pivot_root oldroot=/old, # foo'), (' pivot_root oldroot=/old -> some_profile , ', 'pivot_root oldroot=/old -> some_profile,'), (' pivot_root oldroot=/old /new -> some_profile , ', 'pivot_root oldroot=/old /new -> some_profile,'), + ('priority=1 pivot_root oldroot=/old /new -> some_profile , ', 'priority=1 pivot_root oldroot=/old /new -> some_profile,'), + ('priority=0 pivot_root oldroot=/old /new -> some_profile , ', 'priority=0 pivot_root oldroot=/old /new -> some_profile,'), + ('priority=-1 pivot_root oldroot=/old /new -> some_profile , ', 'priority=-1 pivot_root oldroot=/old /new -> some_profile,'), + ('priority=+1 pivot_root oldroot=/old /new -> some_profile , ', 'priority=1 pivot_root oldroot=/old /new -> some_profile,'), ) def test_write_manually(self): diff --git a/utils/test/test-ptrace.py b/utils/test/test-ptrace.py index 18362f262..5193d99c5 100644 --- a/utils/test/test-ptrace.py +++ b/utils/test/test-ptrace.py @@ -260,6 +260,10 @@ class WritePtraceTestAATest(AATest): ('ptrace (read tracedby) peer=/usr/bin/bar,', 'ptrace (read tracedby) peer=/usr/bin/bar,'), ('ptrace (trace read) peer=/usr/bin/bar,', 'ptrace (read trace) peer=/usr/bin/bar,'), ('ptrace wr peer=/sbin/baz,', 'ptrace wr peer=/sbin/baz,'), + ('priority = 010 deny ptrace ( read ), ', 'priority=10 deny ptrace read,'), + ('priority = 0 deny ptrace ( read ), ', 'priority=0 deny ptrace read,'), + ('priority = -21 deny ptrace ( read ), ', 'priority=-21 deny ptrace read,'), + ('priority = +83 deny ptrace ( read ), ', 'priority=83 deny ptrace read,'), ) def test_write_manually(self): diff --git a/utils/test/test-regex_matches.py b/utils/test/test-regex_matches.py index 927f0ea6f..243707762 100644 --- a/utils/test/test-regex_matches.py +++ b/utils/test/test-regex_matches.py @@ -218,11 +218,16 @@ class AARegexCapability(AARegexTest): self.regex = RE_PROFILE_CAP tests = ( - (' capability net_raw,', (None, None, 'net_raw', 'net_raw', None)), - ('capability net_raw , ', (None, None, 'net_raw', 'net_raw', None)), - (' capability,', (None, None, None, None, None)), - (' capability , ', (None, None, None, None, None)), - (' capabilitynet_raw,', False) + (' capability net_raw,', (None, None, None, None, 'net_raw', 'net_raw', None)), + ('capability net_raw , ', (None, None, None, None, 'net_raw', 'net_raw', None)), + (' capability,', (None, None, None, None, None, None, None)), + (' capability , ', (None, None, None, None, None, None, None)), + (' capabilitynet_raw,', False), + (' priority=1 capability net_raw,', ('priority=1', '1', None, None, 'net_raw', 'net_raw', None)), + ('priority=1 capability net_raw , ', ('priority=1', '1', None, None, 'net_raw', 'net_raw', None)), + (' priority=1 capability,', ('priority=1', '1', None, None, None, None, None)), + (' priority=1 capability , ', ('priority=1', '1', None, None, None, None, None)), + (' priority=1 capabilitynet_raw,', False), ) @@ -233,13 +238,19 @@ class AARegexDbus(AARegexTest): self.regex = RE_PROFILE_DBUS tests = ( - (' dbus,', (None, None, 'dbus,', None, None)), - (' audit dbus,', ('audit', None, 'dbus,', None, None)), - (' dbus send member=no_comment,', (None, None, 'dbus send member=no_comment,', 'send member=no_comment', None)), - (' dbus send member=no_comment, # comment', (None, None, 'dbus send member=no_comment,', 'send member=no_comment', '# comment')), + (' dbus,', (None, None, None, None, 'dbus,', None, None)), + (' audit dbus,', (None, None, 'audit', None, 'dbus,', None, None)), + (' dbus send member=no_comment,', (None, None, None, None, 'dbus send member=no_comment,', 'send member=no_comment', None)), + (' dbus send member=no_comment, # comment', (None, None, None, None, 'dbus send member=no_comment,', 'send member=no_comment', '# comment')), + + (' priority=-11 dbus,', ('priority=-11', '-11', None, None, 'dbus,', None, None)), + (' priority=-11 audit dbus,', ('priority=-11', '-11', 'audit', None, 'dbus,', None, None)), + (' priority=-11 dbus send member=no_comment,', ('priority=-11', '-11', None, None, 'dbus send member=no_comment,', 'send member=no_comment', None)), + (' priority=-11 dbus send member=no_comment, # comment', ('priority=-11', '-11', None, None, 'dbus send member=no_comment,', 'send member=no_comment', '# comment')), (' dbusdriver,', False), (' audit dbusdriver,', False), + (' priority=-11 audit dbusdriver,', False), ) @@ -250,19 +261,30 @@ class AARegexMount(AARegexTest): self.regex = RE_PROFILE_MOUNT tests = ( - (' mount,', (None, None, 'mount,', 'mount', None, None)), - (' audit mount,', ('audit', None, 'mount,', 'mount', None, None)), - (' umount,', (None, None, 'umount,', 'umount', None, None)), - (' audit umount,', ('audit', None, 'umount,', 'umount', None, None)), - (' unmount,', (None, None, 'unmount,', 'unmount', None, None)), - (' audit unmount,', ('audit', None, 'unmount,', 'unmount', None, None)), - (' remount,', (None, None, 'remount,', 'remount', None, None)), - (' deny remount,', (None, 'deny', 'remount,', 'remount', None, None)), + (' mount,', (None, None, None, None, 'mount,', 'mount', None, None)), + (' audit mount,', (None, None, 'audit', None, 'mount,', 'mount', None, None)), + (' umount,', (None, None, None, None, 'umount,', 'umount', None, None)), + (' audit umount,', (None, None, 'audit', None, 'umount,', 'umount', None, None)), + (' unmount,', (None, None, None, None, 'unmount,', 'unmount', None, None)), + (' audit unmount,', (None, None, 'audit', None, 'unmount,', 'unmount', None, None)), + (' remount,', (None, None, None, None, 'remount,', 'remount', None, None)), + (' deny remount,', (None, None, None, 'deny', 'remount,', 'remount', None, None)), - (' mount, # comment', (None, None, 'mount,', 'mount', None, '# comment')), + (' priority = 0 mount,', ('priority = 0', '0', None, None, 'mount,', 'mount', None, None)), + (' priority = 0 audit mount,', ('priority = 0', '0', 'audit', None, 'mount,', 'mount', None, None)), + (' priority = 0 umount,', ('priority = 0', '0', None, None, 'umount,', 'umount', None, None)), + (' priority = 0 audit umount,', ('priority = 0', '0', 'audit', None, 'umount,', 'umount', None, None)), + (' priority = 0 unmount,', ('priority = 0', '0', None, None, 'unmount,', 'unmount', None, None)), + (' priority = 0 audit unmount,', ('priority = 0', '0', 'audit', None, 'unmount,', 'unmount', None, None)), + (' priority = 0 remount,', ('priority = 0', '0', None, None, 'remount,', 'remount', None, None)), + (' priority = 0 deny remount,', ('priority = 0', '0', None, 'deny', 'remount,', 'remount', None, None)), + + (' mount, # comment', (None, None, None, None, 'mount,', 'mount', None, '# comment')), + (' priority = 0 mount, # comment', ('priority = 0', '0', None, None, 'mount,', 'mount', None, '# comment')), (' mountain,', False), (' audit mountain,', False), + (' priority = 0 audit mountain,', False), ) @@ -273,16 +295,25 @@ class AARegexSignal(AARegexTest): self.regex = RE_PROFILE_SIGNAL tests = ( - (' signal,', (None, None, 'signal,', None, None)), - (' audit signal,', ('audit', None, 'signal,', None, None)), - (' signal receive,', (None, None, 'signal receive,', 'receive', None)), - (' signal (send, receive),', (None, None, 'signal (send, receive),', '(send, receive)', None)), - (' audit signal (receive),', ('audit', None, 'signal (receive),', '(receive)', None)), - (' signal (send, receive) set=(usr1 usr2),', (None, None, 'signal (send, receive) set=(usr1 usr2),', '(send, receive) set=(usr1 usr2)', None)), - (' signal send set=(hup, quit) peer=/usr/sbin/daemon,', (None, None, 'signal send set=(hup, quit) peer=/usr/sbin/daemon,', 'send set=(hup, quit) peer=/usr/sbin/daemon', None)), + (' signal,', (None, None, None, None, 'signal,', None, None)), + (' audit signal,', (None, None, 'audit', None, 'signal,', None, None)), + (' signal receive,', (None, None, None, None, 'signal receive,', 'receive', None)), + (' signal (send, receive),', (None, None, None, None, 'signal (send, receive),', '(send, receive)', None)), + (' audit signal (receive),', (None, None, 'audit', None, 'signal (receive),', '(receive)', None)), + (' signal (send, receive) set=(usr1 usr2),', (None, None, None, None, 'signal (send, receive) set=(usr1 usr2),', '(send, receive) set=(usr1 usr2)', None)), + (' signal send set=(hup, quit) peer=/usr/sbin/daemon,', (None, None, None, None, 'signal send set=(hup, quit) peer=/usr/sbin/daemon,', 'send set=(hup, quit) peer=/usr/sbin/daemon', None)), + + (' priority = -1 signal,', ('priority = -1', '-1', None, None, 'signal,', None, None)), + (' priority = -1 audit signal,', ('priority = -1', '-1', 'audit', None, 'signal,', None, None)), + (' priority = -1 signal receive,', ('priority = -1', '-1', None, None, 'signal receive,', 'receive', None)), + (' priority = -1 signal (send, receive),', ('priority = -1', '-1', None, None, 'signal (send, receive),', '(send, receive)', None)), + (' priority = -1 audit signal (receive),', ('priority = -1', '-1', 'audit', None, 'signal (receive),', '(receive)', None)), + (' priority = -1 signal (send, receive) set=(usr1 usr2),', ('priority = -1', '-1', None, None, 'signal (send, receive) set=(usr1 usr2),', '(send, receive) set=(usr1 usr2)', None)), + (' priority = -1 signal send set=(hup, quit) peer=/usr/sbin/daemon,', ('priority = -1', '-1', None, None, 'signal send set=(hup, quit) peer=/usr/sbin/daemon,', 'send set=(hup, quit) peer=/usr/sbin/daemon', None)), (' signalling,', False), (' audit signalling,', False), + (' priority = -1 audit signalling,', False), (' signalling receive,', False), ) @@ -294,16 +325,24 @@ class AARegexPtrace(AARegexTest): self.regex = RE_PROFILE_PTRACE tests = ( - # audit allow rule rule details comment - (' ptrace,', (None, None, 'ptrace,', None, None)), - (' audit ptrace,', ('audit', None, 'ptrace,', None, None)), - (' ptrace trace,', (None, None, 'ptrace trace,', 'trace', None)), - (' ptrace (tracedby, readby),', (None, None, 'ptrace (tracedby, readby),', '(tracedby, readby)', None)), - (' audit ptrace (read),', ('audit', None, 'ptrace (read),', '(read)', None)), - (' ptrace trace peer=/usr/sbin/daemon,', (None, None, 'ptrace trace peer=/usr/sbin/daemon,', 'trace peer=/usr/sbin/daemon', None)), + # priority audit allow rule rule details comment + (' ptrace,', (None, None, None, None, 'ptrace,', None, None)), + (' audit ptrace,', (None, None, 'audit', None, 'ptrace,', None, None)), + (' ptrace trace,', (None, None, None, None, 'ptrace trace,', 'trace', None)), + (' ptrace (tracedby, readby),', (None, None, None, None, 'ptrace (tracedby, readby),', '(tracedby, readby)', None)), + (' audit ptrace (read),', (None, None, 'audit', None, 'ptrace (read),', '(read)', None)), + (' ptrace trace peer=/usr/sbin/daemon,', (None, None, None, None, 'ptrace trace peer=/usr/sbin/daemon,', 'trace peer=/usr/sbin/daemon', None)), + + (' priority=100 ptrace,', ('priority=100', '100', None, None, 'ptrace,', None, None)), + (' priority=100 audit ptrace,', ('priority=100', '100', 'audit', None, 'ptrace,', None, None)), + (' priority=100 ptrace trace,', ('priority=100', '100', None, None, 'ptrace trace,', 'trace', None)), + (' priority=100 ptrace (tracedby, readby),', ('priority=100', '100', None, None, 'ptrace (tracedby, readby),', '(tracedby, readby)', None)), + (' priority=100 audit ptrace (read),', ('priority=100', '100', 'audit', None, 'ptrace (read),', '(read)', None)), + (' priority=100 ptrace trace peer=/usr/sbin/daemon,', ('priority=100', '100', None, None, 'ptrace trace peer=/usr/sbin/daemon,', 'trace peer=/usr/sbin/daemon', None)), (' ptraceback,', False), (' audit ptraceback,', False), + (' priority=100 audit ptraceback,', False), (' ptraceback trace,', False), ) @@ -315,12 +354,19 @@ class AARegexPivotRoot(AARegexTest): self.regex = RE_PROFILE_PIVOT_ROOT tests = ( - (' pivot_root,', (None, None, 'pivot_root,', None, None)), - (' audit pivot_root,', ('audit', None, 'pivot_root,', None, None)), - (' pivot_root oldroot=/new/old,', (None, None, 'pivot_root oldroot=/new/old,', 'oldroot=/new/old', None)), - (' pivot_root oldroot=/new/old /new,', (None, None, 'pivot_root oldroot=/new/old /new,', 'oldroot=/new/old /new', None)), - (' pivot_root oldroot=/new/old /new -> child,', (None, None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), - (' audit pivot_root oldroot=/new/old /new -> child,', ('audit', None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), + (' pivot_root,', (None, None, None, None, 'pivot_root,', None, None)), + (' audit pivot_root,', (None, None, 'audit', None, 'pivot_root,', None, None)), + (' pivot_root oldroot=/new/old,', (None, None, None, None, 'pivot_root oldroot=/new/old,', 'oldroot=/new/old', None)), + (' pivot_root oldroot=/new/old /new,', (None, None, None, None, 'pivot_root oldroot=/new/old /new,', 'oldroot=/new/old /new', None)), + (' pivot_root oldroot=/new/old /new -> child,', (None, None, None, None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), + (' audit pivot_root oldroot=/new/old /new -> child,', (None, None, 'audit', None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), + + (' priority=-100 pivot_root,', ('priority=-100', '-100', None, None, 'pivot_root,', None, None)), + (' priority=-100 audit pivot_root,', ('priority=-100', '-100', 'audit', None, 'pivot_root,', None, None)), + (' priority=-100 pivot_root oldroot=/new/old,', ('priority=-100', '-100', None, None, 'pivot_root oldroot=/new/old,', 'oldroot=/new/old', None)), + (' priority=-100 pivot_root oldroot=/new/old /new,', ('priority=-100', '-100', None, None, 'pivot_root oldroot=/new/old /new,', 'oldroot=/new/old /new', None)), + (' priority=-100 pivot_root oldroot=/new/old /new -> child,', ('priority=-100', '-100', None, None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), + (' priority=-100 audit pivot_root oldroot=/new/old /new -> child,', ('priority=-100', '-100', 'audit', None, 'pivot_root oldroot=/new/old /new -> child,', 'oldroot=/new/old /new -> child', None)), ('pivot_root', False), # comma missing @@ -329,6 +375,7 @@ class AARegexPivotRoot(AARegexTest): ('pivot_rootbeer, # comment', False), ('pivot_rootbeer /new, ', False), ('pivot_rootbeer /new, # comment', False), + ('priority=-100 pivot_rootbeer /new, # comment', False), ) @@ -339,20 +386,35 @@ class AARegexUnix(AARegexTest): self.regex = RE_PROFILE_UNIX tests = ( - (' unix,', (None, None, 'unix,', None, None)), - (' audit unix,', ('audit', None, 'unix,', None, None)), - (' unix accept,', (None, None, 'unix accept,', 'accept', None)), - (' allow unix connect,', (None, 'allow', 'unix connect,', 'connect', None)), - (' audit allow unix bind,', ('audit', 'allow', 'unix bind,', 'bind', None)), - (' deny unix bind,', (None, 'deny', 'unix bind,', 'bind', None)), - ('unix peer=(label=@{profile_name}),', (None, None, 'unix peer=(label=@{profile_name}),', 'peer=(label=@{profile_name})', None)), - ('unix (receive) peer=(label=unconfined),', (None, None, 'unix (receive) peer=(label=unconfined),', '(receive) peer=(label=unconfined)', None)), - (' unix (getattr, shutdown) peer=(addr=none),', (None, None, 'unix (getattr, shutdown) peer=(addr=none),', '(getattr, shutdown) peer=(addr=none)', None)), - ('unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', (None, None, 'unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', + (' unix,', (None, None, None, None, 'unix,', None, None)), + (' audit unix,', (None, None, 'audit', None, 'unix,', None, None)), + (' unix accept,', (None, None, None, None, 'unix accept,', 'accept', None)), + (' allow unix connect,', (None, None, None, 'allow', 'unix connect,', 'connect', None)), + (' audit allow unix bind,', (None, None, 'audit', 'allow', 'unix bind,', 'bind', None)), + (' deny unix bind,', (None, None, None, 'deny', 'unix bind,', 'bind', None)), + ('unix peer=(label=@{profile_name}),', (None, None, None, None, 'unix peer=(label=@{profile_name}),', 'peer=(label=@{profile_name})', None)), + ('unix (receive) peer=(label=unconfined),', (None, None, None, None, 'unix (receive) peer=(label=unconfined),', '(receive) peer=(label=unconfined)', None)), + (' unix (getattr, shutdown) peer=(addr=none),', (None, None, None, None, 'unix (getattr, shutdown) peer=(addr=none),', '(getattr, shutdown) peer=(addr=none)', None)), + ('unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', (None, None, None, None, 'unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', '(connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*")', # noqa: E127 None)), # noqa: E127 + + (' priority=1 unix,', ('priority=1', '1', None, None, 'unix,', None, None)), + (' priority=1 audit unix,', ('priority=1', '1', 'audit', None, 'unix,', None, None)), + (' priority=1 unix accept,', ('priority=1', '1', None, None, 'unix accept,', 'accept', None)), + (' priority=1 allow unix connect,', ('priority=1', '1', None, 'allow', 'unix connect,', 'connect', None)), + (' priority=1 audit allow unix bind,', ('priority=1', '1', 'audit', 'allow', 'unix bind,', 'bind', None)), + (' priority=1 deny unix bind,', ('priority=1', '1', None, 'deny', 'unix bind,', 'bind', None)), + ('priority=1 unix peer=(label=@{profile_name}),', ('priority=1', '1', None, None, 'unix peer=(label=@{profile_name}),', 'peer=(label=@{profile_name})', None)), + ('priority=1 unix (receive) peer=(label=unconfined),', ('priority=1', '1', None, None, 'unix (receive) peer=(label=unconfined),', '(receive) peer=(label=unconfined)', None)), + (' priority=1 unix (getattr, shutdown) peer=(addr=none),', ('priority=1', '1', None, None, 'unix (getattr, shutdown) peer=(addr=none),', '(getattr, shutdown) peer=(addr=none)', None)), + ('priority=1 unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', ('priority=1', '1', None, None, 'unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', + '(connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*")', # noqa: E127 + None)), # noqa: E127 + ('unixlike', False), ('deny unixlike,', False), + ('priority=1 deny unixlike,', False), ) diff --git a/utils/test/test-rlimit.py b/utils/test/test-rlimit.py index 532d53492..7bbd3a7b7 100644 --- a/utils/test/test-rlimit.py +++ b/utils/test/test-rlimit.py @@ -174,6 +174,10 @@ class InvalidRlimitInit(AATest): with self.assertRaises(AppArmorBug): RlimitRule('as', '1024MB', audit=True) + def test_priority_keyword(self): + with self.assertRaises(AppArmorBug): + RlimitRule('as', '1024MB', priority=0) + class InvalidRlimitTest(AATest): def _check_invalid_rawrule(self, rawrule): diff --git a/utils/test/test-signal.py b/utils/test/test-signal.py index 58c6af44e..92f7cf771 100644 --- a/utils/test/test-signal.py +++ b/utils/test/test-signal.py @@ -277,6 +277,10 @@ class WriteSignalTestAATest(AATest): ('signal receive peer=foo,', 'signal receive peer=foo,'), ('signal (send receive) peer=/usr/bin/bar,', 'signal (receive send) peer=/usr/bin/bar,'), ('signal wr set=(pipe, usr1) peer=/sbin/baz,', 'signal wr set=(pipe usr1) peer=/sbin/baz,'), + ('priority = 29 signal receive peer=foo,', 'priority=29 signal receive peer=foo,'), + ('priority = 0 signal receive peer=foo,', 'priority=0 signal receive peer=foo,'), + ('priority =-123 signal receive peer=foo,', 'priority=-123 signal receive peer=foo,'), + ('priority =+10 signal receive peer=foo,', 'priority=10 signal receive peer=foo,'), ) def test_write_manually(self): diff --git a/utils/test/test-unix.py b/utils/test/test-unix.py index 104abc1da..5fbf013c9 100644 --- a/utils/test/test-unix.py +++ b/utils/test/test-unix.py @@ -166,15 +166,18 @@ class UnixTestGlob(AATest): class UnixTestClean(AATest): tests = ( - (' audit unix , # foo ', 'audit unix, # foo'), - (' audit deny unix label = foo , ', 'audit deny unix label=foo,'), - (' audit allow unix peer = (addr = a) , # foo ', 'audit allow unix peer=(addr=a), # foo'), - (' deny unix type = foo , ', 'deny unix type=foo,'), - (' allow unix peer = (label=bb) , # foo ', 'allow unix peer=(label=bb), # foo'), - (' unix , # foo ', 'unix, # foo'), - (' unix addr = foo , ', 'unix addr=foo,'), - (' unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ) , ', 'unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), - + (' audit unix , # foo ', 'audit unix, # foo'), + (' audit deny unix label = foo , ', 'audit deny unix label=foo,'), + (' audit allow unix peer = (addr = a) , # foo ', 'audit allow unix peer=(addr=a), # foo'), + (' deny unix type = foo , ', 'deny unix type=foo,'), + (' allow unix peer = (label=bb) , # foo ', 'allow unix peer=(label=bb), # foo'), + (' unix , # foo ', 'unix, # foo'), + (' unix addr = foo , ', 'unix addr=foo,'), + (' unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ) , ', 'unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), + ('priority=-42 unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ), ', 'priority=-42 unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), + ('priority = 0 unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ), ', 'priority=0 unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), + ('priority=211 unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ), ', 'priority=211 unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), + ('priority=+45 unix ( accept , rw) protocol = AA type = BB opt = myopt label = bb peer = (addr = a label = bb ), ', 'priority=45 unix (accept, rw) type=BB protocol=AA label=bb opt=myopt peer=(addr=a label=bb),'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-userns.py b/utils/test/test-userns.py index 82e523fd0..4d5419eed 100644 --- a/utils/test/test-userns.py +++ b/utils/test/test-userns.py @@ -59,10 +59,10 @@ class UserNamespaceTestParseInvalid(AATest): UserNamespaceRule.create_instance('foo,') def test_diff_non_usernsrule(self): - exp = namedtuple('exp', ('audit', 'deny')) + exp = namedtuple('exp', ('audit', 'deny', 'priority')) obj = UserNamespaceRule(('create')) with self.assertRaises(AppArmorBug): - obj.is_equal(exp(False, False), False) + obj.is_equal(exp(False, False, None), False) def test_diff_access(self): obj1 = UserNamespaceRule(UserNamespaceRule.ALL) @@ -98,6 +98,10 @@ class WriteUserNamespaceTestAATest(AATest): (' allow userns create ,# foo bar', 'allow userns create, # foo bar'), ('userns,', 'userns,'), ('userns create,', 'userns create,'), + (' priority = -1 allow userns create,', 'priority=-1 allow userns create,'), + (' priority = 0 allow userns create,', 'priority=0 allow userns create,'), + (' priority=+234 allow userns create,', 'priority=234 allow userns create,'), + (' priority = 65 allow userns create,', 'priority=65 allow userns create,'), ) def _run_test(self, rawrule, expected): diff --git a/utils/test/test-variable.py b/utils/test/test-variable.py index 1dcedc3dd..eba5b3f03 100644 --- a/utils/test/test-variable.py +++ b/utils/test/test-variable.py @@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'varname', 'mode', 'values')) class VariableTest(AATest): def _compare_obj(self, obj, expected): - # variables don't support the allow, audit or deny keyword + # variables don't support the allow, audit, deny, or priority keyword self.assertEqual(False, obj.allow_keyword) self.assertEqual(False, obj.audit) self.assertEqual(False, obj.deny) + self.assertEqual(None, obj.priority) self.assertEqual(expected.varname, obj.varname) self.assertEqual(expected.mode, obj.mode) @@ -166,6 +167,14 @@ class InvalidVariableInit(AATest): with self.assertRaises(AppArmorBug): VariableRule('@{foo}', '=', '/bar', deny=True) + def test_invalid_priority_1(self): + with self.assertRaises(AppArmorBug): + VariableRule('@{foo}', '=', '/bar', priority=98) + + def test_invalid_priority_2(self): + with self.assertRaises(AppArmorBug): + VariableRule('@{foo}', '=', '/bar', priority=0) + class InvalidVariableTest(AATest): def _check_invalid_rawrule(self, rawrule, matches_regex=False): From 94c5cf047f0e079ab42beba66f8f3c3d552bda74 Mon Sep 17 00:00:00 2001 From: Christian Boltz Date: Mon, 5 May 2025 20:53:53 +0200 Subject: [PATCH 07/11] Split priority rules with `unsafe` keyword to separate tests This helps to limit the amount of rules skipped in the utils tests (because the utils don't support the `unsafe` keyword) --- .../simple_tests/file/priority/front_perms_ok_1.sd | 5 ----- .../simple_tests/file/priority/front_perms_ok_2.sd | 5 ----- .../simple_tests/file/priority/front_perms_ok_3.sd | 12 ++++++++++++ .../simple_tests/file/priority/front_perms_ok_4.sd | 13 +++++++++++++ utils/test/test-parser-simple-tests.py | 4 ++-- 5 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 parser/tst/simple_tests/file/priority/front_perms_ok_3.sd create mode 100644 parser/tst/simple_tests/file/priority/front_perms_ok_4.sd diff --git a/parser/tst/simple_tests/file/priority/front_perms_ok_1.sd b/parser/tst/simple_tests/file/priority/front_perms_ok_1.sd index 2375fd1dc..137a9454a 100644 --- a/parser/tst/simple_tests/file/priority/front_perms_ok_1.sd +++ b/parser/tst/simple_tests/file/priority/front_perms_ok_1.sd @@ -15,10 +15,5 @@ priority=-1 file ux /foo3, priority=-1 file Ux /foo4, priority=-1 file ix /foo5, - priority=-1 file unsafe px /foo6, - priority=-1 file unsafe Px /foo7, - priority=-1 file unsafe ux /foo8, - priority=-1 file unsafe Ux /foo9, - priority=-1 file unsafe ix /foo10, } diff --git a/parser/tst/simple_tests/file/priority/front_perms_ok_2.sd b/parser/tst/simple_tests/file/priority/front_perms_ok_2.sd index f1ee0837a..88db2191f 100644 --- a/parser/tst/simple_tests/file/priority/front_perms_ok_2.sd +++ b/parser/tst/simple_tests/file/priority/front_perms_ok_2.sd @@ -15,10 +15,5 @@ priority=-1 ux /foo3, priority=-1 Ux /foo4, priority=-1 ix /foo5, - priority=-1 unsafe px /foo6, - priority=-1 unsafe Px /foo7, - priority=-1 unsafe ux /foo8, - priority=-1 unsafe Ux /foo9, - priority=-1 unsafe ix /foo10, } diff --git a/parser/tst/simple_tests/file/priority/front_perms_ok_3.sd b/parser/tst/simple_tests/file/priority/front_perms_ok_3.sd new file mode 100644 index 000000000..4140ae0ef --- /dev/null +++ b/parser/tst/simple_tests/file/priority/front_perms_ok_3.sd @@ -0,0 +1,12 @@ +# +#=DESCRIPTION perms before pathname + unsafe keyword +#=EXRESULT PASS +# +/usr/bin/foo { + priority=-1 file unsafe px /foo6, + priority=-1 file unsafe Px /foo7, + priority=-1 file unsafe ux /foo8, + priority=-1 file unsafe Ux /foo9, + priority=-1 file unsafe ix /foo10, + +} diff --git a/parser/tst/simple_tests/file/priority/front_perms_ok_4.sd b/parser/tst/simple_tests/file/priority/front_perms_ok_4.sd new file mode 100644 index 000000000..3a33020eb --- /dev/null +++ b/parser/tst/simple_tests/file/priority/front_perms_ok_4.sd @@ -0,0 +1,13 @@ +# +#=DESCRIPTION perms before pathname + unsafe keyword +#=EXRESULT PASS +# +/usr/bin/foo { + + priority=-1 unsafe px /foo6, + priority=-1 unsafe Px /foo7, + priority=-1 unsafe ux /foo8, + priority=-1 unsafe Ux /foo9, + priority=-1 unsafe ix /foo10, + +} diff --git a/utils/test/test-parser-simple-tests.py b/utils/test/test-parser-simple-tests.py index 22a7b480b..04e03fb68 100644 --- a/utils/test/test-parser-simple-tests.py +++ b/utils/test/test-parser-simple-tests.py @@ -251,8 +251,8 @@ unknown_line = ( 'file/file/front_perms_ok_2.sd', 'file/front_perms_ok_2.sd', 'xtrans/simple_ok_cx_1.sd', - 'file/priority/front_perms_ok_1.sd', - 'file/priority/front_perms_ok_2.sd', + 'file/priority/front_perms_ok_3.sd', + 'file/priority/front_perms_ok_4.sd', # owner / audit {...} blocks 'file/file/owner/ok_1.sd', From 260ef98a959a46c9a090fdcb334a96df79eb44b3 Mon Sep 17 00:00:00 2001 From: Evan Caville Date: Thu, 27 Mar 2025 16:19:54 +1000 Subject: [PATCH 08/11] profiles/apparmor.d: add ssh-keyscan profile Signed-off-by: Evan Caville --- profiles/apparmor.d/ssh-keyscan | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 profiles/apparmor.d/ssh-keyscan diff --git a/profiles/apparmor.d/ssh-keyscan b/profiles/apparmor.d/ssh-keyscan new file mode 100644 index 000000000..a71012c05 --- /dev/null +++ b/profiles/apparmor.d/ssh-keyscan @@ -0,0 +1,33 @@ +#------------------------------------------------------------------ +# Copyright (C) 2025 Canonical Ltd. +# +# 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. +#------------------------------------------------------------------ +# vim: ft=apparmor +# +abi , + +include + +profile ssh-keyscan /usr/bin/ssh-keyscan { + include + include + + network inet dgram, + network inet6 dgram, + network inet stream, + network inet6 stream, + network netlink raw, + + # By default, limit file options to the following dirs + file r @{HOME}/.ssh/{,**}, + + # Allow executable mapping and read for the binary + file mr /usr/bin/ssh-keyscan, + + # Site-specific additions and overrides. See local/README for details. + include if exists +} + From 004dc61959dea60032a48b3e9cc45eec91e82201 Mon Sep 17 00:00:00 2001 From: Evan Caville Date: Fri, 2 May 2025 09:48:20 +1000 Subject: [PATCH 09/11] profiles/apparmor.d: remove file access Signed-off-by: Evan Caville --- profiles/apparmor.d/ssh-keyscan | 3 --- 1 file changed, 3 deletions(-) diff --git a/profiles/apparmor.d/ssh-keyscan b/profiles/apparmor.d/ssh-keyscan index a71012c05..7b05bfbbf 100644 --- a/profiles/apparmor.d/ssh-keyscan +++ b/profiles/apparmor.d/ssh-keyscan @@ -21,9 +21,6 @@ profile ssh-keyscan /usr/bin/ssh-keyscan { network inet6 stream, network netlink raw, - # By default, limit file options to the following dirs - file r @{HOME}/.ssh/{,**}, - # Allow executable mapping and read for the binary file mr /usr/bin/ssh-keyscan, From 3b1819db3777e043275632eb8b54469f60044998 Mon Sep 17 00:00:00 2001 From: Ryan Lee Date: Mon, 5 May 2025 17:16:06 -0700 Subject: [PATCH 10/11] fix incorrect mount flag documentation in apparmor.d man page The documentation was wrong about how options=(list) and options in (list) are combined Signed-off-by: Ryan Lee --- parser/apparmor.d.pod | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/parser/apparmor.d.pod b/parser/apparmor.d.pod index dfcb37077..9533155c8 100644 --- a/parser/apparmor.d.pod +++ b/parser/apparmor.d.pod @@ -1196,17 +1196,17 @@ using inode access times. Matches only: =item B<< mount options=(ro, atime) options in (nodev, user) /dev/foo -E /mnt/, >> -allow mounting /dev/foo on /mmt/ read only and using inode access times or -allow mounting /dev/foo on /mnt/ with some combination of 'nodev' and 'user'. +allow mounting /dev/foo on /mnt/ read only and using inode access times, in +addition to allowing some combination of 'nodev' and 'user' to be added on top. Matches only: $ mount -o ro,atime /dev/foo /mnt - $ mount -o nodev /dev/foo /mnt + $ mount -o ro,atime,nodev /dev/foo /mnt - $ mount -o user /dev/foo /mnt + $ mount -o ro,atime,user /dev/foo /mnt - $ mount -o nodev,user /dev/foo /mnt + $ mount -o ro,atime,nodev,user /dev/foo /mnt =back From 06e349345ed2cb4ef4c3f22851d7ddc2c4d5f6bf Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 25 Apr 2025 07:44:10 -0700 Subject: [PATCH 11/11] parser: fix failure to properly apply deny clearing in perms accumulation The internal permission accumulation is currently broken in that the ordering of rules matter to whether deny is clearing accumulated perms. If a deny node comes before an allow node the deny bits will get set but the following allow bits won't get cleared by the deny node. This isn't currently an actual issue for mediation as the deny bit will be applied at one of 1. apply_and_clear_deny 2. permission remapping 3. run time mediation but it does result in the internal state having sometimes having both allow and deny bits set, dependent on order of computation, resulting in state machines with different sizes because minimization partitioning is based on the internal permissions. This means that dfa minimization may not result in a truly minimal state machine, and even worse can cause inconsistenty and failure in tests that rely on internal state like the equality and minimization test, as seen in https://gitlab.com/apparmor/apparmor/-/issues/513 The failure was due to musl stl sets implementation producing a different ordering of the nodes than glibc. So when the permissions where accumulated the internal set of permissions were different. Fix this by giving the different node classes their own internal priority. This will ensure the bits are properly cleared for that priority before accumulating. Note: other ways of fixing. 1. Fixup internal accumulation to use accumulating perms of "higher" priority as part of the mask (deny and allow mask prompt). 2. Do a hard masking apply at the end after all bits have been accumulated (ie, in accept_perms after the for loop). the priority route was chosen because it is a little smaller and scales better if we get new Node types we have to deal with (eg. planned complain node). BugLink: https://gitlab.com/apparmor/apparmor/-/issues/513 Fixes: 1ebd99115 ("parser: change priority so that it accumulates based on permissions") Signed-off-by: John Johansen --- parser/libapparmor_re/hfa.cc | 61 +++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 470b58871..f40defb3e 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -1443,9 +1443,31 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, MatchFlag *match, perms_t &perms, perms_t &exact, bool filedfa) { - if (priority[i] > match->priority) { + // scaling priority *4 + int pri = match->priority<<2; + + /* use priority to get proper ordering and application of the type + * of match flag. + * + * Note: this is the last use of priority, it is dropped and not + * used in the backend. + */ + if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) + pri += 3; + // exact match must be same priority as allow as its audit + // flags has the same priority. + // current no ALLOWMATCHFLAG it is just absence of other flags + // so it has to be second last in this list, using !last + // until this gets fixed + else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG) || + (!match->is_type(NODE_TYPE_PROMPTMATCHFLAG))) + pri += 2; + else if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) + pri += 1; + + if (priority[i] > pri) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " > " << match->priority << " SKIPPING " << hex << (match->perms) << "/" << (match->audit) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " > " << pri << " SKIPPING " << hex << (match->perms) << "/" << (match->audit) << dec << "\n"; return 0; } @@ -1461,8 +1483,8 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, if (match->perms & AA_EXEC_INHERIT) { xmask |= AA_USER_EXEC_MMAP; //USER_EXEC_MAP = 6 - if (priority[6] < match->priority) - priority[6] = match->priority; + if (priority[6] < pri) + priority[6] = pri; } amask = mask | xmask; } else if (mask & AA_OTHER_EXEC) { @@ -1471,8 +1493,8 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, if (match->perms & AA_OTHER_EXEC_INHERIT) { xmask |= AA_OTHER_EXEC_MMAP; //OTHER_EXEC_MAP = 20 - if (priority[20] < match->priority) - priority[20] = match->priority; + if (priority[20] < pri) + priority[20] = pri; } amask = mask | xmask; } else if (((mask & AA_USER_EXEC_MMAP) && @@ -1481,17 +1503,17 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, (match->perms & AA_OTHER_EXEC_INHERIT))) { // if exec && ix we handled mmp above if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " SKIPPING mmap unmasked " << hex << match->perms << "/" << match->audit << " masked " << (match->perms & amask) << "/" << (match->audit & amask) << " data " << (perms.allow & mask) << "/" << (perms.audit & mask) << " exact " << (exact.allow & mask) << "/" << (exact.audit & mask) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " SKIPPING mmap unmasked " << hex << match->perms << "/" << match->audit << " masked " << (match->perms & amask) << "/" << (match->audit & amask) << " data " << (perms.allow & mask) << "/" << (perms.audit & mask) << " exact " << (exact.allow & mask) << "/" << (exact.audit & mask) << dec << "\n"; return 0; } } if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " vs. " << match->priority << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n"; - if (priority[i] < match->priority) { + cerr << " " << match << "[" << i << "]=" << priority[i] << " vs. " << pri << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n"; + if (priority[i] < pri) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << match->priority << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec; - priority[i] = match->priority; + cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << pri << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec; + priority[i] = pri; perms.clear_bits(amask); exact.clear_bits(amask); if (opts.dump & DUMP_DFA_PERMS) @@ -1501,7 +1523,7 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, // the if conditions in order of permission priority if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " deny " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " deny " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; perms.deny |= match->perms & amask; perms.quiet |= match->audit & amask; @@ -1511,11 +1533,11 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, } else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) { /* exact match only asserts dominance on the XTYPE */ if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " exact " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " exact " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; if (filedfa && !is_merged_x_consistent(exact.allow, match->perms & amask)) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " exact match conflict" << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " exact match conflict" << "\n"; return 1; } exact.allow |= match->perms & amask; @@ -1536,11 +1558,11 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, // allow perms, if exact has been encountered will already be set // if overlaps x here, don't conflict, because exact will override if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " allow " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " allow " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; if (filedfa && !(exact.allow & mask) && !is_merged_x_consistent(perms.allow, match->perms & amask)) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " allow match conflict" << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " allow match conflict" << "\n"; return 1; } // mask off if XTYPE in xmatch @@ -1554,11 +1576,11 @@ static int pri_update_perm(optflags const &opts, vector &priority, int i, } } else { // if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " prompt " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " prompt " << hex << (match->perms & amask) << "/" << (match->audit & amask) << dec << "\n"; if (filedfa && !((exact.allow | perms.allow) & mask) && !is_merged_x_consistent(perms.allow, match->perms & amask)) { if (opts.dump & DUMP_DFA_PERMS) - cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << match->priority << " prompt match conflict" << "\n"; + cerr << " " << match << "[" << i << "]=" << priority[i] << " <= " << pri << " prompt match conflict" << "\n"; return 1; } if ((exact.allow | exact.audit | perms.allow | perms.audit) & mask) { @@ -1584,7 +1606,8 @@ int accept_perms(optflags const &opts, NodeVec *state, perms_t &perms, { int error = 0; perms_t exact; - std::vector priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY); // 32 but wan't tied to perm32_t + // scaling priority by *4 + std::vector priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY<<2); // 32 but wan't tied to perm32_t perms.clear(); if (!state)