parser: minimization - remove unnecessary second minimization pass

Moving apply_and_clear_deny() before the first minimization pass, which
was necessary to propperly support building accept information for
older none extended permission dfas, allows us to also get rid of doing a
second minimization pass if we want to force clearing explicit deny
info from extended permission tables.

Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2024-05-10 03:06:22 -07:00
parent 1fa45b7c1f
commit 2737cb2c2b
21 changed files with 477 additions and 150 deletions

View file

@ -344,7 +344,8 @@ int unix_rule::gen_policy_re(Profile &prof)
write_to_prot(buffer); write_to_prot(buffer);
if ((mask & AA_NET_CREATE) && !has_peer_conds()) { if ((mask & AA_NET_CREATE) && !has_peer_conds()) {
buf = buffer.str(); buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode,
map_perms(AA_NET_CREATE), map_perms(AA_NET_CREATE),
map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0), map_perms(audit == AUDIT_FORCE ? AA_NET_CREATE : 0),
parseopts)) parseopts))
@ -369,7 +370,8 @@ int unix_rule::gen_policy_re(Profile &prof)
tmp << "\\x00"; tmp << "\\x00";
buf = tmp.str(); buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode,
map_perms(AA_NET_BIND), map_perms(AA_NET_BIND),
map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0), map_perms(audit == AUDIT_FORCE ? AA_NET_BIND : 0),
parseopts)) parseopts))
@ -394,7 +396,8 @@ int unix_rule::gen_policy_re(Profile &prof)
AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD; AA_LOCAL_NET_PERMS & ~AA_LOCAL_NET_CMD;
if (mask & local_mask) { if (mask & local_mask) {
buf = buffer.str(); buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode,
map_perms(mask & local_mask), map_perms(mask & local_mask),
map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0), map_perms(audit == AUDIT_FORCE ? mask & local_mask : 0),
parseopts)) parseopts))
@ -408,7 +411,9 @@ int unix_rule::gen_policy_re(Profile &prof)
/* TODO: backlog conditional: for now match anything*/ /* TODO: backlog conditional: for now match anything*/
tmp << ".."; tmp << "..";
buf = tmp.str(); buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(),
priority,
rule_mode,
map_perms(AA_NET_LISTEN), map_perms(AA_NET_LISTEN),
map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0), map_perms(audit == AUDIT_FORCE ? AA_NET_LISTEN : 0),
parseopts)) parseopts))
@ -422,6 +427,7 @@ int unix_rule::gen_policy_re(Profile &prof)
tmp << ".."; tmp << "..";
buf = tmp.str(); buf = tmp.str();
if (!prof.policy.rules->add_rule(buf.c_str(), if (!prof.policy.rules->add_rule(buf.c_str(),
priority,
rule_mode, rule_mode,
map_perms(mask & AA_NET_OPT), map_perms(mask & AA_NET_OPT),
map_perms(audit == AUDIT_FORCE ? map_perms(audit == AUDIT_FORCE ?
@ -444,7 +450,10 @@ int unix_rule::gen_policy_re(Profile &prof)
goto fail; goto fail;
buf = buffer.str(); buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms & AA_PEER_NET_PERMS), map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0), parseopts)) if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode, map_perms(perms & AA_PEER_NET_PERMS),
map_perms(audit == AUDIT_FORCE ? perms & AA_PEER_NET_PERMS : 0),
parseopts))
goto fail; goto fail;
} }

View file

@ -274,23 +274,24 @@ int dbus_rule::gen_policy_re(Profile &prof)
} }
if (perms & AA_DBUS_BIND) { if (perms & AA_DBUS_BIND) {
if (!prof.policy.rules->add_rule_vec(rule_mode, perms & AA_DBUS_BIND, if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0, perms & AA_DBUS_BIND,
2, vec, parseopts, false)) audit == AUDIT_FORCE ? perms & AA_DBUS_BIND : 0,
2, vec, parseopts, false))
goto fail; goto fail;
} }
if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) { if (perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE)) {
if (!prof.policy.rules->add_rule_vec(rule_mode, if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE), perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE),
audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0, audit == AUDIT_FORCE ? perms & (AA_DBUS_SEND | AA_DBUS_RECEIVE) : 0,
6, vec, parseopts, false)) 6, vec, parseopts, false))
goto fail; goto fail;
} }
if (perms & AA_DBUS_EAVESDROP) { if (perms & AA_DBUS_EAVESDROP) {
if (!prof.policy.rules->add_rule_vec(rule_mode, if (!prof.policy.rules->add_rule_vec(priority, rule_mode,
perms & AA_DBUS_EAVESDROP, perms & AA_DBUS_EAVESDROP,
audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0, audit == AUDIT_FORCE ? perms & AA_DBUS_EAVESDROP : 0,
1, vec, parseopts, false)) 1, vec, parseopts, false))
goto fail; goto fail;
} }

View file

@ -122,16 +122,18 @@ int io_uring_rule::gen_policy_re(Profile &prof)
} }
if (perms & AA_VALID_IO_URING_PERMS) { if (perms & AA_VALID_IO_URING_PERMS) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
audit == AUDIT_FORCE ? perms : 0, rule_mode, perms,
parseopts)) audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail; goto fail;
if (perms & AA_IO_URING_OVERRIDE_CREDS) { if (perms & AA_IO_URING_OVERRIDE_CREDS) {
buf = buffer.str(); /* update buf to have label */ buf = buffer.str(); /* update buf to have label */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(),
perms, audit == AUDIT_FORCE ? perms : 0, priority, rule_mode,
parseopts)) perms, audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail; goto fail;
} }

View file

@ -44,10 +44,11 @@ aare_rules::~aare_rules(void)
expr_map.clear(); expr_map.clear();
} }
bool aare_rules::add_rule(const char *rule, rule_mode_t mode, perm32_t perms, bool aare_rules::add_rule(const char *rule, int priority, rule_mode_t mode,
perm32_t audit, optflags const &opts) perm32_t perms, perm32_t audit, optflags const &opts)
{ {
return add_rule_vec(mode, perms, audit, 1, &rule, opts, false); return add_rule_vec(priority, mode, perms, audit, 1, &rule, opts,
false);
} }
void aare_rules::add_to_rules(Node *tree, Node *perms) void aare_rules::add_to_rules(Node *tree, Node *perms)
@ -71,9 +72,9 @@ static Node *cat_with_oob_separator(Node *l, Node *r)
return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r); return new CatNode(new CatNode(l, new CharNode(transchar(-1, true))), r);
} }
bool aare_rules::add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit, bool aare_rules::add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
int count, const char **rulev, optflags const &opts, perm32_t audit, int count, const char **rulev,
bool oob) optflags const &opts, bool oob)
{ {
Node *tree = NULL, *accept; Node *tree = NULL, *accept;
int exact_match; int exact_match;
@ -107,7 +108,7 @@ bool aare_rules::add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit,
if (reverse) if (reverse)
flip_tree(tree); flip_tree(tree);
accept = unique_perms.insert(mode, perms, audit, exact_match); accept = unique_perms.insert(priority, mode, perms, audit, exact_match);
if (opts.dump & DUMP_DFA_RULE_EXPR) { if (opts.dump & DUMP_DFA_RULE_EXPR) {
const char *separator; const char *separator;
@ -124,6 +125,7 @@ bool aare_rules::add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit,
cerr << " -> "; cerr << " -> ";
tree->dump(cerr); tree->dump(cerr);
// TODO: split out from prefixes class // TODO: split out from prefixes class
cerr << " priority=" << priority;
if (mode == RULE_DENY) if (mode == RULE_DENY)
cerr << " deny"; cerr << " deny";
else if (mode == RULE_PROMPT) else if (mode == RULE_PROMPT)
@ -256,6 +258,20 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
if (opts.dump & DUMP_DFA_UNIQ_PERMS) if (opts.dump & DUMP_DFA_UNIQ_PERMS)
dfa.dump_uniq_perms("dfa"); dfa.dump_uniq_perms("dfa");
/* since we are building a chfa, use the info about
* whether the chfa supports extended perms to help
* determine whether we clear the deny info.
* This will let us build the minimal dfa for the
* information supported by the backed
*/
if (!extended_perms ||
// TODO: we should drop DFA_MINIMIZE check here but doing
// so changes behavior. Do as a separate patch and fixup
// tests, etc.
((opts.control & CONTROL_DFA_FILTER_DENY) &&
(opts.control & CONTROL_DFA_MINIMIZE)))
dfa.apply_and_clear_deny();
if (opts.control & CONTROL_DFA_MINIMIZE) { if (opts.control & CONTROL_DFA_MINIMIZE) {
dfa.minimize(opts); dfa.minimize(opts);
@ -263,22 +279,6 @@ CHFA *aare_rules::create_chfa(int *min_match_len,
dfa.dump_uniq_perms("minimized dfa"); dfa.dump_uniq_perms("minimized dfa");
} }
if (opts.control & CONTROL_DFA_FILTER_DENY &&
opts.control & CONTROL_DFA_MINIMIZE &&
dfa.apply_and_clear_deny()) {
/* Do a second minimization pass as removal of deny
* information has moved some states from accepting
* to none accepting partitions
*
* TODO: add this as a tail pass to minimization
* so we don't need to do a full second pass
*/
dfa.minimize(opts);
if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS)
dfa.dump_uniq_perms("minimized dfa");
}
if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE) if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE)
dfa.remove_unreachable(opts); dfa.remove_unreachable(opts);

View file

@ -35,6 +35,7 @@
class UniquePerm { class UniquePerm {
public: public:
int priority;
rule_mode_t mode; rule_mode_t mode;
bool exact_match; bool exact_match;
uint32_t perms; uint32_t perms;
@ -42,6 +43,8 @@ public:
bool operator<(UniquePerm const &rhs)const bool operator<(UniquePerm const &rhs)const
{ {
if (priority < rhs.priority)
return priority < rhs.priority;
if (mode >= rhs.mode) { if (mode >= rhs.mode) {
if (exact_match == rhs.exact_match) { if (exact_match == rhs.exact_match) {
if (perms == rhs.perms) if (perms == rhs.perms)
@ -71,21 +74,21 @@ public:
nodes.clear(); nodes.clear();
} }
Node *insert(rule_mode_t mode, uint32_t perms, uint32_t audit, Node *insert(int priority, rule_mode_t mode, uint32_t perms,
bool exact_match) uint32_t audit, bool exact_match)
{ {
UniquePerm tmp = { mode, exact_match, perms, audit }; UniquePerm tmp = { priority, mode, exact_match, perms, audit };
iterator res = nodes.find(tmp); iterator res = nodes.find(tmp);
if (res == nodes.end()) { if (res == nodes.end()) {
Node *node; Node *node;
if (mode == RULE_DENY) if (mode == RULE_DENY)
node = new DenyMatchFlag(perms, audit); node = new DenyMatchFlag(priority, perms, audit);
else if (mode == RULE_PROMPT) else if (mode == RULE_PROMPT)
node = new PromptMatchFlag(perms, audit); node = new PromptMatchFlag(priority, perms, audit);
else if (exact_match) else if (exact_match)
node = new ExactMatchFlag(perms, audit); node = new ExactMatchFlag(priority, perms, audit);
else else
node = new MatchFlag(perms, audit); node = new MatchFlag(priority, perms, audit);
pair<iterator, bool> val = nodes.insert(make_pair(tmp, node)); pair<iterator, bool> val = nodes.insert(make_pair(tmp, node));
if (val.second == false) if (val.second == false)
return val.first->second; return val.first->second;
@ -109,11 +112,11 @@ class aare_rules {
aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { }; aare_rules(int reverse): root(NULL), unique_perms(), expr_map(), reverse(reverse), rule_count(0) { };
~aare_rules(); ~aare_rules();
bool add_rule(const char *rule, rule_mode_t mode, perm32_t perms, bool add_rule(const char *rule, int priority, rule_mode_t mode,
perm32_t audit, optflags const &opts); perm32_t perms, perm32_t audit, optflags const &opts);
bool add_rule_vec(rule_mode_t mode, perm32_t perms, perm32_t audit, bool add_rule_vec(int priority, rule_mode_t mode, perm32_t perms,
int count, const char **rulev, optflags const &opts, perm32_t audit, int count, const char **rulev,
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, vector <aa_perms> &perms_table,

View file

@ -886,19 +886,20 @@ public:
class MatchFlag: public AcceptNode { class MatchFlag: public AcceptNode {
public: public:
MatchFlag(perm32_t perms, perm32_t audit): perms(perms), audit(audit) MatchFlag(int priority, perm32_t perms, perm32_t audit): priority(priority), perms(perms), audit(audit)
{ {
type_flags |= NODE_TYPE_MATCHFLAG; type_flags |= NODE_TYPE_MATCHFLAG;
} }
ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << '>'; } ostream &dump(ostream &os) { return os << "< 0x" << hex << perms << '>'; }
int priority;
perm32_t perms; perm32_t perms;
perm32_t audit; perm32_t audit;
}; };
class ExactMatchFlag: public MatchFlag { class ExactMatchFlag: public MatchFlag {
public: public:
ExactMatchFlag(perm32_t perms, perm32_t audit): MatchFlag(perms, audit) ExactMatchFlag(int priority, perm32_t perms, perm32_t audit): MatchFlag(priority, perms, audit)
{ {
type_flags |= NODE_TYPE_EXACTMATCHFLAG; type_flags |= NODE_TYPE_EXACTMATCHFLAG;
} }
@ -906,7 +907,7 @@ public:
class DenyMatchFlag: public MatchFlag { class DenyMatchFlag: public MatchFlag {
public: public:
DenyMatchFlag(perm32_t perms, perm32_t quiet): MatchFlag(perms, quiet) DenyMatchFlag(int priority, perm32_t perms, perm32_t quiet): MatchFlag(priority, perms, quiet)
{ {
type_flags |= NODE_TYPE_DENYMATCHFLAG; type_flags |= NODE_TYPE_DENYMATCHFLAG;
} }
@ -914,7 +915,7 @@ public:
class PromptMatchFlag: public MatchFlag { class PromptMatchFlag: public MatchFlag {
public: public:
PromptMatchFlag(perm32_t prompt, perm32_t audit): MatchFlag(prompt, audit) {} PromptMatchFlag(int priority, perm32_t prompt, perm32_t audit): MatchFlag(priority, prompt, audit) {}
}; };

View file

@ -493,6 +493,11 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed
*/ */
nnodes_cache.clear(); nnodes_cache.clear();
node_map.clear(); node_map.clear();
/* once created the priority information is no longer needed and
* can prevent sets with the same perms and different priorities
* from being merged during minimization
*/
clear_priorities();
} }
DFA::~DFA() DFA::~DFA()
@ -646,6 +651,12 @@ int DFA::apply_and_clear_deny(void)
return c; return c;
} }
void DFA::clear_priorities(void)
{
for (Partition::iterator i = states.begin(); i != states.end(); i++)
(*i)->perms.priority = 0;
}
/* minimize the number of dfa states */ /* minimize the number of dfa states */
@ -1379,9 +1390,7 @@ static inline int diff_qualifiers(perm32_t perm1, perm32_t perm2)
int accept_perms(NodeVec *state, perms_t &perms, bool filedfa) int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
{ {
int error = 0; int error = 0;
perm32_t exact_match_allow = 0; perms_t exact;
perm32_t exact_match_prompt = 0;
perm32_t exact_audit = 0;
perms.clear(); perms.clear();
@ -1393,13 +1402,20 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
continue; continue;
MatchFlag *match = static_cast<MatchFlag *>(*i); MatchFlag *match = static_cast<MatchFlag *>(*i);
if (perms.priority > match->priority)
continue;
if (perms.priority < match->priority) {
perms.clear(match->priority);
exact.clear(match->priority);
}
if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) { if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) {
/* exact match only ever happens with x */ /* exact match only ever happens with x */
if (filedfa && !is_merged_x_consistent(exact_match_allow, if (filedfa &&
match->perms)) !is_merged_x_consistent(exact.allow, match->perms))
error = 1;; error = 1;
exact_match_allow |= match->perms; exact.allow |= match->perms;
exact_audit |= match->audit; exact.audit |= match->audit;
} else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { } else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) {
perms.deny |= match->perms; perms.deny |= match->perms;
perms.quiet |= match->audit; perms.quiet |= match->audit;
@ -1407,7 +1423,8 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
perms.prompt |= match->perms; perms.prompt |= match->perms;
perms.audit |= match->audit; perms.audit |= match->audit;
} else { } else {
if (filedfa && !is_merged_x_consistent(perms.allow, match->perms)) if (filedfa &&
!is_merged_x_consistent(perms.allow, match->perms))
error = 1; error = 1;
perms.allow |= match->perms; perms.allow |= match->perms;
perms.audit |= match->audit; perms.audit |= match->audit;
@ -1415,21 +1432,21 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
} }
if (filedfa) { if (filedfa) {
perms.allow |= exact_match_allow & ~(ALL_AA_EXEC_TYPE); perms.allow |= exact.allow & ~(ALL_AA_EXEC_TYPE);
perms.prompt |= exact_match_prompt & ~(ALL_AA_EXEC_TYPE); perms.prompt |= exact.prompt & ~(ALL_AA_EXEC_TYPE);
perms.audit |= exact_audit & ~(ALL_AA_EXEC_TYPE); perms.audit |= exact.audit & ~(ALL_AA_EXEC_TYPE);
} else { } else {
perms.allow |= exact_match_allow; perms.allow |= exact.allow;
perms.prompt |= exact_match_prompt; perms.prompt |= exact.prompt;
perms.audit |= exact_audit; perms.audit |= exact.audit;
} }
if (exact_match_allow & AA_USER_EXEC) { if (exact.allow & AA_USER_EXEC) {
perms.allow = (exact_match_allow & AA_USER_EXEC_TYPE) | perms.allow = (exact.allow & AA_USER_EXEC_TYPE) |
(perms.allow & ~AA_USER_EXEC_TYPE); (perms.allow & ~AA_USER_EXEC_TYPE);
perms.exact = AA_USER_EXEC_TYPE; perms.exact = AA_USER_EXEC_TYPE;
} }
if (exact_match_allow & AA_OTHER_EXEC) { if (exact.allow & AA_OTHER_EXEC) {
perms.allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) | perms.allow = (exact.allow & AA_OTHER_EXEC_TYPE) |
(perms.allow & ~AA_OTHER_EXEC_TYPE); (perms.allow & ~AA_OTHER_EXEC_TYPE);
perms.exact |= AA_OTHER_EXEC_TYPE; perms.exact |= AA_OTHER_EXEC_TYPE;
} }
@ -1443,7 +1460,6 @@ int accept_perms(NodeVec *state, perms_t &perms, bool filedfa)
perms.quiet &= perms.deny; perms.quiet &= perms.deny;
perms.prompt &= ~perms.deny; perms.prompt &= ~perms.deny;
perms.prompt &= ~perms.allow; perms.prompt &= ~perms.allow;
if (error) if (error)
fprintf(stderr, "profile has merged rule with conflicting x modifiers\n"); fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");

View file

@ -30,6 +30,7 @@
#include <iostream> #include <iostream>
#include <assert.h> #include <assert.h>
#include <limits.h>
#include <stdint.h> #include <stdint.h>
#include "expr-tree.h" #include "expr-tree.h"
@ -51,24 +52,37 @@ ostream &operator<<(ostream &os, State &state);
class perms_t { class perms_t {
public: public:
perms_t(void): allow(0), deny(0), audit(0), quiet(0), exact(0) { }; perms_t(void): priority(INT_MIN), allow(0), deny(0), prompt(0), audit(0), quiet(0), exact(0) { };
bool is_accept(void) { return (allow | deny | prompt | audit | quiet); } bool is_accept(void) { return (allow | deny | prompt | audit | quiet); }
void dump_header(ostream &os) void dump_header(ostream &os)
{ {
os << "(allow/deny/prompt/audit/quiet)"; os << "priority (allow/deny/prompt/audit/quiet)";
} }
void dump(ostream &os) void dump(ostream &os)
{ {
os << " (0x " << hex os << " " << priority << " (0x " << hex
<< allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet << allow << "/" << deny << "/" << "/" << prompt << "/" << audit << "/" << quiet
<< ')' << dec; << ')' << dec;
} }
void clear(void) { allow = deny = prompt = audit = quiet = 0; } void clear(void) {
priority = INT_MIN;
allow = deny = prompt = audit = quiet = exact = 0;
}
void clear(int p) {
priority = p;
allow = deny = prompt = audit = quiet = exact = 0;
}
void add(perms_t &rhs, bool filedfa) void add(perms_t &rhs, bool filedfa)
{ {
if (priority > rhs.priority)
return;
if (priority < rhs.priority) {
*this = rhs;
return;
} //else if (rhs.priority == priority) {
deny |= rhs.deny; deny |= rhs.deny;
if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC, if (filedfa && !is_merged_x_consistent(allow & ALL_USER_EXEC,
@ -131,6 +145,8 @@ public:
bool operator<(perms_t const &rhs)const bool operator<(perms_t const &rhs)const
{ {
if (priority < rhs.priority)
return priority < rhs.priority;
if (allow < rhs.allow) if (allow < rhs.allow)
return allow < rhs.allow; return allow < rhs.allow;
if (deny < rhs.deny) if (deny < rhs.deny)
@ -142,6 +158,7 @@ public:
return quiet < rhs.quiet; return quiet < rhs.quiet;
} }
int priority;
perm32_t allow, deny, prompt, audit, quiet, exact; perm32_t allow, deny, prompt, audit, quiet, exact;
}; };
@ -351,6 +368,7 @@ public:
bool same_mappings(State *s1, State *s2); bool same_mappings(State *s1, State *s2);
void minimize(optflags const &flags); void minimize(optflags const &flags);
int apply_and_clear_deny(void); int apply_and_clear_deny(void);
void clear_priorities(void);
void diff_encode(optflags const &flags); void diff_encode(optflags const &flags);
void undiff_encode(void); void undiff_encode(void);

View file

@ -797,8 +797,9 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
* if a data match is required this only has AA_MATCH_CONT perms * if a data match is required this only has AA_MATCH_CONT perms
* else it has full perms * else it has full perms
*/ */
if (!prof.policy.rules->add_rule_vec(rule_mode, tmpperms, tmpaudit, 4, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, tmpperms,
vec, parseopts, false)) tmpaudit, 4, vec, parseopts,
false))
goto fail; goto fail;
count++; count++;
@ -808,7 +809,7 @@ int mnt_rule::gen_policy_remount(Profile &prof, int &count,
if (!build_mnt_opts(optsbuf, opts)) if (!build_mnt_opts(optsbuf, opts))
goto fail; goto fail;
vec[4] = optsbuf.c_str(); vec[4] = optsbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
(audit == AUDIT_FORCE ? perms : 0), (audit == AUDIT_FORCE ? perms : 0),
5, vec, parseopts, false)) 5, vec, parseopts, false))
goto fail; goto fail;
@ -850,7 +851,8 @@ int mnt_rule::gen_policy_bind_mount(Profile &prof, int &count,
opt_flags & MS_BIND_FLAGS)) opt_flags & MS_BIND_FLAGS))
goto fail; goto fail;
vec[3] = flagsbuf; vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
audit == AUDIT_FORCE ? perms : 0,
4, vec, 4, vec,
parseopts, false)) parseopts, false))
goto fail; goto fail;
@ -907,7 +909,8 @@ int mnt_rule::gen_policy_change_mount_type(Profile &prof, int &count,
opt_flags & MS_MAKE_FLAGS)) opt_flags & MS_MAKE_FLAGS))
goto fail; goto fail;
vec[3] = flagsbuf; vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
audit == AUDIT_FORCE ? perms : 0,
4, vec, 4, vec,
parseopts, false)) parseopts, false))
goto fail; goto fail;
@ -950,7 +953,8 @@ int mnt_rule::gen_policy_move_mount(Profile &prof, int &count,
opt_flags & MS_MOVE_FLAGS)) opt_flags & MS_MOVE_FLAGS))
goto fail; goto fail;
vec[3] = flagsbuf; vec[3] = flagsbuf;
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, audit == AUDIT_FORCE ? perms : 0, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
audit == AUDIT_FORCE ? perms : 0,
4, vec, 4, vec,
parseopts, false)) parseopts, false))
goto fail; goto fail;
@ -1002,8 +1006,9 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
tmpaudit = audit == AUDIT_FORCE ? perms : 0; tmpaudit = audit == AUDIT_FORCE ? perms : 0;
} }
/* rule for match without required data || data MATCH_CONT */ /* rule for match without required data || data MATCH_CONT */
if (!prof.policy.rules->add_rule_vec(rule_mode, tmpperms, tmpaudit, 4, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, tmpperms,
vec, parseopts, false)) tmpaudit, 4, vec, parseopts,
false))
goto fail; goto fail;
count++; count++;
@ -1013,7 +1018,7 @@ int mnt_rule::gen_policy_new_mount(Profile &prof, int &count,
if (!build_mnt_opts(optsbuf, opts)) if (!build_mnt_opts(optsbuf, opts))
goto fail; goto fail;
vec[4] = optsbuf.c_str(); vec[4] = optsbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
audit == AUDIT_FORCE ? perms : 0, audit == AUDIT_FORCE ? perms : 0,
5, vec, parseopts, false)) 5, vec, parseopts, false))
goto fail; goto fail;
@ -1105,7 +1110,7 @@ int mnt_rule::gen_policy_re(Profile &prof)
if (!convert_entry(mntbuf, mnt_point)) if (!convert_entry(mntbuf, mnt_point))
goto fail; goto fail;
vec[0] = mntbuf.c_str(); vec[0] = mntbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
(audit == AUDIT_FORCE ? perms : 0), 1, vec, (audit == AUDIT_FORCE ? perms : 0), 1, vec,
parseopts, false)) parseopts, false))
goto fail; goto fail;
@ -1120,7 +1125,7 @@ int mnt_rule::gen_policy_re(Profile &prof)
if (!clear_and_convert_entry(devbuf, device)) if (!clear_and_convert_entry(devbuf, device))
goto fail; goto fail;
vec[1] = devbuf.c_str(); vec[1] = devbuf.c_str();
if (!prof.policy.rules->add_rule_vec(rule_mode, perms, if (!prof.policy.rules->add_rule_vec(priority, rule_mode, perms,
(audit == AUDIT_FORCE ? perms : 0), 2, vec, (audit == AUDIT_FORCE ? perms : 0), 2, vec,
parseopts, false)) parseopts, false))
goto fail; goto fail;

View file

@ -231,10 +231,19 @@ int mqueue_rule::gen_policy_re(Profile &prof)
/* store perms at name match so label doesn't need /* store perms at name match so label doesn't need
* to be checked * to be checked
*/ */
if (!label && !prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) if (!label && !prof.policy.rules->add_rule_vec(
priority,
rule_mode,
map_mqueue_perms(perms),
audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1,
vec, parseopts, false))
goto fail; goto fail;
/* also provide label match with perm */ /* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) if (!prof.policy.rules->add_rule_vec(priority,
rule_mode,
map_mqueue_perms(perms),
audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0,
size, vec, parseopts, false))
goto fail; goto fail;
} }
} }
@ -266,10 +275,19 @@ int mqueue_rule::gen_policy_re(Profile &prof)
} }
if (perms & AA_VALID_SYSV_MQ_PERMS) { if (perms & AA_VALID_SYSV_MQ_PERMS) {
if (!label && !prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1, vec, parseopts, false)) if (!label &&
!prof.policy.rules->add_rule_vec(priority,
rule_mode,
map_mqueue_perms(perms),
audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, 1,
vec, parseopts, false))
goto fail; goto fail;
/* also provide label match with perm */ /* also provide label match with perm */
if (!prof.policy.rules->add_rule_vec(rule_mode, map_mqueue_perms(perms), audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0, size, vec, parseopts, false)) if (!prof.policy.rules->add_rule_vec(priority,
rule_mode,
map_mqueue_perms(perms),
audit == AUDIT_FORCE ? map_mqueue_perms(perms) : 0,
size, vec, parseopts, false))
goto fail; goto fail;
} }
} }

View file

@ -697,7 +697,8 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &st
buf = oss.str(); buf = oss.str();
/* AA_CONT_MATCH mapping (cond_perms) only applies to perms, not audit */ /* AA_CONT_MATCH mapping (cond_perms) only applies to perms, not audit */
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, cond_perms, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
@ -710,7 +711,8 @@ bool network_rule::gen_ip_conds(Profile &prof, std::list<std::ostringstream> &st
oss << "\\x00"; /* null transition */ oss << "\\x00"; /* null transition */
buf = oss.str(); buf = oss.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, cond_perms, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode, cond_perms,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts)) parseopts))
return false; return false;
@ -735,9 +737,10 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
if (!features_supports_inet || (family != AF_INET && family != AF_INET6)) { if (!features_supports_inet || (family != AF_INET && family != AF_INET6)) {
buf = buffer.str(); buf = buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), priority,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, rule_mode, map_perms(perms),
parseopts)) dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false; return false;
return true; return true;
} }
@ -745,7 +748,8 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
buf = buffer.str(); buf = buffer.str();
/* create perms need to be generated excluding the rest of the perms */ /* create perms need to be generated excluding the rest of the perms */
if (perms & AA_NET_CREATE) { if (perms & AA_NET_CREATE) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1), if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode, map_perms(perms & AA_NET_CREATE) | (AA_CONT_MATCH << 1),
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms & AA_NET_CREATE) : 0, dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms & AA_NET_CREATE) : 0,
parseopts)) parseopts))
return false; return false;
@ -797,9 +801,10 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
/* length of queue allowed - not used for now */ /* length of queue allowed - not used for now */
listen_buffer << ".."; listen_buffer << "..";
buf = listen_buffer.str(); buf = listen_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), priority,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, rule_mode, map_perms(perms),
parseopts)) dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false; return false;
} }
} }
@ -816,9 +821,10 @@ bool network_rule::gen_net_rule(Profile &prof, u16 family, unsigned int type_mas
/* socket mapping - not used for now */ /* socket mapping - not used for now */
opt_buffer << ".."; opt_buffer << "..";
buf = opt_buffer.str(); buf = opt_buffer.str();
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, map_perms(perms), if (!prof.policy.rules->add_rule(buf.c_str(), priority,
dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0, rule_mode, map_perms(perms),
parseopts)) dedup_perms_rule_t::audit == AUDIT_FORCE ? map_perms(perms) : 0,
parseopts))
return false; return false;
} }
} }

View file

@ -114,6 +114,7 @@ struct cond_entry_list {
}; };
struct cod_entry { struct cod_entry {
int priority;
char *name; char *name;
union { union {
char *link_name; char *link_name;

View file

@ -984,6 +984,7 @@ struct cod_entry *new_entry(char *id, perm32_t perms, char *link_id)
if (!entry) if (!entry)
return NULL; return NULL;
entry->priority = 0;
entry->name = id; entry->name = id;
entry->link_name = link_id; entry->link_name = link_id;
entry->perms = perms; entry->perms = perms;
@ -1010,6 +1011,7 @@ struct cod_entry *copy_cod_entry(struct cod_entry *orig)
DUP_STRING(orig, entry, name, err); DUP_STRING(orig, entry, name, err);
DUP_STRING(orig, entry, link_name, err); DUP_STRING(orig, entry, link_name, err);
DUP_STRING(orig, entry, nt_name, err); DUP_STRING(orig, entry, nt_name, err);
entry->priority = orig->priority;
entry->perms = orig->perms; entry->perms = orig->perms;
entry->audit = orig->audit; entry->audit = orig->audit;
entry->rule_mode = orig->rule_mode; entry->rule_mode = orig->rule_mode;

View file

@ -507,7 +507,7 @@ static int process_profile_name_xmatch(Profile *prof)
aare_rules *rules = new aare_rules(); aare_rules *rules = new aare_rules();
if (!rules) if (!rules)
return FALSE; return FALSE;
if (!rules->add_rule(tbuf.c_str(), RULE_ALLOW, if (!rules->add_rule(tbuf.c_str(), 0, RULE_ALLOW,
AA_MAY_EXEC, 0, parseopts)) { AA_MAY_EXEC, 0, parseopts)) {
delete rules; delete rules;
return FALSE; return FALSE;
@ -521,7 +521,7 @@ static int process_profile_name_xmatch(Profile *prof)
ptype = convert_aaregex_to_pcre(alt->name, 0, ptype = convert_aaregex_to_pcre(alt->name, 0,
glob_default, glob_default,
tbuf, &len); tbuf, &len);
if (!rules->add_rule(tbuf.c_str(), if (!rules->add_rule(tbuf.c_str(), 0,
RULE_ALLOW, AA_MAY_EXEC, RULE_ALLOW, AA_MAY_EXEC,
0, parseopts)) { 0, parseopts)) {
delete rules; delete rules;
@ -644,13 +644,14 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
if (entry->rule_mode == RULE_DENY) { if (entry->rule_mode == RULE_DENY) {
if ((entry->perms & ~AA_LINK_BITS) && if ((entry->perms & ~AA_LINK_BITS) &&
!is_change_profile_perms(entry->perms) && !is_change_profile_perms(entry->perms) &&
!dfarules->add_rule(tbuf.c_str(), entry->rule_mode, !dfarules->add_rule(tbuf.c_str(), entry->priority,
entry->rule_mode,
entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE), entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE),
entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0, entry->audit == AUDIT_FORCE ? entry->perms & ~(AA_LINK_BITS | AA_CHANGE_PROFILE) : 0,
parseopts)) parseopts))
return FALSE; return FALSE;
} else if (!is_change_profile_perms(entry->perms)) { } else if (!is_change_profile_perms(entry->perms)) {
if (!dfarules->add_rule(tbuf.c_str(), if (!dfarules->add_rule(tbuf.c_str(), entry->priority,
entry->rule_mode, entry->perms, entry->rule_mode, entry->perms,
entry->audit == AUDIT_FORCE ? entry->perms : 0, entry->audit == AUDIT_FORCE ? entry->perms : 0,
parseopts)) parseopts))
@ -676,7 +677,10 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
perms |= LINK_TO_LINK_SUBSET(perms); perms |= LINK_TO_LINK_SUBSET(perms);
vec[1] = "/[^/].*"; vec[1] = "/[^/].*";
} }
if (!dfarules->add_rule_vec(entry->rule_mode, perms, entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0, 2, vec, parseopts, false)) if (!dfarules->add_rule_vec(entry->priority,
entry->rule_mode, perms,
entry->audit == AUDIT_FORCE ? perms & AA_LINK_BITS : 0,
2, vec, parseopts, false))
return FALSE; return FALSE;
} }
if (is_change_profile_perms(entry->perms)) { if (is_change_profile_perms(entry->perms)) {
@ -727,13 +731,14 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
} }
/* regular change_profile rule */ /* regular change_profile rule */
if (!dfarules->add_rule_vec(entry->rule_mode, if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
AA_CHANGE_PROFILE | onexec_perms, AA_CHANGE_PROFILE | onexec_perms,
0, index - 1, &vec[1], parseopts, false)) 0, index - 1, &vec[1], parseopts, false))
return FALSE; return FALSE;
/* onexec rules - both rules are needed for onexec */ /* onexec rules - both rules are needed for onexec */
if (!dfarules->add_rule_vec(entry->rule_mode, onexec_perms, if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
onexec_perms,
0, 1, vec, parseopts, false)) 0, 1, vec, parseopts, false))
return FALSE; return FALSE;
@ -742,8 +747,9 @@ static int process_dfa_entry(aare_rules *dfarules, struct cod_entry *entry)
* unsafe exec transitions * unsafe exec transitions
*/ */
onexec_perms |= (entry->perms & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE)); onexec_perms |= (entry->perms & (AA_EXEC_BITS | ALL_AA_EXEC_UNSAFE));
if (!dfarules->add_rule_vec(entry->rule_mode, onexec_perms, if (!dfarules->add_rule_vec(entry->priority, entry->rule_mode,
0, index, vec, parseopts, false)) onexec_perms, 0, index, vec,
parseopts, false))
return FALSE; return FALSE;
} }
return TRUE; return TRUE;
@ -999,7 +1005,8 @@ static bool gen_net_rule(Profile *prof, u16 family, unsigned int type_mask,
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff); buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << (type_mask & 0xff);
} }
buf = buffer.str(); buf = buffer.str();
if (!prof->policy.rules->add_rule(buf.c_str(), rmode, map_perms(AA_VALID_NET_PERMS), if (!prof->policy.rules->add_rule(buf.c_str(), 0, rmode,
map_perms(AA_VALID_NET_PERMS),
audit ? map_perms(AA_VALID_NET_PERMS) : 0, audit ? map_perms(AA_VALID_NET_PERMS) : 0,
parseopts)) parseopts))
return false; return false;
@ -1091,7 +1098,7 @@ int process_profile_policydb(Profile *prof)
* to be supported * to be supported
*/ */
if (features_supports_userns && if (features_supports_userns &&
!prof->policy.rules->add_rule(mediates_ns, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_ns, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
/* don't add mediated classes to unconfined profiles */ /* don't add mediated classes to unconfined profiles */
@ -1099,35 +1106,35 @@ int process_profile_policydb(Profile *prof)
prof->flags.mode != MODE_DEFAULT_ALLOW) { prof->flags.mode != MODE_DEFAULT_ALLOW) {
/* note: this activates fs based unix domain sockets mediation on connect */ /* note: this activates fs based unix domain sockets mediation on connect */
if (kernel_abi_version > 5 && if (kernel_abi_version > 5 &&
!prof->policy.rules->add_rule(mediates_file, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_file, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_mount && if (features_supports_mount &&
!prof->policy.rules->add_rule(mediates_mount, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_mount, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_dbus && if (features_supports_dbus &&
!prof->policy.rules->add_rule(mediates_dbus, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_dbus, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_signal && if (features_supports_signal &&
!prof->policy.rules->add_rule(mediates_signal, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_signal, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_ptrace && if (features_supports_ptrace &&
!prof->policy.rules->add_rule(mediates_ptrace, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_ptrace, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_networkv8 && if (features_supports_networkv8 &&
!prof->policy.rules->add_rule(mediates_netv8, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_netv8, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_unix && if (features_supports_unix &&
(!prof->policy.rules->add_rule(mediates_extended_net, RULE_ALLOW, AA_MAY_READ, 0, parseopts) || (!prof->policy.rules->add_rule(mediates_extended_net, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts) ||
!prof->policy.rules->add_rule(mediates_net_unix, RULE_ALLOW, AA_MAY_READ, 0, parseopts))) !prof->policy.rules->add_rule(mediates_net_unix, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts)))
goto out; goto out;
if (features_supports_posix_mqueue && if (features_supports_posix_mqueue &&
!prof->policy.rules->add_rule(mediates_posix_mqueue, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_posix_mqueue, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_sysv_mqueue && if (features_supports_sysv_mqueue &&
!prof->policy.rules->add_rule(mediates_sysv_mqueue, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_sysv_mqueue, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
if (features_supports_io_uring && if (features_supports_io_uring &&
!prof->policy.rules->add_rule(mediates_io_uring, RULE_ALLOW, AA_MAY_READ, 0, parseopts)) !prof->policy.rules->add_rule(mediates_io_uring, 0, RULE_ALLOW, AA_MAY_READ, 0, parseopts))
goto out; goto out;
} }
@ -1136,11 +1143,11 @@ int process_profile_policydb(Profile *prof)
// This requires file rule processing happen first // This requires file rule processing happen first
if (!prof->dfa.rules->rule_count) { if (!prof->dfa.rules->rule_count) {
// add null dfa // add null dfa
if (!prof->dfa.rules->add_rule(deny_file, RULE_DENY, AA_MAY_READ, 0, parseopts)) if (!prof->dfa.rules->add_rule(deny_file, 0, RULE_DENY, AA_MAY_READ, 0, parseopts))
goto out; goto out;
} }
if (!prof->policy.rules->rule_count) { if (!prof->policy.rules->rule_count) {
if (!prof->policy.rules->add_rule(mediates_file, RULE_DENY, AA_MAY_READ, 0, parseopts)) if (!prof->policy.rules->add_rule(mediates_file, 0, RULE_DENY, AA_MAY_READ, 0, parseopts))
goto out; goto out;
} }
int xmatch_len = 0; int xmatch_len = 0;

View file

@ -133,9 +133,10 @@ int ptrace_rule::gen_policy_re(Profile &prof)
buf = buffer.str(); buf = buffer.str();
if (perms & AA_VALID_PTRACE_PERMS) { if (perms & AA_VALID_PTRACE_PERMS) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
audit == AUDIT_FORCE ? perms : 0, rule_mode, perms,
parseopts)) audit == AUDIT_FORCE ? perms : 0,
parseopts))
goto fail; goto fail;
} }

View file

@ -82,10 +82,11 @@ class rule_t {
public: public:
int rule_type; int rule_type;
rule_flags_t flags; rule_flags_t flags;
int priority;
rule_t *removed_by; rule_t *removed_by;
rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE), removed_by(NULL) { } rule_t(int t): rule_type(t), flags(RULE_FLAG_NONE), priority(0), removed_by(NULL) { }
virtual ~rule_t() { }; virtual ~rule_t() { };
bool is_type(int type) { return rule_type == type; } bool is_type(int type) { return rule_type == type; }
@ -113,6 +114,9 @@ public:
virtual int expand_variables(void) = 0; virtual int expand_variables(void) = 0;
virtual int cmp(rule_t const &rhs) const { virtual int cmp(rule_t const &rhs) const {
int tmp = priority - rhs.priority;
if (tmp != 0)
return tmp;
return rule_type - rhs.rule_type; return rule_type - rhs.rule_type;
} }
virtual bool operator<(rule_t const &rhs) const { virtual bool operator<(rule_t const &rhs) const {

View file

@ -316,7 +316,8 @@ int signal_rule::gen_policy_re(Profile &prof)
buf = buffer.str(); buf = buffer.str();
if (perms & (AA_MAY_SEND | AA_MAY_RECEIVE)) { if (perms & (AA_MAY_SEND | AA_MAY_RECEIVE)) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode,
perms, audit == AUDIT_FORCE ? perms : 0, perms, audit == AUDIT_FORCE ? perms : 0,
parseopts)) parseopts))
goto fail; goto fail;

View file

@ -0,0 +1,68 @@
capability {0xffffff
}
caps {extended {yes
}
mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend audit_read perfmon bpf checkpoint_restore
}
}
dbus {mask {acquire send receive
}
}
domain {attach_conditions {xattr {yes
}
}
change_hat {yes
}
change_hatv {yes
}
change_onexec {yes
}
change_profile {yes
}
computed_longest_left {yes
}
disconnected.path {yes
}
fix_binfmt_elf_mmap {yes
}
interruptible {yes
}
kill.signal {yes
}
post_nnp_subset {yes
}
stack {yes
}
unconfined_allowed_children {yes
}
version {1.2
}
}
policy {outofband {0x000001
}
permstable32 {allow deny subtree cond kill complain prompt audit quiet hide xindex tag label
}
permstable32_version {0x000003
}
set_load {yes
}
versions {v5 {yes
}
v6 {yes
}
v7 {yes
}
v8 {yes
}
v9 {yes
}
}
}
query {label {data {yes
}
multi_transaction {yes
}
perms {allow deny audit quiet
}
}
}

View file

@ -0,0 +1,117 @@
capability {0xffffff
}
caps {extended {yes
}
mask {chown dac_override dac_read_search fowner fsetid kill setgid setuid setpcap linux_immutable net_bind_service net_broadcast net_admin net_raw ipc_lock ipc_owner sys_module sys_rawio sys_chroot sys_ptrace sys_pacct sys_admin sys_boot sys_nice sys_resource sys_time sys_tty_config mknod lease audit_write audit_control setfcap mac_override mac_admin syslog wake_alarm block_suspend audit_read perfmon bpf checkpoint_restore
}
}
dbus {mask {acquire send receive
}
}
domain {attach_conditions {xattr {yes
}
}
change_hat {yes
}
change_hatv {yes
}
change_onexec {yes
}
change_profile {yes
}
computed_longest_left {yes
}
disconnected.path {yes
}
fix_binfmt_elf_mmap {yes
}
interruptible {yes
}
kill.signal {yes
}
post_nnp_subset {yes
}
stack {yes
}
unconfined_allowed_children {yes
}
version {1.2
}
}
file {mask {create read write exec append mmap_exec link lock
}
}
io_uring {mask {sqpoll override_creds
}
}
ipc {posix_mqueue {create read write open delete setattr getattr
}
}
mount {mask {mount umount pivot_root
}
move_mount {detached
}
}
namespaces {mask {userns_create
}
pivot_root {no
}
profile {yes
}
userns_create {pciu&
}
}
network {af_mask {unspec unix inet ax25 ipx appletalk netrom bridge atmpvc x25 inet6 rose netbeui security key netlink packet ash econet atmsvc rds sna irda pppox wanpipe llc ib mpls can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock kcm qipcrtr smc xdp mctp
}
af_unix {yes
}
}
network_v8 {af_inet {yes
}
af_mask {unspec unix inet ax25 ipx appletalk netrom bridge atmpvc x25 inet6 rose netbeui security key netlink packet ash econet atmsvc rds sna irda pppox wanpipe llc ib mpls can tipc bluetooth iucv rxrpc isdn phonet ieee802154 caif alg nfc vsock kcm qipcrtr smc xdp mctp
}
}
policy {outofband {0x000001
}
permstable32 {allow deny subtree cond kill complain prompt audit quiet hide xindex tag label
}
permstable32_version {0x000003
}
set_load {yes
}
unconfined_restrictions {change_profile {yes
}
io_uring {0
}
userns {0
}
}
versions {v5 {yes
}
v6 {yes
}
v7 {yes
}
v8 {yes
}
v9 {yes
}
}
}
ptrace {mask {read trace
}
}
query {label {data {yes
}
multi_transaction {yes
}
perms {allow deny audit quiet
}
}
}
rlimit {mask {cpu fsize data stack core rss nproc nofile memlock as locks sigpending msgqueue nice rtprio rttime
}
}
signal {mask {hup int quit ill trap abrt bus fpe kill usr1 segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg xcpu xfsz vtalrm prof winch io pwr sys emt lost
}
}

View file

@ -78,7 +78,7 @@ APPARMOR_PARSER="${APPARMOR_PARSER:-../apparmor_parser}"
# {a} (0x 40030/0/0/0) # {a} (0x 40030/0/0/0)
echo -n "Minimize profiles basic perms " echo -n "Minimize profiles basic perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 6 ] ; then if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -93,7 +93,7 @@ echo "ok"
# {9} (0x 12804a/0/2800a/0) # {9} (0x 12804a/0/2800a/0)
# {c} (0x 40030/0/0/0) # {c} (0x 40030/0/0/0)
echo -n "Minimize profiles audit perms " echo -n "Minimize profiles audit perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 6 ] ; then if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -112,7 +112,7 @@ echo "ok"
# {c} (0x 40030/0/0/0) # {c} (0x 40030/0/0/0)
echo -n "Minimize profiles deny perms " echo -n "Minimize profiles deny perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 6 ] ; then if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -130,13 +130,59 @@ echo "ok"
# {c} (0x 40030/0/0/0) # {c} (0x 40030/0/0/0)
echo -n "Minimize profiles audit deny perms " echo -n "Minimize profiles audit deny perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 5 ] ; then if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 5 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
echo "ok" echo "ok"
# ---------------------- extended perms ------------------------------
# Test that not filtering deny results in more states. This test is testing
# without filtering. The following test does the filtering
#
# {1} <== (allow/deny/prompt/audit/quiet)
# {3} (0x 0/2800a///0/0/0)
# {4} (0x 10004/2800a///0/0/0)
# {7} (0x 40010/2800a///0/0/0)
# {8} (0x 80020/2800a///0/0/0)
# {9} (0x 100040/2800a///0/0/0)
# {12} (0x 40030/0///0/0/0)
# {2} (0x 4/0//0/0/0) <- from policydb still showing up bug
## NOTE: change count from 6 to 7 when extend perms is not dependent on
## prompt rules being present
echo -n "Minimize profiles extended no-filter audit deny perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
echo "failed"
exit 1;
fi
echo "ok"
# same test as above except with filter-deny which should result in one less
# accept state
#
# {1} <== (allow/deny/prompt/audit/quiet)
# {4} (0x 10004/0///0/0/0)
# {7} (0x 40010/0///0/0/0)
# {8} (0x 80020/0///0/0/0)
# {9} (0x 100040/0///0/0/0)
# {12} (0x 40030/0///0/0/0)
# {2} (0x 4/0//0/0/0) <- from policydb still showing up bug
echo -n "Minimize profiles extended filter audit deny perms "
if [ "$(echo "/t { /a r, /b w, /c a, /d l, /e k, /f m, audit deny /** w, }" | ${APPARMOR_PARSER} -M features_files/features.extended-perms-no-policydb -QT -O minimize -O filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 6 ] ; then
echo "failed"
exit 1;
fi
echo "ok"
# ======================= x transition ===============================
# The x transition test profile is setup so that there are 3 conflicting x # The x transition test profile is setup so that there are 3 conflicting x
# permissions, two are on paths that won't collide during dfa creation. The # permissions, two are on paths that won't collide during dfa creation. The
# 3rd is a generic permission that should be overridden during dfa creation. # 3rd is a generic permission that should be overridden during dfa creation.
@ -162,7 +208,7 @@ echo "ok"
# #
echo -n "Minimize profiles xtrans " echo -n "Minimize profiles xtrans "
if [ "$(echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 3 ] ; then if [ "$(echo "/t { /b px, /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 3 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -170,7 +216,7 @@ echo "ok"
# same test as above + audit # same test as above + audit
echo -n "Minimize profiles audit xtrans " echo -n "Minimize profiles audit xtrans "
if [ "$(echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 3 ] ; then if [ "$(echo "/t { /b px, audit /* Pixr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 3 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -183,7 +229,7 @@ echo "ok"
# {3} (0x 0/fe17f85/0/14005) # {3} (0x 0/fe17f85/0/14005)
echo -n "Minimize profiles deny xtrans " echo -n "Minimize profiles deny xtrans "
if [ "$(echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 1 ] ; then if [ "$(echo "/t { /b px, deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 1 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi
@ -195,7 +241,7 @@ echo "ok"
# {3} (0x 0/fe17f85/0/0) # {3} (0x 0/fe17f85/0/0)
echo -n "Minimize profiles audit deny xtrans " echo -n "Minimize profiles audit deny xtrans "
if [ "$(echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} (.*)$')" -ne 0 ] ; then if [ "$(echo "/t { /b px, audit deny /* xr, /a Cx -> foo, }" | ${APPARMOR_PARSER} -M features_files/features.nopolicydb -QT -O minimize -O no-filter-deny -D dfa-states 2>&1 | grep -v '<==' | grep -c '^{.*} 0 (.*)$')" -ne 0 ] ; then
echo "failed" echo "failed"
exit 1; exit 1;
fi fi

View file

@ -95,7 +95,8 @@ int userns_rule::gen_policy_re(Profile &prof)
buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NS; buffer << "\\x" << std::setfill('0') << std::setw(2) << std::hex << AA_CLASS_NS;
buf = buffer.str(); buf = buffer.str();
if (perms & AA_VALID_USERNS_PERMS) { if (perms & AA_VALID_USERNS_PERMS) {
if (!prof.policy.rules->add_rule(buf.c_str(), rule_mode, perms, if (!prof.policy.rules->add_rule(buf.c_str(), priority,
rule_mode, perms,
audit == AUDIT_FORCE ? perms : 0, audit == AUDIT_FORCE ? perms : 0,
parseopts)) parseopts))
goto fail; goto fail;