mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-22 10:07:12 +00:00
Track deny and quiet perms during DFA construction
Delay the packing of audit and quiet permissions until chfa construction, and track deny and quiet perms during DFA construction, so that we will be able to do full minimization. Also delay the packing of audit and Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
parent
fb55e9cddc
commit
82a20d9bb8
@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
#include "hfa.h"
|
#include "hfa.h"
|
||||||
#include "chfa.h"
|
#include "chfa.h"
|
||||||
|
#include "../immunix.h"
|
||||||
|
|
||||||
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)
|
||||||
@ -112,8 +113,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
|||||||
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
|
||||||
if (*i != dfa.nonmatching && *i != dfa.start) {
|
if (*i != dfa.nonmatching && *i != dfa.start) {
|
||||||
insert_state(free_list, *i, dfa);
|
insert_state(free_list, *i, dfa);
|
||||||
accept[num.size()] = (*i)->accept;
|
accept[num.size()] = (*i)->perms.allow;
|
||||||
accept2[num.size()] = (*i)->audit;
|
accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
|
||||||
num.insert(make_pair(*i, num.size()));
|
num.insert(make_pair(*i, num.size()));
|
||||||
}
|
}
|
||||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||||
@ -129,8 +130,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
|
|||||||
if (i->second != dfa.nonmatching &&
|
if (i->second != dfa.nonmatching &&
|
||||||
i->second != dfa.start) {
|
i->second != dfa.start) {
|
||||||
insert_state(free_list, i->second, dfa);
|
insert_state(free_list, i->second, dfa);
|
||||||
accept[num.size()] = i->second->accept;
|
accept[num.size()] = i->second->perms.allow;
|
||||||
accept2[num.size()] = i->second->audit;
|
accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
|
||||||
num.insert(make_pair(i->second, num.size()));
|
num.insert(make_pair(i->second, num.size()));
|
||||||
}
|
}
|
||||||
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
|
||||||
|
@ -291,15 +291,16 @@ State *DFA::match(const char *str)
|
|||||||
|
|
||||||
void DFA::dump_uniq_perms(const char *s)
|
void DFA::dump_uniq_perms(const char *s)
|
||||||
{
|
{
|
||||||
set<pair<uint32_t, uint32_t> > uniq;
|
set<perms_t> uniq;
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
for (Partition::iterator i = states.begin(); i != states.end(); i++)
|
||||||
uniq.insert(make_pair((*i)->accept, (*i)->audit));
|
uniq.insert((*i)->perms);
|
||||||
|
|
||||||
cerr << "Unique Permission sets: " << s << " (" << uniq.size() << ")\n";
|
cerr << "Unique Permission sets: " << s << " (" << uniq.size() << ")\n";
|
||||||
cerr << "----------------------\n";
|
cerr << "----------------------\n";
|
||||||
for (set<pair<uint32_t, uint32_t> >::iterator i = uniq.begin();
|
for (set<perms_t >::iterator i = uniq.begin(); i != uniq.end(); i++) {
|
||||||
i != uniq.end(); i++) {
|
cerr << " allow:" << hex << i->allow << " deny:"
|
||||||
cerr << " " << hex << i->first << " " << i->second << dec << "\n";
|
<< i->deny << " audit:" << i->audit
|
||||||
|
<< " quiet:" << i->quiet << dec << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,10 +340,12 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
|||||||
cerr << "unreachable: " << **i;
|
cerr << "unreachable: " << **i;
|
||||||
if (*i == start)
|
if (*i == start)
|
||||||
cerr << " <==";
|
cerr << " <==";
|
||||||
if ((*i)->accept) {
|
if (!(*i)->perms.is_null()) {
|
||||||
cerr << " (0x" << hex
|
cerr << " (0x" << hex
|
||||||
<< (*i)->accept << " "
|
<< (*i)->perms.allow << " "
|
||||||
<< (*i)->audit << dec
|
<< (*i)->perms.deny << " "
|
||||||
|
<< (*i)->perms.audit << " "
|
||||||
|
<< (*i)->perms.quiet << dec
|
||||||
<< ')';
|
<< ')';
|
||||||
}
|
}
|
||||||
cerr << "\n";
|
cerr << "\n";
|
||||||
@ -438,9 +441,9 @@ void DFA::minimize(dfaflags_t flags)
|
|||||||
uint64_t perm_hash = 0;
|
uint64_t perm_hash = 0;
|
||||||
if (flags & DFA_CONTROL_MINIMIZE_HASH_PERMS) {
|
if (flags & DFA_CONTROL_MINIMIZE_HASH_PERMS) {
|
||||||
/* make every unique perm create a new partition */
|
/* make every unique perm create a new partition */
|
||||||
perm_hash = ((uint64_t) (*i)->audit) << 32 |
|
perm_hash = ((uint64_t) PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32 |
|
||||||
(uint64_t) (*i)->accept;
|
(uint64_t) (*i)->perms.allow;
|
||||||
} else if ((*i)->audit || (*i)->accept) {
|
} else if (!(*i)->perms.is_null()) {
|
||||||
/* combine all perms together into a single parition */
|
/* combine all perms together into a single parition */
|
||||||
perm_hash = 1;
|
perm_hash = 1;
|
||||||
} /* else not an accept state so 0 for perm_hash */
|
} /* else not an accept state so 0 for perm_hash */
|
||||||
@ -467,7 +470,6 @@ void DFA::minimize(dfaflags_t flags)
|
|||||||
<< partitions.size() << "\tinit " << partitions.size()
|
<< partitions.size() << "\tinit " << partitions.size()
|
||||||
<< " (accept " << accept_count << ")\r";
|
<< " (accept " << accept_count << ")\r";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* perm_map is no longer needed so free the memory it is using.
|
/* perm_map is no longer needed so free the memory it is using.
|
||||||
* Don't remove - doing it manually here helps reduce peak memory usage.
|
* Don't remove - doing it manually here helps reduce peak memory usage.
|
||||||
*/
|
*/
|
||||||
@ -567,10 +569,12 @@ void DFA::minimize(dfaflags_t flags)
|
|||||||
if (flags & DFA_DUMP_MIN_PARTS)
|
if (flags & DFA_DUMP_MIN_PARTS)
|
||||||
cerr << **i << ", ";
|
cerr << **i << ", ";
|
||||||
(*i)->label = -1;
|
(*i)->label = -1;
|
||||||
rep->accept |= (*i)->accept;
|
rep->perms.allow |= (*i)->perms.allow;
|
||||||
rep->audit |= (*i)->audit;
|
rep->perms.deny |= (*i)->perms.deny;
|
||||||
|
rep->perms.audit |= (*i)->perms.audit;
|
||||||
|
rep->perms.quiet |= (*i)->perms.quiet;
|
||||||
}
|
}
|
||||||
if (rep->accept || rep->audit)
|
if (rep->perms.allow || rep->perms.audit || rep->perms.quiet)
|
||||||
final_accept++;
|
final_accept++;
|
||||||
//if ((*p)->size() > 1)
|
//if ((*p)->size() > 1)
|
||||||
//cerr << "\n";
|
//cerr << "\n";
|
||||||
@ -625,13 +629,15 @@ out:
|
|||||||
void DFA::dump(ostream & os)
|
void DFA::dump(ostream & os)
|
||||||
{
|
{
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||||
if (*i == start || (*i)->accept) {
|
if (*i == start || !(*i)->perms.is_null()) {
|
||||||
os << **i;
|
os << **i;
|
||||||
if (*i == start)
|
if (*i == start)
|
||||||
os << " <==";
|
os << " <==";
|
||||||
if ((*i)->accept) {
|
if ((*i)->perms.allow) {
|
||||||
os << " (0x" << hex << (*i)->accept << " "
|
os << " (0x" << hex << (*i)->perms.allow << " "
|
||||||
<< (*i)->audit << dec << ')';
|
<< (*i)->perms.deny << " "
|
||||||
|
<< (*i)->perms.audit << " "
|
||||||
|
<< (*i)->perms.audit << dec << ')';
|
||||||
}
|
}
|
||||||
os << "\n";
|
os << "\n";
|
||||||
}
|
}
|
||||||
@ -665,7 +671,7 @@ void DFA::dump_dot_graph(ostream & os)
|
|||||||
if (*i == start) {
|
if (*i == start) {
|
||||||
os << "\t\tstyle=bold" << "\n";
|
os << "\t\tstyle=bold" << "\n";
|
||||||
}
|
}
|
||||||
uint32_t perms = (*i)->accept;
|
uint32_t perms = (*i)->perms.allow;
|
||||||
if (perms) {
|
if (perms) {
|
||||||
os << "\t\tlabel=\"" << **i << "\\n("
|
os << "\t\tlabel=\"" << **i << "\\n("
|
||||||
<< perms << ")\"" << "\n";
|
<< perms << ")\"" << "\n";
|
||||||
@ -847,17 +853,16 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
|
|||||||
* have any exact matches, then they override the execute and safe
|
* have any exact matches, then they override the execute and safe
|
||||||
* execute flags.
|
* execute flags.
|
||||||
*/
|
*/
|
||||||
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
|
int accept_perms(NodeSet *state, perms_t &perms)
|
||||||
{
|
{
|
||||||
uint32_t perms = 0, exact_match_perms = 0;
|
int error = 0;
|
||||||
|
uint32_t allow = 0, exact_match_allow = 0;
|
||||||
uint32_t audit = 0, exact_audit = 0, quiet = 0, deny = 0;
|
uint32_t audit = 0, exact_audit = 0, quiet = 0, deny = 0;
|
||||||
|
|
||||||
if (error)
|
perms.clear();
|
||||||
*error = 0;
|
|
||||||
if (!state) {
|
if (!state)
|
||||||
*audit_ctl = 0;
|
return error;
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
|
||||||
MatchFlag *match;
|
MatchFlag *match;
|
||||||
@ -865,68 +870,69 @@ uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
|
|||||||
continue;
|
continue;
|
||||||
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
if (dynamic_cast<ExactMatchFlag *>(match)) {
|
||||||
/* exact match only ever happens with x */
|
/* exact match only ever happens with x */
|
||||||
if (!is_merged_x_consistent(exact_match_perms,
|
if (!is_merged_x_consistent(exact_match_allow,
|
||||||
match->flag) && error)
|
match->flag))
|
||||||
*error = 1;;
|
error = 1;;
|
||||||
exact_match_perms |= match->flag;
|
exact_match_allow |= match->flag;
|
||||||
exact_audit |= match->audit;
|
exact_audit |= match->audit;
|
||||||
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
|
} else if (dynamic_cast<DenyMatchFlag *>(match)) {
|
||||||
deny |= match->flag;
|
deny |= match->flag;
|
||||||
quiet |= match->audit;
|
quiet |= match->audit;
|
||||||
} else {
|
} else {
|
||||||
if (!is_merged_x_consistent(perms, match->flag)
|
if (!is_merged_x_consistent(allow, match->flag))
|
||||||
&& error)
|
error = 1;
|
||||||
*error = 1;
|
allow |= match->flag;
|
||||||
perms |= match->flag;
|
|
||||||
audit |= match->audit;
|
audit |= match->audit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (audit || quiet)
|
//if (audit || quiet)
|
||||||
//fprintf(stderr, "perms: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", perms, audit, exact_match_perms, exact_audit, deny, quiet);
|
//fprintf(stderr, "allow: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", allow, audit, exact_match_allow, exact_audit, deny, quiet);
|
||||||
|
|
||||||
perms |= exact_match_perms & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
|
allow |= exact_match_allow & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
|
||||||
|
|
||||||
if (exact_match_perms & AA_USER_EXEC_TYPE) {
|
if (exact_match_allow & AA_USER_EXEC_TYPE) {
|
||||||
perms = (exact_match_perms & AA_USER_EXEC_TYPE) |
|
allow = (exact_match_allow & AA_USER_EXEC_TYPE) |
|
||||||
(perms & ~AA_USER_EXEC_TYPE);
|
(allow & ~AA_USER_EXEC_TYPE);
|
||||||
audit = (exact_audit & AA_USER_EXEC_TYPE) |
|
audit = (exact_audit & AA_USER_EXEC_TYPE) |
|
||||||
(audit & ~AA_USER_EXEC_TYPE);
|
(audit & ~AA_USER_EXEC_TYPE);
|
||||||
}
|
}
|
||||||
if (exact_match_perms & AA_OTHER_EXEC_TYPE) {
|
if (exact_match_allow & AA_OTHER_EXEC_TYPE) {
|
||||||
perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) |
|
allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) |
|
||||||
(perms & ~AA_OTHER_EXEC_TYPE);
|
(allow & ~AA_OTHER_EXEC_TYPE);
|
||||||
audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
|
audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
|
||||||
(audit & ~AA_OTHER_EXEC_TYPE);
|
(audit & ~AA_OTHER_EXEC_TYPE);
|
||||||
}
|
}
|
||||||
if (perms & AA_USER_EXEC & deny)
|
if (allow & AA_USER_EXEC & deny)
|
||||||
perms &= ~AA_USER_EXEC_TYPE;
|
allow &= ~AA_USER_EXEC_TYPE;
|
||||||
|
|
||||||
if (perms & AA_OTHER_EXEC & deny)
|
if (allow & AA_OTHER_EXEC & deny)
|
||||||
perms &= ~AA_OTHER_EXEC_TYPE;
|
allow &= ~AA_OTHER_EXEC_TYPE;
|
||||||
|
|
||||||
perms &= ~deny;
|
allow &= ~deny;
|
||||||
|
|
||||||
if (audit_ctl)
|
perms.allow = allow & ~deny;
|
||||||
*audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny);
|
perms.deny = deny;
|
||||||
|
perms.audit = audit;
|
||||||
|
perms.quiet = quiet & deny;
|
||||||
|
|
||||||
// if (perms & AA_ERROR_BIT) {
|
// if (allow & AA_ERROR_BIT) {
|
||||||
// fprintf(stderr, "error bit 0x%x\n", perms);
|
// fprintf(stderr, "error bit 0x%x\n", allow);
|
||||||
// exit(255);
|
// exit(255);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
//if (perms & AA_EXEC_BITS)
|
//if (allow & AA_EXEC_BITS)
|
||||||
//fprintf(stderr, "accept perm: 0x%x\n", perms);
|
//fprintf(stderr, "accept perm: 0x%x\n", allow);
|
||||||
/*
|
/*
|
||||||
if (perms & ~AA_VALID_PERMS)
|
if (allow & ~AA_VALID_PERMS)
|
||||||
yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), perms);
|
yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), allow);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//if (perms & AA_CHANGE_HAT)
|
//if (allow & AA_CHANGE_HAT)
|
||||||
// fprintf(stderr, "change_hat 0x%x\n", perms);
|
// fprintf(stderr, "change_hat 0x%x\n", 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");
|
||||||
|
|
||||||
return perms;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,36 @@ class State;
|
|||||||
typedef map<uchar, State *> StateTrans;
|
typedef map<uchar, State *> StateTrans;
|
||||||
typedef list<State *> Partition;
|
typedef list<State *> Partition;
|
||||||
|
|
||||||
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
|
class perms_t {
|
||||||
|
public:
|
||||||
|
perms_t(void): allow(0), deny(0), audit(0), quiet(0) { };
|
||||||
|
|
||||||
|
bool is_null(void) { return !(allow | deny | audit | quiet); }
|
||||||
|
|
||||||
|
void clear(void) { allow = deny = audit = quiet = 0; }
|
||||||
|
void add(perms_t &rhs)
|
||||||
|
{
|
||||||
|
deny |= rhs.deny;
|
||||||
|
allow = (allow | rhs.audit) & ~deny;
|
||||||
|
audit |= rhs.audit;
|
||||||
|
quiet = (quiet | rhs.quiet) & deny;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(perms_t const &rhs)const
|
||||||
|
{
|
||||||
|
if (allow < rhs.allow)
|
||||||
|
return allow < rhs.allow;
|
||||||
|
if (deny < rhs.deny)
|
||||||
|
return deny < rhs.deny;
|
||||||
|
if (audit < rhs.audit)
|
||||||
|
return audit < rhs.audit;
|
||||||
|
return quiet < rhs.quiet;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t allow, deny, audit, quiet;
|
||||||
|
};
|
||||||
|
|
||||||
|
int accept_perms(NodeSet *state, perms_t &perms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* hashedNodes - for efficient set comparison
|
* hashedNodes - for efficient set comparison
|
||||||
@ -256,7 +285,7 @@ public:
|
|||||||
class State {
|
class State {
|
||||||
public:
|
public:
|
||||||
State(int l, ProtoState &n, State *other) throw(int):
|
State(int l, ProtoState &n, State *other) throw(int):
|
||||||
label(l), audit(0), accept(0), trans()
|
label(l), perms(), trans()
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -268,7 +297,7 @@ public:
|
|||||||
proto = n;
|
proto = n;
|
||||||
|
|
||||||
/* Compute permissions associated with the State. */
|
/* Compute permissions associated with the State. */
|
||||||
accept = accept_perms(n.anodes, &audit, &error);
|
error = accept_perms(n.anodes, perms);
|
||||||
if (error) {
|
if (error) {
|
||||||
//cerr << "Failing on accept perms " << error << "\n";
|
//cerr << "Failing on accept perms " << error << "\n";
|
||||||
throw error;
|
throw error;
|
||||||
@ -283,7 +312,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
int label;
|
int label;
|
||||||
uint32_t audit, accept;
|
perms_t perms;
|
||||||
StateTrans trans;
|
StateTrans trans;
|
||||||
State *otherwise;
|
State *otherwise;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user