2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-22 01:57:43 +00:00

Merge branch 'master' into 'override'

# Conflicts:
#   parser/libapparmor_re/expr-tree.h
This commit is contained in:
John Johansen 2025-05-07 23:04:59 +00:00
commit 330d202586
77 changed files with 707 additions and 310 deletions

View File

@ -17,6 +17,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <dirent.h> #include <dirent.h>
#include <limits.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>

View File

@ -30,6 +30,8 @@
#include "profile.h" #include "profile.h"
#include "af_unix.h" #include "af_unix.h"
using namespace std;
/* See unix(7) for autobind address definition */ /* 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]"; #define autobind_address_pattern "\\x00[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]";

View File

@ -1196,17 +1196,17 @@ using inode access times. Matches only:
=item B<< mount options=(ro, atime) options in (nodev, user) /dev/foo -E<gt> /mnt/, >> =item B<< mount options=(ro, atime) options in (nodev, user) /dev/foo -E<gt> /mnt/, >>
allow mounting /dev/foo on /mmt/ read only and using inode access times or allow mounting /dev/foo on /mnt/ read only and using inode access times, in
allow mounting /dev/foo on /mnt/ with some combination of 'nodev' and 'user'. addition to allowing some combination of 'nodev' and 'user' to be added on top.
Matches only: Matches only:
$ mount -o ro,atime /dev/foo /mnt $ 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 =back

View File

@ -21,14 +21,12 @@
#include <set> #include <set>
#include <string> #include <string>
using namespace std;
/* TODO: have includecache be a frontend for file cache, don't just /* TODO: have includecache be a frontend for file cache, don't just
* store name. * store name.
*/ */
class IncludeCache_t { class IncludeCache_t {
public: public:
set<string> cache; std::set<std::string> cache;
IncludeCache_t() = default; IncludeCache_t() = default;
virtual ~IncludeCache_t() = default; virtual ~IncludeCache_t() = default;
@ -39,7 +37,7 @@ public:
} }
bool insert(const char *name) { bool insert(const char *name) {
pair<set<string>::iterator,bool> res = cache.insert(name); std::pair<std::set<std::string>::iterator,bool> res = cache.insert(name);
if (res.second == false) { if (res.second == false) {
return false; return false;
} }

View File

@ -28,6 +28,8 @@
#include "lib.h" #include "lib.h"
#include "parser.h" #include "parser.h"
using namespace std;
int dirat_for_each(int dirfd, const char *name, void *data, int dirat_for_each(int dirfd, const char *name, void *data,
int (* cb)(int, const char *, struct stat *, void *)) int (* cb)(int, const char *, struct stat *, void *))
{ {

View File

@ -34,6 +34,7 @@
#include "chfa.h" #include "chfa.h"
#include "../immunix.h" #include "../immunix.h"
using namespace std;
aare_rules::~aare_rules(void) aare_rules::~aare_rules(void)
{ {

View File

@ -59,7 +59,7 @@ public:
class UniquePermsCache { class UniquePermsCache {
public: public:
typedef map<UniquePerm, Node*> UniquePermMap; typedef std::map<UniquePerm, Node*> UniquePermMap;
typedef UniquePermMap::iterator iterator; typedef UniquePermMap::iterator iterator;
UniquePermMap nodes; UniquePermMap nodes;
@ -89,7 +89,7 @@ public:
node = new ExactMatchFlag(priority, perms, audit); node = new ExactMatchFlag(priority, perms, audit);
else else
node = new MatchFlag(priority, perms, audit); node = new MatchFlag(priority, perms, audit);
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node)); std::pair<iterator, bool> val = nodes.insert(std::make_pair(tmp, node));
if (val.second == false) { if (val.second == false) {
delete node; delete node;
return val.first->second; return val.first->second;
@ -121,17 +121,17 @@ class aare_rules {
optflags const &opts, bool oob); optflags const &opts, bool oob);
bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts); bool append_rule(const char *rule, bool oob, bool with_perm, optflags const &opts);
CHFA *create_chfa(int *min_match_len, CHFA *create_chfa(int *min_match_len,
vector <aa_perms> &perms_table, std::vector <aa_perms> &perms_table,
optflags const &opts, bool filedfa, optflags const &opts, bool filedfa,
bool extended_perms, bool prompt); bool extended_perms, bool prompt);
void *create_dfablob(size_t *size, int *min_match_len, void *create_dfablob(size_t *size, int *min_match_len,
vector <aa_perms> &perms_table, std::vector <aa_perms> &perms_table,
optflags const &opts, optflags const &opts,
bool filedfa, bool extended_perms, bool prompt); bool filedfa, bool extended_perms, bool prompt);
void *create_welded_dfablob(aare_rules *file_rules, void *create_welded_dfablob(aare_rules *file_rules,
size_t *size, int *min_match_len, size_t *size, int *min_match_len,
size_t *new_start, size_t *new_start,
vector <aa_perms> &perms_table, std::vector <aa_perms> &perms_table,
optflags const &opts, optflags const &opts,
bool extended_perms, bool prompt); bool extended_perms, bool prompt);
}; };

View File

@ -37,6 +37,8 @@
#include "../policydb.h" #include "../policydb.h"
#include "flex-tables.h" #include "flex-tables.h"
using namespace std;
void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list, void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
size_t prev, size_t start) size_t prev, size_t start)
{ {

View File

@ -32,39 +32,37 @@
#define MATCH_FLAG_OOB_TRANSITION 0x20000000 #define MATCH_FLAG_OOB_TRANSITION 0x20000000
#define base_mask_size(X) ((X) & ~BASE32_FLAGS) #define base_mask_size(X) ((X) & ~BASE32_FLAGS)
using namespace std; typedef std::vector<std::pair<const State *, size_t> > DefaultBase;
typedef std::vector<std::pair<const State *, const State *> > NextCheck;
typedef vector<pair<const State *, size_t> > DefaultBase;
typedef vector<pair<const State *, const State *> > NextCheck;
class CHFA { class CHFA {
public: public:
CHFA(void); CHFA(void);
CHFA(DFA &dfa, map<transchar, transchar> &eq, optflags const &opts, CHFA(DFA &dfa, std::map<transchar, transchar> &eq, optflags const &opts,
bool permindex, bool prompt); bool permindex, bool prompt);
void dump(ostream & os); void dump(ostream & os);
void flex_table(ostream &os, optflags const &opts); void flex_table(ostream &os, optflags const &opts);
void init_free_list(vector<pair<size_t, size_t> > &free_list, void init_free_list(std::vector<std::pair<size_t, size_t> > &free_list,
size_t prev, size_t start); size_t prev, size_t start);
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base, bool fits_in(std::vector<std::pair<size_t, size_t> > &free_list, size_t base,
StateTrans &cases); StateTrans &cases);
void insert_state(vector<pair<size_t, size_t> > &free_list, void insert_state(std::vector<std::pair<size_t, size_t> > &free_list,
State *state, DFA &dfa); State *state, DFA &dfa);
void weld_file_to_policy(CHFA &file_chfa, size_t &new_start, void weld_file_to_policy(CHFA &file_chfa, size_t &new_start,
bool accept_idx, bool prompt, bool accept_idx, bool prompt,
vector <aa_perms> &policy_perms, std::vector <aa_perms> &policy_perms,
vector <aa_perms> &file_perms); std::vector <aa_perms> &file_perms);
// private: // private:
// sigh templates suck, friend declaration does not work so for now // sigh templates suck, friend declaration does not work so for now
// make these public // make these public
vector<uint32_t> accept; std::vector<uint32_t> accept;
vector<uint32_t> accept2; std::vector<uint32_t> accept2;
DefaultBase default_base; DefaultBase default_base;
NextCheck next_check; NextCheck next_check;
const State *start; const State *start;
Renumber_Map num; Renumber_Map num;
map<transchar, transchar> eq; std::map<transchar, transchar> eq;
unsigned int chfaflags; unsigned int chfaflags;
private: private:
transchar max_eq; transchar max_eq;

View File

@ -38,6 +38,8 @@
#include "expr-tree.h" #include "expr-tree.h"
#include "apparmor_re.h" #include "apparmor_re.h"
using namespace std;
/* Use a single static EpsNode as it carries no node specific information */ /* Use a single static EpsNode as it carries no node specific information */
EpsNode epsnode; EpsNode epsnode;

View File

@ -44,8 +44,6 @@
#include "../perms.h" #include "../perms.h"
#include "apparmor_re.h" #include "apparmor_re.h"
using namespace std;
/* /*
* transchar - representative input character for state transitions * transchar - representative input character for state transitions
* *
@ -146,9 +144,9 @@ public:
class Chars { class Chars {
public: public:
set<transchar> chars; std::set<transchar> chars;
typedef set<transchar>::iterator iterator; typedef std::set<transchar>::iterator iterator;
iterator begin() { return chars.begin(); } iterator begin() { return chars.begin(); }
iterator end() { return chars.end(); } iterator end() { return chars.end(); }
@ -166,11 +164,11 @@ public:
{ {
return chars.find(key); return chars.find(key);
} }
pair<iterator,bool> insert(transchar c) std::pair<iterator,bool> insert(transchar c)
{ {
return chars.insert(c); return chars.insert(c);
} }
pair<iterator,bool> insert(char c) std::pair<iterator,bool> insert(char c)
{ {
transchar tmp(c); transchar tmp(c);
return chars.insert(tmp); return chars.insert(tmp);
@ -181,9 +179,9 @@ public:
ostream &operator<<(ostream &os, transchar c); ostream &operator<<(ostream &os, transchar c);
/* Compute the union of two sets. */ /* Compute the union of two sets. */
template<class T> set<T> operator+(const set<T> &a, const set<T> &b) template<class T> std::set<T> operator+(const std::set<T> &a, const std::set<T> &b)
{ {
set<T> c(a); std::set<T> c(a);
c.insert(b.begin(), b.end()); c.insert(b.begin(), b.end());
return c; return c;
} }
@ -196,7 +194,7 @@ template<class T> set<T> operator+(const set<T> &a, const set<T> &b)
*/ */
class Node; class Node;
class ImportantNode; class ImportantNode;
typedef set<ImportantNode *> NodeSet; typedef std::set<ImportantNode *> NodeSet;
/** /**
* Text-dump a state (for debugging). * 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. * enumerating all the explicit tranitions for default matches.
*/ */
typedef struct Cases { typedef struct Cases {
typedef map<transchar, NodeSet *>::iterator iterator; typedef std::map<transchar, NodeSet *>::iterator iterator;
iterator begin() { return cases.begin(); } iterator begin() { return cases.begin(); }
iterator end() { return cases.end(); } iterator end() { return cases.end(); }
Cases(): otherwise(0) { } Cases(): otherwise(0) { }
map<transchar, NodeSet *> cases; std::map<transchar, NodeSet *> cases;
NodeSet *otherwise; NodeSet *otherwise;
} Cases; } Cases;
@ -891,7 +889,8 @@ public:
{ {
type_flags |= NODE_TYPE_MATCHFLAG; type_flags |= NODE_TYPE_MATCHFLAG;
} }
ostream &dump(ostream &os) override { return os << "< 0x" << hex << perms << std::dec << '>'; }
ostream &dump(ostream &os) override { return os << "< 0x" << std::hex << perms << std::dec << '>'; }
int priority; int priority;
perm32_t perms; perm32_t perms;
@ -925,7 +924,7 @@ public:
/* Traverse the syntax tree depth-first in an iterator-like manner. */ /* Traverse the syntax tree depth-first in an iterator-like manner. */
class depth_first_traversal { class depth_first_traversal {
stack<Node *>pos; std::stack<Node *>pos;
void push_left(Node *node) { void push_left(Node *node) {
pos.push(node); pos.push(node);
@ -1051,7 +1050,7 @@ struct deref_less_than {
class NodeVecCache: public CacheStats { class NodeVecCache: public CacheStats {
public: public:
set<NodeVec *, deref_less_than> cache; std::set<NodeVec *, deref_less_than> cache;
NodeVecCache(void): cache() { }; NodeVecCache(void): cache() { };
~NodeVecCache() override { clear(); }; ~NodeVecCache() override { clear(); };
@ -1060,7 +1059,7 @@ public:
void clear() void clear()
{ {
for (set<NodeVec *>::iterator i = cache.begin(); for (std::set<NodeVec *>::iterator i = cache.begin();
i != cache.end(); i++) { i != cache.end(); i++) {
delete *i; delete *i;
} }
@ -1072,7 +1071,7 @@ public:
{ {
if (!nodes) if (!nodes)
return NULL; return NULL;
pair<set<NodeVec *>::iterator,bool> uniq; std::pair<std::set<NodeVec *>::iterator,bool> uniq;
NodeVec *nv = new NodeVec(nodes); NodeVec *nv = new NodeVec(nodes);
uniq = cache.insert(nv); uniq = cache.insert(nv);
if (uniq.second == false) { if (uniq.second == false) {

View File

@ -38,6 +38,8 @@
#include "../immunix.h" #include "../immunix.h"
#include "../perms.h" #include "../perms.h"
using namespace std;
ostream &operator<<(ostream &os, const CacheStats &cache) ostream &operator<<(ostream &os, const CacheStats &cache)
{ {
/* dump the state label */ /* dump the state label */
@ -1443,9 +1445,31 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
MatchFlag *match, perms_t &perms, perms_t &exact, MatchFlag *match, perms_t &perms, perms_t &exact,
bool filedfa) 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) 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; return 0;
} }
@ -1461,8 +1485,8 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
if (match->perms & AA_EXEC_INHERIT) { if (match->perms & AA_EXEC_INHERIT) {
xmask |= AA_USER_EXEC_MMAP; xmask |= AA_USER_EXEC_MMAP;
//USER_EXEC_MAP = 6 //USER_EXEC_MAP = 6
if (priority[6] < match->priority) if (priority[6] < pri)
priority[6] = match->priority; priority[6] = pri;
} }
amask = mask | xmask; amask = mask | xmask;
} else if (mask & AA_OTHER_EXEC) { } else if (mask & AA_OTHER_EXEC) {
@ -1471,8 +1495,8 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
if (match->perms & AA_OTHER_EXEC_INHERIT) { if (match->perms & AA_OTHER_EXEC_INHERIT) {
xmask |= AA_OTHER_EXEC_MMAP; xmask |= AA_OTHER_EXEC_MMAP;
//OTHER_EXEC_MAP = 20 //OTHER_EXEC_MAP = 20
if (priority[20] < match->priority) if (priority[20] < pri)
priority[20] = match->priority; priority[20] = pri;
} }
amask = mask | xmask; amask = mask | xmask;
} else if (((mask & AA_USER_EXEC_MMAP) && } else if (((mask & AA_USER_EXEC_MMAP) &&
@ -1481,17 +1505,17 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
(match->perms & AA_OTHER_EXEC_INHERIT))) { (match->perms & AA_OTHER_EXEC_INHERIT))) {
// if exec && ix we handled mmp above // if exec && ix we handled mmp above
if (opts.dump & DUMP_DFA_PERMS) 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; return 0;
} }
} }
if (opts.dump & DUMP_DFA_PERMS) if (opts.dump & DUMP_DFA_PERMS)
cerr << " " << match << "[" << i << "]=" << priority[i] << " vs. " << match->priority << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n"; cerr << " " << match << "[" << i << "]=" << priority[i] << " vs. " << pri << " mask: " << hex << mask << " xmask: " << xmask << " amask: " << amask << dec << "\n";
if (priority[i] < match->priority) { if (priority[i] < pri) {
if (opts.dump & DUMP_DFA_PERMS) if (opts.dump & DUMP_DFA_PERMS)
cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << match->priority << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec; cerr << " " << match << "[" << i << "]=" << priority[i] << " < " << pri << " clearing " << hex << (perms.allow & amask) << "/" << (perms.audit & amask) << " -> " << dec;
priority[i] = match->priority; priority[i] = pri;
perms.clear_bits(amask); perms.clear_bits(amask);
exact.clear_bits(amask); exact.clear_bits(amask);
if (opts.dump & DUMP_DFA_PERMS) if (opts.dump & DUMP_DFA_PERMS)
@ -1501,7 +1525,7 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
// the if conditions in order of permission priority // the if conditions in order of permission priority
if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
if (opts.dump & DUMP_DFA_PERMS) 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.deny |= match->perms & amask;
perms.quiet |= match->audit & amask; perms.quiet |= match->audit & amask;
@ -1511,11 +1535,11 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
} else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) { } else if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
/* exact match only asserts dominance on the XTYPE */ /* exact match only asserts dominance on the XTYPE */
if (opts.dump & DUMP_DFA_PERMS) 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 && if (filedfa &&
!is_merged_x_consistent(exact.allow, match->perms & amask)) { !is_merged_x_consistent(exact.allow, match->perms & amask)) {
if (opts.dump & DUMP_DFA_PERMS) 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; return 1;
} }
exact.allow |= match->perms & amask; exact.allow |= match->perms & amask;
@ -1536,11 +1560,11 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
// allow perms, if exact has been encountered will already be set // allow perms, if exact has been encountered will already be set
// if overlaps x here, don't conflict, because exact will override // if overlaps x here, don't conflict, because exact will override
if (opts.dump & DUMP_DFA_PERMS) 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) && if (filedfa && !(exact.allow & mask) &&
!is_merged_x_consistent(perms.allow, match->perms & amask)) { !is_merged_x_consistent(perms.allow, match->perms & amask)) {
if (opts.dump & DUMP_DFA_PERMS) 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; return 1;
} }
// mask off if XTYPE in xmatch // mask off if XTYPE in xmatch
@ -1554,11 +1578,11 @@ static int pri_update_perm(optflags const &opts, vector<int> &priority, int i,
} }
} else { // if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) { } else { // if (match->is_type(NODE_TYPE_PROMPTMATCHFLAG)) {
if (opts.dump & DUMP_DFA_PERMS) 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) && if (filedfa && !((exact.allow | perms.allow) & mask) &&
!is_merged_x_consistent(perms.allow, match->perms & amask)) { !is_merged_x_consistent(perms.allow, match->perms & amask)) {
if (opts.dump & DUMP_DFA_PERMS) 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; return 1;
} }
if ((exact.allow | exact.audit | perms.allow | perms.audit) & mask) { if ((exact.allow | exact.audit | perms.allow | perms.audit) & mask) {
@ -1584,7 +1608,8 @@ int accept_perms(optflags const &opts, NodeVec *state, perms_t &perms,
{ {
int error = 0; int error = 0;
perms_t exact; perms_t exact;
std::vector<int> priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY); // 32 but wan't tied to perm32_t // scaling priority by *4
std::vector<int> priority(sizeof(perm32_t)*8, MIN_INTERNAL_PRIORITY<<2); // 32 but wan't tied to perm32_t
perms.clear(); perms.clear();
if (!state) if (!state)

View File

@ -42,8 +42,8 @@ extern int prompt_compat_mode;
class State; class State;
typedef map<transchar, State *> StateTrans; typedef std::map<transchar, State *> StateTrans;
typedef list<State *> Partition; typedef std::list<State *> Partition;
#include "../immunix.h" #include "../immunix.h"
@ -62,9 +62,9 @@ public:
} }
ostream &dump(ostream &os) ostream &dump(ostream &os)
{ {
os << "(0x " << hex os << "(0x " << std::hex
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet << allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
<< ')' << dec; << ')' << std::dec;
return os; return os;
} }
@ -317,11 +317,11 @@ public:
class NodeMap: public CacheStats class NodeMap: public CacheStats
{ {
public: public:
typedef map<ProtoState, State *>::iterator iterator; typedef std::map<ProtoState, State *>::iterator iterator;
iterator begin() { return cache.begin(); } iterator begin() { return cache.begin(); }
iterator end() { return cache.end(); } iterator end() { return cache.end(); }
map<ProtoState, State *> cache; std::map<ProtoState, State *> cache;
NodeMap(void): cache() { }; NodeMap(void): cache() { };
~NodeMap() override { clear(); }; ~NodeMap() override { clear(); };
@ -334,10 +334,10 @@ public:
CacheStats::clear(); CacheStats::clear();
} }
pair<iterator,bool> insert(ProtoState &proto, State *state) std::pair<iterator,bool> insert(ProtoState &proto, State *state)
{ {
pair<iterator,bool> uniq; std::pair<iterator,bool> uniq;
uniq = cache.insert(make_pair(proto, state)); uniq = cache.insert(std::make_pair(proto, state));
if (uniq.second == false) { if (uniq.second == false) {
dup++; dup++;
} else { } else {
@ -349,7 +349,7 @@ public:
} }
}; };
typedef map<const State *, size_t> Renumber_Map; typedef std::map<const State *, size_t> Renumber_Map;
/* Transitions in the DFA. */ /* Transitions in the DFA. */
class DFA { class DFA {
@ -360,7 +360,7 @@ class DFA {
NodeSet *nnodes, State *other); NodeSet *nnodes, State *other);
void update_state_transitions(optflags const &opts, State *state); void update_state_transitions(optflags const &opts, State *state);
void process_work_queue(const char *header, optflags const &); void process_work_queue(const char *header, optflags const &);
void dump_diff_chain(ostream &os, map<State *, Partition> &relmap, void dump_diff_chain(ostream &os, std::map<State *, Partition> &relmap,
Partition &chain, State *state, Partition &chain, State *state,
unsigned int &count, unsigned int &total, unsigned int &count, unsigned int &total,
unsigned int &max); unsigned int &max);
@ -369,7 +369,7 @@ class DFA {
NodeVecCache anodes_cache; NodeVecCache anodes_cache;
NodeVecCache nnodes_cache; NodeVecCache nnodes_cache;
NodeMap node_map; NodeMap node_map;
list<State *> work_queue; std::list<State *> work_queue;
public: public:
DFA(Node *root, optflags const &flags, bool filedfa); DFA(Node *root, optflags const &flags, bool filedfa);
@ -394,14 +394,14 @@ public:
void dump_uniq_perms(const char *s); void dump_uniq_perms(const char *s);
ostream &dump_partition(ostream &os, Partition &p); ostream &dump_partition(ostream &os, Partition &p);
ostream &dump_partitions(ostream &os, const char *description, ostream &dump_partitions(ostream &os, const char *description,
list<Partition *> &partitions); std::list<Partition *> &partitions);
map<transchar, transchar> equivalence_classes(optflags const &flags); std::map<transchar, transchar> equivalence_classes(optflags const &flags);
void apply_equivalence_classes(map<transchar, transchar> &eq); void apply_equivalence_classes(std::map<transchar, transchar> &eq);
void compute_perms_table_ent(State *state, size_t pos, void compute_perms_table_ent(State *state, size_t pos,
vector <aa_perms> &perms_table, std::vector <aa_perms> &perms_table,
bool prompt); bool prompt);
void compute_perms_table(vector <aa_perms> &perms_table, void compute_perms_table(std::vector <aa_perms> &perms_table,
bool prompt); bool prompt);
unsigned int diffcount; unsigned int diffcount;
@ -415,6 +415,6 @@ public:
bool filedfa; bool filedfa;
}; };
void dump_equivalence_classes(ostream &os, map<transchar, transchar> &eq); void dump_equivalence_classes(ostream &os, std::map<transchar, transchar> &eq);
#endif /* __LIBAA_RE_HFA_H */ #endif /* __LIBAA_RE_HFA_H */

View File

@ -24,6 +24,8 @@
/* #define DEBUG_TREE */ /* #define DEBUG_TREE */
#include "expr-tree.h" #include "expr-tree.h"
using namespace std;
%} %}
%union { %union {
@ -60,7 +62,7 @@ static inline Chars* insert_char_range(Chars* cset, transchar a, transchar b)
%lex-param {YYLEX_PARAM} %lex-param {YYLEX_PARAM}
%parse-param {Node **root} %parse-param {Node **root}
%parse-param {const char *text} %parse-param {const char *text}
%name-prefix "regex_" %define api.prefix {regex_}
%token <c> CHAR %token <c> CHAR
%type <c> regex_char cset_char1 cset_char cset_charN %type <c> regex_char cset_char1 cset_char cset_charN

View File

@ -228,6 +228,8 @@
#include "profile.h" #include "profile.h"
#include "mount.h" #include "mount.h"
using namespace std;
struct mnt_keyword_table { struct mnt_keyword_table {
const char *keyword; const char *keyword;
unsigned int set; unsigned int set;

View File

@ -41,8 +41,6 @@
#include <string> #include <string>
using namespace std;
#include <set> #include <set>

View File

@ -41,6 +41,7 @@
#define SD_CODE_SIZE (sizeof(u8)) #define SD_CODE_SIZE (sizeof(u8))
#define SD_STR_LEN (sizeof(u16)) #define SD_STR_LEN (sizeof(u16))
using namespace std;
int __sd_serialize_profile(int option, aa_kernel_interface *kernel_interface, int __sd_serialize_profile(int option, aa_kernel_interface *kernel_interface,
Profile *prof, int cache_fd); Profile *prof, int cache_fd);

View File

@ -46,6 +46,8 @@
#include "policy_cache.h" #include "policy_cache.h"
#include "file_cache.h" #include "file_cache.h"
using namespace std;
#ifdef PDEBUG #ifdef PDEBUG
#undef PDEBUG #undef PDEBUG
#endif #endif

View File

@ -66,6 +66,8 @@ void *reallocarray(void *ptr, size_t nmemb, size_t size)
#define NULL nullptr #define NULL nullptr
#endif #endif
using namespace std;
int is_blacklisted(const char *name, const char *path) int is_blacklisted(const char *name, const char *path)
{ {
int retval = _aa_is_blacklisted(name); int retval = _aa_is_blacklisted(name);

View File

@ -45,6 +45,7 @@
#endif #endif
#define NPDEBUG(fmt, args...) /* Do nothing */ #define NPDEBUG(fmt, args...) /* Do nothing */
using namespace std;
ProfileList policy_list; ProfileList policy_list;

View File

@ -45,6 +45,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
using namespace std;
#define CIDR_32 htonl(0xffffffff) #define CIDR_32 htonl(0xffffffff)
#define CIDR_24 htonl(0xffffff00) #define CIDR_24 htonl(0xffffff00)

View File

@ -21,6 +21,8 @@
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
using namespace std;
const char *profile_mode_table[] = { const char *profile_mode_table[] = {
"", "",
"enforce", "enforce",

View File

@ -42,16 +42,16 @@ struct deref_profileptr_lt {
class ProfileList { class ProfileList {
public: public:
set<Profile *, deref_profileptr_lt> list; std::set<Profile *, deref_profileptr_lt> list;
typedef set<Profile *, deref_profileptr_lt>::iterator iterator; typedef std::set<Profile *, deref_profileptr_lt>::iterator iterator;
iterator begin() { return list.begin(); } iterator begin() { return list.begin(); }
iterator end() { return list.end(); } iterator end() { return list.end(); }
ProfileList() { }; ProfileList() { };
virtual ~ProfileList() { clear(); } virtual ~ProfileList() { clear(); }
virtual bool empty(void) { return list.empty(); } virtual bool empty(void) { return list.empty(); }
virtual pair<ProfileList::iterator,bool> insert(Profile *); virtual std::pair<ProfileList::iterator,bool> insert(Profile *);
virtual void erase(ProfileList::iterator pos); virtual void erase(ProfileList::iterator pos);
void clear(void); void clear(void);
void dump(void); void dump(void);
@ -368,7 +368,7 @@ struct dfa_stuff {
void *dfa; void *dfa;
size_t size; size_t size;
size_t file_start; /* special start in welded dfa */ size_t file_start; /* special start in welded dfa */
vector <aa_perms> perms_table; std::vector <aa_perms> perms_table;
dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { } dfa_stuff(void): rules(NULL), dfa(NULL), size(0) { }
}; };
@ -382,7 +382,7 @@ public:
void *xmatch; void *xmatch;
size_t xmatch_size; size_t xmatch_size;
int xmatch_len; int xmatch_len;
vector <aa_perms> xmatch_perms_table; std::vector <aa_perms> xmatch_perms_table;
struct cond_entry_list xattrs; struct cond_entry_list xattrs;
/* char *sub_name; */ /* subdomain name or NULL */ /* char *sub_name; */ /* subdomain name or NULL */
@ -477,7 +477,7 @@ public:
debug_cod_entries(entries); debug_cod_entries(entries);
for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++) { for (RuleList::iterator i = rule_ents.begin(); i != rule_ents.end(); i++) {
(*i)->dump(cout); (*i)->dump(std::cout);
} }
printf("\n"); printf("\n");
@ -511,7 +511,7 @@ public:
void dump_name(bool fqp) void dump_name(bool fqp)
{ {
cout << get_name(fqp);; std::cout << get_name(fqp);;
} }
void post_parse_profile(void); void post_parse_profile(void);

View File

@ -25,8 +25,6 @@
#include "perms.h" #include "perms.h"
#include "policydb.h" #include "policydb.h"
using namespace std;
#define PROMPT_COMPAT_UNKNOWN 0 #define PROMPT_COMPAT_UNKNOWN 0
#define PROMPT_COMPAT_IGNORE 1 #define PROMPT_COMPAT_IGNORE 1
#define PROMPT_COMPAT_PERMSV2 2 #define PROMPT_COMPAT_PERMSV2 2
@ -436,9 +434,9 @@ public:
class_rule_t::dump(os); class_rule_t::dump(os);
if (saved) if (saved)
os << "(0x" << hex << perms << "/orig " << saved << ") "; os << "(0x" << std::hex << perms << "/orig " << saved << ") ";
else else
os << "(0x" << hex << perms << ") "; os << "(0x" << std::hex << perms << ") ";
return os; return os;
} }
@ -464,7 +462,7 @@ public:
ostream &dump(ostream &os) override { ostream &dump(ostream &os) override {
class_rule_t::dump(os); class_rule_t::dump(os);
os << "(0x" << hex << perms << ") "; os << "(0x" << std::hex << perms << ") ";
return os; return os;
} }

View File

@ -30,6 +30,8 @@
#include "parser_yacc.h" #include "parser_yacc.h"
#include "signal.h" #include "signal.h"
using namespace std;
#define MAXMAPPED_SIG 35 #define MAXMAPPED_SIG 35
#define MINRT_SIG 128 /* base of RT sigs */ #define MINRT_SIG 128 /* base of RT sigs */
#define MAXRT_SIG 32 /* Max RT above MINRT_SIG */ #define MAXRT_SIG 32 /* Max RT above MINRT_SIG */

View File

@ -29,7 +29,7 @@
#define AA_VALID_SIGNAL_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE) #define AA_VALID_SIGNAL_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE)
typedef set<int> Signals; typedef std::set<int> Signals;
int find_signal_mapping(const char *sig); int find_signal_mapping(const char *sig);
int parse_signal_perms(const char *str_perms, perm32_t *perms, int fail); int parse_signal_perms(const char *str_perms, perm32_t *perms, int fail);

View File

@ -1223,7 +1223,7 @@ done
set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters
if [ $# -eq 0 -o -z $testtype] ; then if [ $# -eq 0 -o -z "$testtype" ] ; then
run_tests "$@" run_tests "$@"
exit $? exit $?
fi fi

View File

@ -15,10 +15,5 @@
priority=-1 file ux /foo3, priority=-1 file ux /foo3,
priority=-1 file Ux /foo4, priority=-1 file Ux /foo4,
priority=-1 file ix /foo5, 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,
} }

View File

@ -15,10 +15,5 @@
priority=-1 ux /foo3, priority=-1 ux /foo3,
priority=-1 Ux /foo4, priority=-1 Ux /foo4,
priority=-1 ix /foo5, 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,
} }

View File

@ -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,
}

View File

@ -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,
}

View File

@ -0,0 +1,30 @@
#------------------------------------------------------------------
# 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 <abi/4.0>,
include <tunables/global>
profile ssh-keyscan /usr/bin/ssh-keyscan {
include <abstractions/base>
include <abstractions/nameservice-strict>
network inet dgram,
network inet6 dgram,
network inet stream,
network inet6 stream,
network netlink raw,
# 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 <local/ssh-keyscan>
}

View File

@ -21,7 +21,7 @@ from apparmor.translations import init_translation
_ = init_translation() _ = init_translation()
# Profile parsing Regex # Profile parsing Regex
RE_AUDIT_DENY = r'^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+)?' # line start, optionally: leading whitespace, <audit> and <allow>/deny RE_PRIORITY_AUDIT_DENY = r'^\s*(priority\s*=\s*(?P<priority>[+-]?[0-9]*)\s+)?(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+)?' # line start, optionally: leading whitespace, <priority> = number, <audit> and <allow>/deny
RE_EOL = r'\s*(?P<comment>#.*?)?\s*$' # optional whitespace, optional <comment>, optional whitespace, end of the line RE_EOL = r'\s*(?P<comment>#.*?)?\s*$' # optional whitespace, optional <comment>, optional whitespace, end of the line
RE_COMMA_EOL = r'\s*,' + RE_EOL # optional whitespace, comma + RE_EOL RE_COMMA_EOL = r'\s*,' + RE_EOL # optional whitespace, comma + RE_EOL
@ -34,8 +34,8 @@ RE_XATTRS = r'(\s+xattrs\s*=\s*\((?P<xattrs>([^)=]+(=[^)=]+)?\s?)+)\)\s*)?'
RE_FLAGS = r'(\s+(flags\s*=\s*)?\((?P<flags>[^)]+)\))?' RE_FLAGS = r'(\s+(flags\s*=\s*)?\((?P<flags>[^)]+)\))?'
RE_PROFILE_END = re.compile(r'^\s*\}' + RE_EOL) RE_PROFILE_END = re.compile(r'^\s*\}' + RE_EOL)
RE_PROFILE_ALL = re.compile(RE_AUDIT_DENY + r'all' + RE_COMMA_EOL) RE_PROFILE_ALL = re.compile(RE_PRIORITY_AUDIT_DENY + r'all' + RE_COMMA_EOL)
RE_PROFILE_CAP = re.compile(RE_AUDIT_DENY + r'capability(?P<capability>(\s+\S+)+)?' + RE_COMMA_EOL) RE_PROFILE_CAP = re.compile(RE_PRIORITY_AUDIT_DENY + r'capability(?P<capability>(\s+\S+)+)?' + RE_COMMA_EOL)
RE_PROFILE_ALIAS = re.compile(r'^\s*alias\s+(?P<orig_path>"??.+?"??)\s+->\s*(?P<target>"??.+?"??)' + RE_COMMA_EOL) RE_PROFILE_ALIAS = re.compile(r'^\s*alias\s+(?P<orig_path>"??.+?"??)\s+->\s*(?P<target>"??.+?"??)' + RE_COMMA_EOL)
RE_PROFILE_RLIMIT = re.compile(r'^\s*set\s+rlimit\s+(?P<rlimit>[a-z]+)\s*<=\s*(?P<value>[^ ]+(\s+[a-zA-Z]+)?)' + RE_COMMA_EOL) RE_PROFILE_RLIMIT = re.compile(r'^\s*set\s+rlimit\s+(?P<rlimit>[a-z]+)\s*<=\s*(?P<value>[^ ]+(\s+[a-zA-Z]+)?)' + RE_COMMA_EOL)
RE_PROFILE_BOOLEAN = re.compile(r'^\s*(?P<varname>\$\{?\w*\}?)\s*=\s*(?P<value>true|false)\s*,?' + RE_EOL, flags=re.IGNORECASE) RE_PROFILE_BOOLEAN = re.compile(r'^\s*(?P<varname>\$\{?\w*\}?)\s*=\s*(?P<value>true|false)\s*,?' + RE_EOL, flags=re.IGNORECASE)
@ -43,18 +43,18 @@ RE_PROFILE_VARIABLE = re.compile(r'^\s*(?P<varname>@\{?\w+\}?)\s*(?P<mode>\+?=)\
RE_PROFILE_CONDITIONAL = re.compile(r'^\s*if\s+(not\s+)?(\$\{?\w*\}?)\s*\{' + RE_EOL) 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_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_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<details>\s+.*)?' + RE_COMMA_EOL) RE_PROFILE_NETWORK = re.compile(RE_PRIORITY_AUDIT_DENY + r'network(?P<details>\s+.*)?' + RE_COMMA_EOL)
RE_PROFILE_CHANGE_HAT = re.compile(r'^\s*\^("??.+?"??)' + RE_COMMA_EOL) RE_PROFILE_CHANGE_HAT = re.compile(r'^\s*\^("??.+?"??)' + RE_COMMA_EOL)
RE_PROFILE_HAT_DEF = re.compile(r'^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>"??[^)]+?"??)' + RE_FLAGS + r'\s*\{' + RE_EOL) RE_PROFILE_HAT_DEF = re.compile(r'^(?P<leadingspace>\s*)(?P<hat_keyword>\^|hat\s+)(?P<hat>"??[^)]+?"??)' + RE_FLAGS + r'\s*\{' + RE_EOL)
RE_PROFILE_DBUS = re.compile(RE_AUDIT_DENY + r'(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_DBUS = re.compile(RE_PRIORITY_AUDIT_DENY + r'(dbus\s*,|dbus(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_MOUNT = re.compile(RE_AUDIT_DENY + r'((?P<operation>mount|remount|umount|unmount)(?P<details>\s+[^#]*)?\s*,)' + RE_EOL) RE_PROFILE_MOUNT = re.compile(RE_PRIORITY_AUDIT_DENY + r'((?P<operation>mount|remount|umount|unmount)(?P<details>\s+[^#]*)?\s*,)' + RE_EOL)
RE_PROFILE_SIGNAL = re.compile(RE_AUDIT_DENY + r'(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_SIGNAL = re.compile(RE_PRIORITY_AUDIT_DENY + r'(signal\s*,|signal(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PTRACE = re.compile(RE_AUDIT_DENY + r'(ptrace\s*,|ptrace(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_PTRACE = re.compile(RE_PRIORITY_AUDIT_DENY + r'(ptrace\s*,|ptrace(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_PIVOT_ROOT = re.compile(RE_AUDIT_DENY + r'(pivot_root\s*,|pivot_root(?P<details>\s+[^#]*),)' + RE_EOL) RE_PROFILE_PIVOT_ROOT = re.compile(RE_PRIORITY_AUDIT_DENY + r'(pivot_root\s*,|pivot_root(?P<details>\s+[^#]*),)' + RE_EOL)
RE_PROFILE_UNIX = re.compile(RE_AUDIT_DENY + r'(unix\s*,|unix(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_UNIX = re.compile(RE_PRIORITY_AUDIT_DENY + r'(unix\s*,|unix(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_USERNS = re.compile(RE_AUDIT_DENY + r'(userns\s*,|userns(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_USERNS = re.compile(RE_PRIORITY_AUDIT_DENY + r'(userns\s*,|userns(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_MQUEUE = re.compile(RE_AUDIT_DENY + r'(mqueue\s*,|mqueue(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_MQUEUE = re.compile(RE_PRIORITY_AUDIT_DENY + r'(mqueue\s*,|mqueue(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
RE_PROFILE_IO_URING = re.compile(RE_AUDIT_DENY + r'(io_uring\s*,|io_uring(?P<details>\s+[^#]*)\s*,)' + RE_EOL) RE_PROFILE_IO_URING = re.compile(RE_PRIORITY_AUDIT_DENY + r'(io_uring\s*,|io_uring(?P<details>\s+[^#]*)\s*,)' + RE_EOL)
# match anything that's not " or #, or matching quotes with anything except quotes inside # match anything that's not " or #, or matching quotes with anything except quotes inside
__re_no_or_quoted_hash = '([^#"]|"[^"]*")*' __re_no_or_quoted_hash = '([^#"]|"[^"]*")*'
@ -81,7 +81,7 @@ RE_PROFILE_START = re.compile(
RE_PROFILE_CHANGE_PROFILE = re.compile( RE_PROFILE_CHANGE_PROFILE = re.compile(
RE_AUDIT_DENY RE_PRIORITY_AUDIT_DENY
+ 'change_profile' + 'change_profile'
+ r'(\s+' + RE_SAFE_OR_UNSAFE + ')?' # optionally exec mode + r'(\s+' + RE_SAFE_OR_UNSAFE + ')?' # optionally exec mode
+ r'(\s+' + RE_PROFILE_PATH_OR_VAR % 'execcond' + ')?' # optionally exec condition + 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_PATH_PERMS = '(?P<%s>[mrwalkPUCpucix]+)'
RE_PROFILE_FILE_ENTRY = re.compile( RE_PROFILE_FILE_ENTRY = re.compile(
RE_AUDIT_DENY RE_PRIORITY_AUDIT_DENY
+ r'(?P<owner>owner\s+)?' # optionally: <owner> + r'(?P<owner>owner\s+)?' # optionally: <owner>
+ '(' + '('
+ '(?P<bare_file>file)' # bare 'file,' # noqa: E131 + '(?P<bare_file>file)' # bare 'file,' # noqa: E131

View File

@ -41,8 +41,10 @@ class BaseRule(metaclass=ABCMeta):
_match_re = None _match_re = None
def __init__(self, audit=False, deny=False, allow_keyword=False, 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""" """initialize variables needed by all rule types"""
self._store_priority(priority)
self.audit = audit self.audit = audit
self.deny = deny self.deny = deny
self.allow_keyword = allow_keyword self.allow_keyword = allow_keyword
@ -52,6 +54,21 @@ class BaseRule(metaclass=ABCMeta):
# Set only in the parse() class method # Set only in the parse() class method
self.raw_rule = None 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): def _aare_or_all(self, rulepart, partname, is_path, log_event, empty_ok=False):
"""checks rulepart and returns """checks rulepart and returns
- (AARE, False) if rulepart is a (non-empty) string - (AARE, False) if rulepart is a (non-empty) string
@ -233,7 +250,9 @@ class BaseRule(metaclass=ABCMeta):
"""compare if rule_obj == self """compare if rule_obj == self
Calls _is_equal_localvars() to compare rule-specific variables""" 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 return False
if strict and ( if strict and (
@ -282,6 +301,9 @@ class BaseRule(metaclass=ABCMeta):
headers = [] headers = []
qualifier = [] qualifier = []
if self.priority:
qualifier.append('priority=%s' % self.priority)
if self.audit: if self.audit:
qualifier.append('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))) raise NotImplementedError("'%s' needs to implement store_edit(), but didn't" % (str(self)))
def modifiers_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: if self.audit:
auditstr = 'audit ' auditstr = 'audit '
@ -332,7 +359,17 @@ class BaseRule(metaclass=ABCMeta):
else: else:
allowstr = '' allowstr = ''
return '%s%s' % (auditstr, allowstr) return '%s%s%s' % (prioritystr, 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__)
if self.priority is not None:
raise AppArmorBug('Attempt to initialize %s with priority' % self.__class__.__name__)
class BaseRuleset: class BaseRuleset:
@ -565,9 +602,16 @@ def parse_comment(matches):
def parse_modifiers(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 - audit, deny and allow_keyword are True/False
- comment is the comment with a leading space""" - comment is the comment with a leading space"""
priority = None
if matches.group('priority'):
priority = int(matches.group('priority'))
audit = False audit = False
if matches.group('audit'): if matches.group('audit'):
audit = True audit = True
@ -586,7 +630,7 @@ def parse_modifiers(matches):
comment = parse_comment(matches) comment = parse_comment(matches)
return (audit, deny, allow_keyword, comment) return (priority, audit, deny, allow_keyword, comment)
def quote_if_needed(data): def quote_if_needed(data):

View File

@ -29,11 +29,11 @@ class AbiRule(IncludeRule):
_match_re = RE_ABI _match_re = RE_ABI
def __init__(self, path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, 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, super().__init__(path, ifexists, ismagic,
audit=audit, deny=deny, allow_keyword=allow_keyword, 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' # abi doesn't support 'if exists'
if ifexists: if ifexists:

View File

@ -27,16 +27,13 @@ class AliasRule(BaseRule):
_match_re = RE_PROFILE_ALIAS _match_re = RE_PROFILE_ALIAS
def __init__(self, orig_path, target, audit=False, deny=False, allow_keyword=False, 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, 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 audit or deny # aliases don't support priority, allow keyword, audit or deny
if audit: self.ensure_modifiers_not_supported()
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__)
if not isinstance(orig_path, str): if not isinstance(orig_path, str):
raise AppArmorBug('Passed unknown type for orig_path to %s: %s' % (self.__class__.__name__, orig_path)) raise AppArmorBug('Passed unknown type for orig_path to %s: %s' % (self.__class__.__name__, orig_path))
@ -65,7 +62,7 @@ class AliasRule(BaseRule):
target = strip_quotes(matches.group('target').strip()) target = strip_quotes(matches.group('target').strip())
return cls(orig_path, target, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -29,10 +29,10 @@ class AllRule(BaseRule):
_match_re = RE_PROFILE_ALL _match_re = RE_PROFILE_ALL
def __init__(self, audit=False, deny=False, allow_keyword=False, 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, 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 # no localvars -> nothing more to do
@ -40,11 +40,11 @@ class AllRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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, return cls(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment) comment=comment, priority=priority)
def get_clean(self, depth=0): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -28,16 +28,13 @@ class BooleanRule(BaseRule):
_match_re = RE_PROFILE_BOOLEAN _match_re = RE_PROFILE_BOOLEAN
def __init__(self, varname, value, audit=False, deny=False, allow_keyword=False, 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, 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 audit or deny # boolean variables don't support priority, allow keyword, audit or deny
if audit: self.ensure_modifiers_not_supported()
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__)
if not isinstance(varname, str): if not isinstance(varname, str):
raise AppArmorBug('Passed unknown type for boolean variable to %s: %s' % (self.__class__.__name__, varname)) raise AppArmorBug('Passed unknown type for boolean variable to %s: %s' % (self.__class__.__name__, varname))
@ -66,7 +63,7 @@ class BooleanRule(BaseRule):
value = matches.group('value') value = matches.group('value')
return cls(varname, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -46,10 +46,10 @@ class CapabilityRule(BaseRule):
_match_re = RE_PROFILE_CAP _match_re = RE_PROFILE_CAP
def __init__(self, cap_list, audit=False, deny=False, allow_keyword=False, 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, 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, # Because we support having multiple caps in one rule,
# initializer needs to accept a list of caps. # initializer needs to accept a list of caps.
self.all_caps = False self.all_caps = False
@ -78,7 +78,7 @@ class CapabilityRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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'): if matches.group('capability'):
capability = matches.group('capability').strip() capability = matches.group('capability').strip()
@ -88,7 +88,7 @@ class CapabilityRule(BaseRule):
return cls(capability, audit=audit, deny=deny, return cls(capability, audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment) comment=comment, priority=priority)
def get_clean(self, depth=0): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -37,11 +37,11 @@ class ChangeProfileRule(BaseRule):
_match_re = RE_PROFILE_CHANGE_PROFILE _match_re = RE_PROFILE_CHANGE_PROFILE
def __init__(self, execmode, execcond, targetprofile, audit=False, deny=False, allow_keyword=False, 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 ]""" """CHANGE_PROFILE RULE = 'change_profile' [ [ EXEC MODE ] EXEC COND ] [ -> PROGRAMCHILD ]"""
super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, 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:
if execmode != 'safe' and execmode != 'unsafe': if execmode != 'safe' and execmode != 'unsafe':
@ -80,7 +80,7 @@ class ChangeProfileRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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') execmode = matches.group('execmode')
@ -95,7 +95,7 @@ class ChangeProfileRule(BaseRule):
targetprofile = cls.ALL targetprofile = cls.ALL
return cls(execmode, execcond, targetprofile, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -80,10 +80,10 @@ class DbusRule(BaseRule):
_match_re = RE_PROFILE_DBUS _match_re = RE_PROFILE_DBUS
def __init__(self, access, bus, path, name, interface, member, peername, peerlabel, 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, 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') self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access')
if unknown_items: if unknown_items:
@ -112,7 +112,7 @@ class DbusRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -186,7 +186,8 @@ class DbusRule(BaseRule):
peerlabel = cls.ALL peerlabel = cls.ALL
return cls(access, bus, path, name, interface, member, peername, peerlabel, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -47,7 +47,7 @@ class FileRule(BaseRule):
_match_re = RE_PROFILE_FILE_ENTRY _match_re = RE_PROFILE_FILE_ENTRY
def __init__(self, path, perms, exec_perms, target, owner, file_keyword=False, leading_perms=False, 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 """Initialize object
Parameters: Parameters:
@ -61,7 +61,7 @@ class FileRule(BaseRule):
""" """
super().__init__(audit=audit, deny=deny, allow_keyword=allow_keyword, 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 # rulepart partperms is_path log_event
self.path, self.all_paths = self._aare_or_all(path, 'path', True, log_event) # noqa: E221 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): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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')) owner = bool(matches.group('owner'))
@ -183,7 +183,7 @@ class FileRule(BaseRule):
file_keyword = bool(matches.group('file_keyword')) file_keyword = bool(matches.group('file_keyword'))
return cls(path, perms, exec_perms, target, owner, file_keyword, leading_perms, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -28,16 +28,13 @@ class IncludeRule(BaseRule):
_match_re = RE_INCLUDE _match_re = RE_INCLUDE
def __init__(self, path, ifexists, ismagic, audit=False, deny=False, allow_keyword=False, 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, 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 audit or deny # include doesn't support priority, allow keyword, audit or deny
if audit: self.ensure_modifiers_not_supported()
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__)
if not isinstance(ifexists, bool): if not isinstance(ifexists, bool):
raise AppArmorBug('Passed unknown type for ifexists to %s: %s' % (self.__class__.__name__, ifexists)) raise AppArmorBug('Passed unknown type for ifexists to %s: %s' % (self.__class__.__name__, ifexists))
@ -62,7 +59,7 @@ class IncludeRule(BaseRule):
path, ifexists, ismagic = re_match_include_parse(raw_rule, cls.rule_name) path, ifexists, ismagic = re_match_include_parse(raw_rule, cls.rule_name)
return cls(path, ifexists, ismagic, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -51,12 +51,12 @@ class IOUringRule(BaseRule):
_match_re = RE_PROFILE_IO_URING _match_re = RE_PROFILE_IO_URING
def __init__(self, access, label, audit=False, deny=False, 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, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, 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') self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access')
if unknown_items: if unknown_items:
@ -68,7 +68,7 @@ class IOUringRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -96,7 +96,7 @@ class IOUringRule(BaseRule):
label = cls.ALL label = cls.ALL
return cls(access, label, audit=audit, deny=deny, 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): def get_clean(self, depth=0):
'''return rule (in clean/default formatting)''' '''return rule (in clean/default formatting)'''

View File

@ -112,12 +112,15 @@ class MountRule(BaseRule):
rule_name = 'mount' rule_name = 'mount'
_match_re = RE_PROFILE_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, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, comment=comment,
log_event=log_event) log_event=log_event,
priority=priority)
self.operation = operation self.operation = operation
@ -164,7 +167,7 @@ class MountRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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') operation = matches.group('operation')
@ -223,7 +226,9 @@ class MountRule(BaseRule):
source = cls.ALL source = cls.ALL
dest = 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): def get_clean(self, depth=0):
space = ' ' * depth space = ' ' * depth

View File

@ -62,12 +62,13 @@ class MessageQueueRule(BaseRule):
def __init__(self, access, mqueue_type, label, mqueue_name, def __init__(self, access, mqueue_type, label, mqueue_name,
audit=False, deny=False, allow_keyword=False, audit=False, deny=False, allow_keyword=False,
comment='', log_event=None): comment='', log_event=None, priority=None):
super().__init__(audit=audit, deny=deny, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, 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') self.access, self.all_access, unknown_items = check_and_split_list(access, access_keywords, self.ALL, type(self).__name__, 'access')
if unknown_items: if unknown_items:
@ -92,7 +93,7 @@ class MessageQueueRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -132,7 +133,7 @@ class MessageQueueRule(BaseRule):
mqueue_name = cls.ALL mqueue_name = cls.ALL
return cls(access, mqueue_type, label, mqueue_name, 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): def get_clean(self, depth=0):
'''return rule (in clean/default formatting)''' '''return rule (in clean/default formatting)'''

View File

@ -92,10 +92,10 @@ class NetworkRule(BaseRule):
_match_re = RE_PROFILE_NETWORK _match_re = RE_PROFILE_NETWORK
def __init__(self, accesses, domain, type_or_protocol, local_expr, peer_expr, audit=False, deny=False, 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, 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 type(local_expr) is tuple:
if accesses is None: if accesses is None:
@ -159,7 +159,7 @@ class NetworkRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -191,7 +191,7 @@ class NetworkRule(BaseRule):
peer_expr = cls.ALL peer_expr = cls.ALL
return cls(accesses, domain, type_or_protocol, local_expr, peer_expr, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -47,12 +47,13 @@ class PivotRootRule(BaseRule):
_match_re = RE_PROFILE_PIVOT_ROOT _match_re = RE_PROFILE_PIVOT_ROOT
# PIVOT ROOT RULE = [ QUALIFIERS ] pivot_root [ oldroot=OLD PUT FILEGLOB ] [ NEW ROOT FILEGLOB ] [ -> PROFILE NAME ] # 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, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, 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.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 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): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -100,7 +101,7 @@ class PivotRootRule(BaseRule):
profile_name = cls.ALL profile_name = cls.ALL
return cls(oldroot=oldroot, newroot=newroot, profile_name=profile_name, 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): def get_clean(self, depth=0):
space = ' ' * depth space = ' ' * depth

View File

@ -53,10 +53,10 @@ class PtraceRule(BaseRule):
_match_re = RE_PROFILE_PTRACE _match_re = RE_PROFILE_PTRACE
def __init__(self, access, peer, audit=False, deny=False, allow_keyword=False, 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, 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( self.access, self.all_access, unknown_items = check_and_split_list(
access, access_keywords, self.ALL, type(self).__name__, 'access') access, access_keywords, self.ALL, type(self).__name__, 'access')
@ -69,7 +69,7 @@ class PtraceRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -98,7 +98,7 @@ class PtraceRule(BaseRule):
peer = cls.ALL peer = cls.ALL
return cls(access, peer, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -49,13 +49,13 @@ class RlimitRule(BaseRule):
_match_re = RE_PROFILE_RLIMIT _match_re = RE_PROFILE_RLIMIT
def __init__(self, rlimit, value, audit=False, deny=False, allow_keyword=False, 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, 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 audit or deny or allow_keyword: # rlimit rules don't support priority, allow keyword, audit or deny
raise AppArmorBug('The audit, allow or deny keywords are not allowed in rlimit rules.') self.ensure_modifiers_not_supported()
if isinstance(rlimit, str): if isinstance(rlimit, str):
if rlimit in rlimit_all: if rlimit in rlimit_all:

View File

@ -78,10 +78,10 @@ class SignalRule(BaseRule):
_match_re = RE_PROFILE_SIGNAL _match_re = RE_PROFILE_SIGNAL
def __init__(self, access, signal, peer, audit=False, deny=False, allow_keyword=False, 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, 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( self.access, self.all_access, unknown_items = check_and_split_list(
access, access_keywords, self.ALL, type(self).__name__, 'access') access, access_keywords, self.ALL, type(self).__name__, 'access')
@ -103,7 +103,7 @@ class SignalRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
"""parse raw_rule and return instance of this class""" """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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -141,7 +141,7 @@ class SignalRule(BaseRule):
peer = cls.ALL peer = cls.ALL
return cls(access, signal, peer, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -65,12 +65,14 @@ class UnixRule(BaseRule):
rule_name = 'unix' rule_name = 'unix'
_match_re = RE_PROFILE_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, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, 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 if type(rule_conds) is tuple: # This comes from the logparser, we convert it to dicts
accesses = strip_parenthesis(accesses).replace(',', ' ').split() accesses = strip_parenthesis(accesses).replace(',', ' ').split()
@ -96,7 +98,7 @@ class UnixRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -124,7 +126,8 @@ class UnixRule(BaseRule):
local_expr = cls.ALL local_expr = cls.ALL
peer_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): def get_clean(self, depth=0):
space = ' ' * depth space = ' ' * depth

View File

@ -44,12 +44,13 @@ class UserNamespaceRule(BaseRule):
_match_re = RE_PROFILE_USERNS _match_re = RE_PROFILE_USERNS
def __init__(self, access, audit=False, deny=False, 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, super().__init__(audit=audit, deny=deny,
allow_keyword=allow_keyword, allow_keyword=allow_keyword,
comment=comment, 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') self.access, self.all_access, unknown_items = check_and_split_list(access, access_keyword, self.ALL, type(self).__name__, 'access')
if unknown_items: if unknown_items:
@ -59,7 +60,7 @@ class UserNamespaceRule(BaseRule):
def _create_instance(cls, raw_rule, matches): def _create_instance(cls, raw_rule, matches):
'''parse raw_rule and return instance of this class''' '''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 = '' rule_details = ''
if matches.group('details'): if matches.group('details'):
@ -75,7 +76,7 @@ class UserNamespaceRule(BaseRule):
access = cls.ALL access = cls.ALL
return cls(access, audit=audit, deny=deny, return cls(access, audit=audit, deny=deny,
allow_keyword=allow_keyword, comment=comment) allow_keyword=allow_keyword, comment=comment, priority=priority)
@staticmethod @staticmethod
def hashlog_from_event(hl, e): def hashlog_from_event(hl, e):

View File

@ -30,16 +30,13 @@ class VariableRule(BaseRule):
_match_re = RE_PROFILE_VARIABLE _match_re = RE_PROFILE_VARIABLE
def __init__(self, varname, mode, values, audit=False, deny=False, allow_keyword=False, 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, 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 audit or deny # variables don't support priority, allow keyword, audit or deny
if audit: self.ensure_modifiers_not_supported()
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__)
if not isinstance(varname, str): if not isinstance(varname, str):
raise AppArmorBug('Passed unknown type for varname to %s: %s' % (self.__class__.__name__, varname)) raise AppArmorBug('Passed unknown type for varname to %s: %s' % (self.__class__.__name__, varname))
@ -73,7 +70,7 @@ class VariableRule(BaseRule):
values = separate_vars(matches.group('values')) values = separate_vars(matches.group('values'))
return cls(varname, mode, 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): def get_clean(self, depth=0):
"""return rule (in clean/default formatting)""" """return rule (in clean/default formatting)"""

View File

@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'orig_path', 'target'))
class AliasTest(AATest): class AliasTest(AATest):
def _compare_obj(self, obj, expected): 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.allow_keyword)
self.assertEqual(False, obj.audit) self.assertEqual(False, obj.audit)
self.assertEqual(False, obj.deny) self.assertEqual(False, obj.deny)
self.assertEqual(None, obj.priority)
self.assertEqual(expected.orig_path, obj.orig_path) self.assertEqual(expected.orig_path, obj.orig_path)
self.assertEqual(expected.target, obj.target) self.assertEqual(expected.target, obj.target)
@ -114,6 +115,14 @@ class InvalidAliasInit(AATest):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
AliasRule('/foo', '/bar', deny=True) 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): class InvalidAliasTest(AATest):
def _check_invalid_rawrule(self, rawrule, matches_regex=False): def _check_invalid_rawrule(self, rawrule, matches_regex=False):

View File

@ -116,6 +116,7 @@ class WriteAllTestAATest(AATest):
(' deny all ,# foo bar', 'deny all, # foo bar'), (' deny all ,# foo bar', 'deny all, # foo bar'),
(' allow all ,# foo bar', 'allow all, # foo bar'), (' allow all ,# foo bar', 'allow all, # foo bar'),
(' allow all ,', 'allow all,'), (' allow all ,', 'allow all,'),
(' priority = -2 allow all ,', 'priority=-2 allow all,'),
) )
def _run_test(self, rawrule, expected): def _run_test(self, rawrule, expected):

View File

@ -71,7 +71,7 @@ class TestBaserule(AATest):
self.ValidSubclass.match('foo') self.ValidSubclass.match('foo')
def test_parse_modifiers_invalid(self): def test_parse_modifiers_invalid(self):
regex = re.compile(r'^\s*(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+|invalid\s+)?') regex = re.compile(r'^\s*(priority\s*=\s*(?P<priority>[+-]?[0-9]*)\s+)?(?P<audit>audit\s+)?(?P<allow>allow\s+|deny\s+|invalid\s+)?')
matches = regex.search('audit invalid ') matches = regex.search('audit invalid ')
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):

View File

@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'varname', 'value'))
class BooleanTest(AATest): class BooleanTest(AATest):
def _compare_obj(self, obj, expected): 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.allow_keyword)
self.assertEqual(False, obj.audit) self.assertEqual(False, obj.audit)
self.assertEqual(False, obj.deny) self.assertEqual(False, obj.deny)
self.assertEqual(None, obj.priority)
self.assertEqual(expected.varname, obj.varname) self.assertEqual(expected.varname, obj.varname)
self.assertEqual(expected.value, obj.value) self.assertEqual(expected.value, obj.value)
@ -122,6 +123,14 @@ class InvalidBooleanInit(AATest):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
BooleanRule('$foo', 'true', deny=True) 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): class InvalidBooleanTest(AATest):
def _check_invalid_rawrule(self, rawrule, matches_regex=False): def _check_invalid_rawrule(self, rawrule, matches_regex=False):

View File

@ -314,6 +314,18 @@ class WriteCapabilityTest(AATest):
self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule') self.assertEqual(expected, obj.get_clean(2), 'unexpected clean rule')
self.assertEqual(expected, obj.get_raw(2), 'unexpected raw 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): class CapabilityCoveredTest(AATest):
def _is_covered(self, obj, rule_to_test): def _is_covered(self, obj, rule_to_test):

View File

@ -225,6 +225,10 @@ class WriteChangeProfileTestAATest(AATest):
(' allow change_profile -> /bar ,# foo bar', 'allow change_profile -> /bar, # foo bar'), (' 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 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",'), (' 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): def _run_test(self, rawrule, expected):

View File

@ -419,6 +419,10 @@ class WriteDbusTest(AATest):
('dbus receive peer=(label=foo),', 'dbus receive peer=(label=foo),'), ('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 (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 ('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 # XXX add more complex rules
) )

View File

@ -415,6 +415,10 @@ class WriteFileTest(AATest):
(' /foo r,', '/foo r,'), (' /foo r,', '/foo r,'),
(' /foo lwr,', '/foo rwl,'), (' /foo lwr,', '/foo rwl,'),
(' /foo Pxrm -> bar,', '/foo mrPx -> bar,'), (' /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 # with leading permissions
(' audit file r /foo,', 'audit file r /foo,'), (' audit file r /foo,', 'audit file r /foo,'),
@ -432,11 +436,19 @@ class WriteFileTest(AATest):
(' r /foo ,', 'r /foo,'), (' r /foo ,', 'r /foo,'),
(' klwr /foo ,', 'rwlk /foo,'), (' klwr /foo ,', 'rwlk /foo,'),
(' Pxrm /foo -> bar,', 'mrPx /foo -> bar,'), (' 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 rules
(' link /foo -> /bar,', 'link /foo -> /bar,'), (' link /foo -> /bar,', 'link /foo -> /bar,'),
(' audit deny owner link subset /foo -> /bar,', 'audit deny owner link subset /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): def test_write_manually_1(self):
@ -851,6 +863,8 @@ class FileLogprofHeaderTest(AATest):
(('allow file /baz rwk,', set(), set()), [_('Qualifier'), 'allow', _('Path'), '/baz', _('New Mode'), 'rwk']), (('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 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']), (('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 (('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']), (('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('r'), set()), [ _('Path'), '/foo', _('Old Mode'), _('r'), _('New Mode'), 'rw']), # noqa: E201

View File

@ -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.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.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(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.comment, obj.comment)
self.assertEqual(expected.path, obj.path) self.assertEqual(expected.path, obj.path)
@ -159,6 +160,10 @@ class InvalidIncludeInit(AATest):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
IncludeRule('foo', False, False, deny=True) IncludeRule('foo', False, False, deny=True)
def test_priority_true(self):
with self.assertRaises(AppArmorBug):
IncludeRule('foo', False, False, priority=0)
class InvalidIncludeTest(AATest): class InvalidIncludeTest(AATest):
def _check_invalid_rawrule(self, rawrule, matches_regex=False): def _check_invalid_rawrule(self, rawrule, matches_regex=False):

View File

@ -64,10 +64,10 @@ class IOUringTestParseInvalid(AATest):
IOUringRule.create_instance('foo,') IOUringRule.create_instance('foo,')
def test_diff_non_iouringrule(self): def test_diff_non_iouringrule(self):
exp = namedtuple('exp', ('audit', 'deny')) exp = namedtuple('exp', ('audit', 'deny', 'priority'))
obj = IOUringRule(('sqpoll'), IOUringRule.ALL) obj = IOUringRule(('sqpoll'), IOUringRule.ALL)
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
obj.is_equal(exp(False, False), False) obj.is_equal(exp(False, False, None), False)
def test_diff_access(self): def test_diff_access(self):
obj1 = IOUringRule(IOUringRule.ALL, IOUringRule.ALL) 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 sqpoll label="tst",', 'io_uring sqpoll label="tst",'),
('io_uring (override_creds) label=bar,', 'io_uring override_creds label=bar,'), ('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,'), ('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): def _run_test(self, rawrule, expected):

View File

@ -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)

View File

@ -123,10 +123,10 @@ class MountTestParseInvalid(AATest):
MountRule.create_instance('foo,') MountRule.create_instance('foo,')
def test_diff_non_mountrule(self): 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) obj = MountRule('mount', ('=', ['ext4']), MountRule.ALL, MountRule.ALL, MountRule.ALL)
with self.assertRaises(AppArmorBug): 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): def test_diff_invalid_fstype_equals_or_in(self):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
@ -230,6 +230,12 @@ class MountTestClean(AATest):
(' umount /foo , ', 'umount /foo,'), (' umount /foo , ', 'umount /foo,'),
(' remount , ', 'remount,'), (' remount , ', 'remount,'),
(' remount /foo , ', 'remount /foo,'), (' 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): def _run_test(self, rawrule, expected):

View File

@ -77,10 +77,10 @@ class MessageQueueTestParseInvalid(AATest):
MessageQueueRule.create_instance('foo,') MessageQueueRule.create_instance('foo,')
def test_diff_non_mqueuerule(self): def test_diff_non_mqueuerule(self):
exp = namedtuple('exp', ('audit', 'deny')) exp = namedtuple('exp', ('audit', 'deny', 'priority'))
obj = MessageQueueRule(('open'), 'posix', 'bar', '/foo') obj = MessageQueueRule(('open'), 'posix', 'bar', '/foo')
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
obj.is_equal(exp(False, False), False) obj.is_equal(exp(False, False, None), False)
def test_diff_access(self): def test_diff_access(self):
obj1 = MessageQueueRule(('open'), 'posix', 'bar', '/foo') 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 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=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,'), ('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): def _run_test(self, rawrule, expected):

View File

@ -286,6 +286,10 @@ class WriteNetworkTestAATest(AATest):
(' network stream peer = ( ip=::1 port=22 ) ,', 'network stream peer=(ip=::1 port=22),'), (' 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,'), (' 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'), (' 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'),
) )

View File

@ -35,9 +35,6 @@ skip_startswith = (
# Pux and Cux (which actually mean PUx and CUx) get rejected by the tools # Pux and Cux (which actually mean PUx and CUx) get rejected by the tools
'generated_x/exact-', 'generated_x/exact-',
# don't handle rule priorities yet
'file/priority/',
) )
# testcases that should raise an exception, but don't # testcases that should raise an exception, but don't
@ -246,11 +243,16 @@ unknown_line = (
'file/ok_other_1.sd', 'file/ok_other_1.sd',
'file/ok_other_2.sd', 'file/ok_other_2.sd',
'file/ok_other_3.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 # 'unsafe' keyword
'file/file/front_perms_ok_2.sd', 'file/file/front_perms_ok_2.sd',
'file/front_perms_ok_2.sd', 'file/front_perms_ok_2.sd',
'xtrans/simple_ok_cx_1.sd', 'xtrans/simple_ok_cx_1.sd',
'file/priority/front_perms_ok_3.sd',
'file/priority/front_perms_ok_4.sd',
# owner / audit {...} blocks # owner / audit {...} blocks
'file/file/owner/ok_1.sd', 'file/file/owner/ok_1.sd',
@ -355,6 +357,9 @@ syntax_failure = (
'file/ok_5.sd', # Invalid mode UX 'file/ok_5.sd', # Invalid mode UX
'file/ok_2.sd', # Invalid mode RWM 'file/ok_2.sd', # Invalid mode RWM
'file/ok_4.sd', # Invalid mode iX '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_pix_1.sd', # Invalid mode pIx
'xtrans/simple_ok_pux_1.sd', # Invalid mode rPux 'xtrans/simple_ok_pux_1.sd', # Invalid mode rPux
@ -424,6 +429,8 @@ syntax_failure = (
'file/ok_embedded_spaces_4.sd', # \-escaped space 'file/ok_embedded_spaces_4.sd', # \-escaped space
'file/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/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. # 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. # Therefore MountRule intentionally raises an exception when parsing such a rule.

View File

@ -261,6 +261,10 @@ class WritePivotRootTestAATest(AATest):
(' pivot_root oldroot="/old" , # foo ', 'pivot_root oldroot=/old, # foo'), (' 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 -> some_profile , ', 'pivot_root oldroot=/old -> some_profile,'),
(' pivot_root oldroot=/old /new -> some_profile , ', 'pivot_root oldroot=/old /new -> 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): def test_write_manually(self):

View File

@ -260,6 +260,10 @@ class WritePtraceTestAATest(AATest):
('ptrace (read tracedby) peer=/usr/bin/bar,', 'ptrace (read tracedby) peer=/usr/bin/bar,'), ('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 (trace read) peer=/usr/bin/bar,', 'ptrace (read trace) peer=/usr/bin/bar,'),
('ptrace wr peer=/sbin/baz,', 'ptrace wr peer=/sbin/baz,'), ('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): def test_write_manually(self):

View File

@ -218,11 +218,16 @@ class AARegexCapability(AARegexTest):
self.regex = RE_PROFILE_CAP self.regex = RE_PROFILE_CAP
tests = ( tests = (
(' capability net_raw,', (None, None, 'net_raw', 'net_raw', None)), (' capability net_raw,', (None, None, None, None, 'net_raw', 'net_raw', None)),
('capability net_raw , ', (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)), (' capability,', (None, None, None, None, None, None, None)),
(' capability , ', (None, None, None, None, None)), (' capability , ', (None, None, None, None, None, None, None)),
(' capabilitynet_raw,', False) (' 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 self.regex = RE_PROFILE_DBUS
tests = ( tests = (
(' dbus,', (None, None, 'dbus,', None, None)), (' dbus,', (None, None, None, None, 'dbus,', None, None)),
(' audit dbus,', ('audit', None, 'dbus,', None, None)), (' audit dbus,', (None, None, '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,', (None, None, 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 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), (' dbusdriver,', False),
(' audit dbusdriver,', False), (' audit dbusdriver,', False),
(' priority=-11 audit dbusdriver,', False),
) )
@ -250,19 +261,30 @@ class AARegexMount(AARegexTest):
self.regex = RE_PROFILE_MOUNT self.regex = RE_PROFILE_MOUNT
tests = ( tests = (
(' mount,', (None, None, 'mount,', 'mount', None, None)), (' mount,', (None, None, None, None, 'mount,', 'mount', None, None)),
(' audit mount,', ('audit', None, 'mount,', 'mount', None, None)), (' audit mount,', (None, None, 'audit', None, 'mount,', 'mount', None, None)),
(' umount,', (None, None, 'umount,', 'umount', None, None)), (' umount,', (None, None, None, None, 'umount,', 'umount', None, None)),
(' audit umount,', ('audit', None, 'umount,', 'umount', None, None)), (' audit umount,', (None, None, 'audit', None, 'umount,', 'umount', None, None)),
(' unmount,', (None, None, 'unmount,', 'unmount', None, None)), (' unmount,', (None, None, None, None, 'unmount,', 'unmount', None, None)),
(' audit unmount,', ('audit', None, 'unmount,', 'unmount', None, None)), (' audit unmount,', (None, None, 'audit', None, 'unmount,', 'unmount', None, None)),
(' remount,', (None, None, 'remount,', 'remount', None, None)), (' remount,', (None, None, None, None, 'remount,', 'remount', None, None)),
(' deny remount,', (None, 'deny', '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), (' mountain,', False),
(' audit mountain,', False), (' audit mountain,', False),
(' priority = 0 audit mountain,', False),
) )
@ -273,16 +295,25 @@ class AARegexSignal(AARegexTest):
self.regex = RE_PROFILE_SIGNAL self.regex = RE_PROFILE_SIGNAL
tests = ( tests = (
(' signal,', (None, None, 'signal,', None, None)), (' signal,', (None, None, None, None, 'signal,', None, None)),
(' audit signal,', ('audit', None, 'signal,', None, None)), (' audit signal,', (None, None, 'audit', None, 'signal,', None, None)),
(' signal receive,', (None, None, 'signal receive,', 'receive', None)), (' signal receive,', (None, None, None, None, 'signal receive,', 'receive', None)),
(' signal (send, receive),', (None, None, 'signal (send, receive),', '(send, receive)', None)), (' signal (send, receive),', (None, None, None, None, 'signal (send, receive),', '(send, receive)', None)),
(' audit signal (receive),', ('audit', None, 'signal (receive),', '(receive)', None)), (' audit signal (receive),', (None, None, '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, 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, 'signal send set=(hup, quit) peer=/usr/sbin/daemon,', 'send set=(hup, quit) peer=/usr/sbin/daemon', 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), (' signalling,', False),
(' audit signalling,', False), (' audit signalling,', False),
(' priority = -1 audit signalling,', False),
(' signalling receive,', False), (' signalling receive,', False),
) )
@ -294,16 +325,24 @@ class AARegexPtrace(AARegexTest):
self.regex = RE_PROFILE_PTRACE self.regex = RE_PROFILE_PTRACE
tests = ( tests = (
# audit allow rule rule details comment # priority audit allow rule rule details comment
(' ptrace,', (None, None, 'ptrace,', None, None)), (' ptrace,', (None, None, None, None, 'ptrace,', None, None)),
(' audit ptrace,', ('audit', None, 'ptrace,', None, None)), (' audit ptrace,', (None, None, 'audit', None, 'ptrace,', None, None)),
(' ptrace trace,', (None, None, 'ptrace trace,', 'trace', None)), (' ptrace trace,', (None, None, None, None, 'ptrace trace,', 'trace', None)),
(' ptrace (tracedby, readby),', (None, None, 'ptrace (tracedby, readby),', '(tracedby, readby)', None)), (' ptrace (tracedby, readby),', (None, None, None, None, 'ptrace (tracedby, readby),', '(tracedby, readby)', None)),
(' audit ptrace (read),', ('audit', None, 'ptrace (read),', '(read)', None)), (' audit ptrace (read),', (None, None, '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)), (' 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), (' ptraceback,', False),
(' audit ptraceback,', False), (' audit ptraceback,', False),
(' priority=100 audit ptraceback,', False),
(' ptraceback trace,', False), (' ptraceback trace,', False),
) )
@ -315,12 +354,19 @@ class AARegexPivotRoot(AARegexTest):
self.regex = RE_PROFILE_PIVOT_ROOT self.regex = RE_PROFILE_PIVOT_ROOT
tests = ( tests = (
(' pivot_root,', (None, None, 'pivot_root,', None, None)), (' pivot_root,', (None, None, None, None, 'pivot_root,', None, None)),
(' audit pivot_root,', ('audit', None, 'pivot_root,', None, None)), (' audit pivot_root,', (None, None, '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,', (None, None, 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,', (None, None, 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)), (' 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,', ('audit', 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 ('pivot_root', False), # comma missing
@ -329,6 +375,7 @@ class AARegexPivotRoot(AARegexTest):
('pivot_rootbeer, # comment', False), ('pivot_rootbeer, # comment', False),
('pivot_rootbeer /new, ', False), ('pivot_rootbeer /new, ', False),
('pivot_rootbeer /new, # comment', 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 self.regex = RE_PROFILE_UNIX
tests = ( tests = (
(' unix,', (None, None, 'unix,', None, None)), (' unix,', (None, None, None, None, 'unix,', None, None)),
(' audit unix,', ('audit', None, 'unix,', None, None)), (' audit unix,', (None, None, 'audit', None, 'unix,', None, None)),
(' unix accept,', (None, None, 'unix accept,', 'accept', None)), (' unix accept,', (None, None, None, None, 'unix accept,', 'accept', None)),
(' allow unix connect,', (None, 'allow', 'unix connect,', 'connect', None)), (' allow unix connect,', (None, None, None, 'allow', 'unix connect,', 'connect', None)),
(' audit allow unix bind,', ('audit', 'allow', 'unix bind,', 'bind', None)), (' audit allow unix bind,', (None, None, 'audit', 'allow', 'unix bind,', 'bind', None)),
(' deny unix bind,', (None, 'deny', 'unix bind,', 'bind', None)), (' deny unix bind,', (None, None, None, 'deny', 'unix bind,', 'bind', None)),
('unix peer=(label=@{profile_name}),', (None, None, 'unix peer=(label=@{profile_name}),', 'peer=(label=@{profile_name})', 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, 'unix (receive) peer=(label=unconfined),', '(receive) peer=(label=unconfined)', 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, 'unix (getattr, shutdown) peer=(addr=none),', '(getattr, shutdown) peer=(addr=none)', 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, 'unix (connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*"),', ('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 '(connect, receive, send) type=stream peer=(label=unconfined,addr="@/tmp/dbus-*")', # noqa: E127
None)), # 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), ('unixlike', False),
('deny unixlike,', False), ('deny unixlike,', False),
('priority=1 deny unixlike,', False),
) )

View File

@ -174,6 +174,10 @@ class InvalidRlimitInit(AATest):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
RlimitRule('as', '1024MB', audit=True) RlimitRule('as', '1024MB', audit=True)
def test_priority_keyword(self):
with self.assertRaises(AppArmorBug):
RlimitRule('as', '1024MB', priority=0)
class InvalidRlimitTest(AATest): class InvalidRlimitTest(AATest):
def _check_invalid_rawrule(self, rawrule): def _check_invalid_rawrule(self, rawrule):

View File

@ -277,6 +277,10 @@ class WriteSignalTestAATest(AATest):
('signal receive peer=foo,', 'signal receive peer=foo,'), ('signal receive peer=foo,', 'signal receive peer=foo,'),
('signal (send receive) peer=/usr/bin/bar,', 'signal (receive send) peer=/usr/bin/bar,'), ('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,'), ('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): def test_write_manually(self):

View File

@ -174,7 +174,10 @@ class UnixTestClean(AATest):
(' unix , # foo ', 'unix, # foo'), (' unix , # foo ', 'unix, # foo'),
(' unix addr = foo , ', 'unix addr=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),'), (' 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): def _run_test(self, rawrule, expected):

View File

@ -59,10 +59,10 @@ class UserNamespaceTestParseInvalid(AATest):
UserNamespaceRule.create_instance('foo,') UserNamespaceRule.create_instance('foo,')
def test_diff_non_usernsrule(self): def test_diff_non_usernsrule(self):
exp = namedtuple('exp', ('audit', 'deny')) exp = namedtuple('exp', ('audit', 'deny', 'priority'))
obj = UserNamespaceRule(('create')) obj = UserNamespaceRule(('create'))
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
obj.is_equal(exp(False, False), False) obj.is_equal(exp(False, False, None), False)
def test_diff_access(self): def test_diff_access(self):
obj1 = UserNamespaceRule(UserNamespaceRule.ALL) obj1 = UserNamespaceRule(UserNamespaceRule.ALL)
@ -98,6 +98,10 @@ class WriteUserNamespaceTestAATest(AATest):
(' allow userns create ,# foo bar', 'allow userns create, # foo bar'), (' allow userns create ,# foo bar', 'allow userns create, # foo bar'),
('userns,', 'userns,'), ('userns,', 'userns,'),
('userns create,', 'userns create,'), ('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): def _run_test(self, rawrule, expected):

View File

@ -30,10 +30,11 @@ exp = namedtuple('exp', ('comment', 'varname', 'mode', 'values'))
class VariableTest(AATest): class VariableTest(AATest):
def _compare_obj(self, obj, expected): 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.allow_keyword)
self.assertEqual(False, obj.audit) self.assertEqual(False, obj.audit)
self.assertEqual(False, obj.deny) self.assertEqual(False, obj.deny)
self.assertEqual(None, obj.priority)
self.assertEqual(expected.varname, obj.varname) self.assertEqual(expected.varname, obj.varname)
self.assertEqual(expected.mode, obj.mode) self.assertEqual(expected.mode, obj.mode)
@ -166,6 +167,14 @@ class InvalidVariableInit(AATest):
with self.assertRaises(AppArmorBug): with self.assertRaises(AppArmorBug):
VariableRule('@{foo}', '=', '/bar', deny=True) 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): class InvalidVariableTest(AATest):
def _check_invalid_rawrule(self, rawrule, matches_regex=False): def _check_invalid_rawrule(self, rawrule, matches_regex=False):