2
0
mirror of https://gitlab.com/apparmor/apparmor synced 2025-08-23 02:27:12 +00:00

Lindent + some hand cleanups hfa

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Seth Arnold <seth.arnold@gmail.com>
This commit is contained in:
John Johansen 2011-03-13 05:55:25 -07:00
parent 3cfe47d3f0
commit 9a377bb9da
3 changed files with 319 additions and 317 deletions

View File

@ -30,7 +30,7 @@ using namespace std;
class TransitionTable { class TransitionTable {
typedef vector<pair<const State *, size_t> > DefaultBase; typedef vector<pair<const State *, size_t> > DefaultBase;
typedef vector<pair<const State *, const State *> >NextCheck; typedef vector<pair<const State *, const State *> > NextCheck;
public: public:
TransitionTable(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags); TransitionTable(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags);
void dump(ostream & os); void dump(ostream & os);

View File

@ -35,9 +35,7 @@
#include "hfa.h" #include "hfa.h"
#include "../immunix.h" #include "../immunix.h"
ostream &operator<<(ostream &os, const State &state)
ostream& operator<<(ostream& os, const State& state)
{ {
/* dump the state label */ /* dump the state label */
os << '{'; os << '{';
@ -46,7 +44,9 @@ ostream& operator<<(ostream& os, const State& state)
return os; return os;
} }
State* DFA::add_new_state(NodeMap &nodemap, pair <unsigned long, NodeSet *> index, NodeSet *nodes, dfa_stats_t &stats) State *DFA::add_new_state(NodeMap &nodemap,
pair<unsigned long, NodeSet *> index,
NodeSet *nodes, dfa_stats_t &stats)
{ {
State *state = new State(nodemap.size(), nodes); State *state = new State(nodemap.size(), nodes);
states.push_back(state); states.push_back(state);
@ -57,14 +57,14 @@ State* DFA::add_new_state(NodeMap &nodemap, pair <unsigned long, NodeSet *> inde
return state; return state;
} }
State *DFA::find_target_state(NodeMap &nodemap, list <State *> &work_queue, State *DFA::find_target_state(NodeMap &nodemap, list<State *> &work_queue,
NodeSet *nodes, dfa_stats_t &stats) NodeSet *nodes, dfa_stats_t &stats)
{ {
State *target; State *target;
pair <unsigned long, NodeSet *> index = make_pair(hash_NodeSet(nodes), nodes); pair<unsigned long, NodeSet *> index = make_pair(hash_NodeSet(nodes), nodes);
map<pair <unsigned long, NodeSet *>, State *, deref_less_than>::iterator x = nodemap.find(index); map<pair<unsigned long, NodeSet *>, State *, deref_less_than>::iterator x = nodemap.find(index);
if (x == nodemap.end()) { if (x == nodemap.end()) {
/* set of nodes isn't known so create new state, and nodes to /* set of nodes isn't known so create new state, and nodes to
@ -75,16 +75,15 @@ State *DFA::find_target_state(NodeMap &nodemap, list <State *> &work_queue,
} else { } else {
/* set of nodes already has a mapping so free this one */ /* set of nodes already has a mapping so free this one */
stats.duplicates++; stats.duplicates++;
delete (nodes); delete(nodes);
target = x->second; target = x->second;
} }
return target; return target;
} }
void DFA::update_state_transitions(NodeMap &nodemap, void DFA::update_state_transitions(NodeMap &nodemap, list<State *> &work_queue,
list <State *> &work_queue, State *state, State *state, dfa_stats_t &stats)
dfa_stats_t &stats)
{ {
/* Compute possible transitions for state->nodes. This is done by /* Compute possible transitions for state->nodes. This is done by
* iterating over all the nodes in state->nodes and combining the * iterating over all the nodes in state->nodes and combining the
@ -113,8 +112,7 @@ void DFA::update_state_transitions(NodeMap &nodemap,
*/ */
for (NodeCases::iterator j = cases.begin(); j != cases.end(); j++) { for (NodeCases::iterator j = cases.begin(); j != cases.end(); j++) {
State *target; State *target;
target = find_target_state(nodemap, work_queue, j->second, target = find_target_state(nodemap, work_queue, j->second, stats);
stats);
/* Don't insert transition that the default transition /* Don't insert transition that the default transition
* already covers * already covers
@ -124,7 +122,6 @@ void DFA::update_state_transitions(NodeMap &nodemap,
} }
} }
/* WARNING: This routine can only be called from within DFA creation as /* WARNING: This routine can only be called from within DFA creation as
* the nodes value is only valid during dfa construction. * the nodes value is only valid during dfa construction.
*/ */
@ -140,7 +137,7 @@ void DFA::dump_node_to_dfa(void)
/** /**
* Construct a DFA from a syntax tree. * Construct a DFA from a syntax tree.
*/ */
DFA::DFA(Node *root, dfaflags_t flags) : root(root) DFA::DFA(Node *root, dfaflags_t flags): root(root)
{ {
dfa_stats_t stats = { 0, 0, 0 }; dfa_stats_t stats = { 0, 0, 0 };
int i = 0; int i = 0;
@ -163,7 +160,7 @@ DFA::DFA(Node *root, dfaflags_t flags) : root(root)
NodeMap nodemap; NodeMap nodemap;
NodeSet *emptynode = new NodeSet; NodeSet *emptynode = new NodeSet;
nonmatching = add_new_state(nodemap, nonmatching = add_new_state(nodemap,
make_pair(hash_NodeSet(emptynode), emptynode), make_pair(hash_NodeSet(emptynode), emptynode),
emptynode, stats); emptynode, stats);
NodeSet *first = new NodeSet(root->firstpos); NodeSet *first = new NodeSet(root->firstpos);
@ -185,7 +182,9 @@ DFA::DFA(Node *root, dfaflags_t flags) : root(root)
while (!work_queue.empty()) { while (!work_queue.empty()) {
if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS))
fprintf(stderr, "\033[2KCreating dfa: queue %ld\tstates %ld\teliminated duplicates %d\r", work_queue.size(), states.size(), stats.duplicates); fprintf(stderr, "\033[2KCreating dfa: queue %ld\tstates %ld\teliminated duplicates %d\r",
work_queue.size(), states.size(),
stats.duplicates);
i++; i++;
State *from = work_queue.front(); State *from = work_queue.front();
@ -196,7 +195,7 @@ DFA::DFA(Node *root, dfaflags_t flags) : root(root)
*/ */
update_state_transitions(nodemap, work_queue, from, stats); update_state_transitions(nodemap, work_queue, from, stats);
} /* for (NodeSet *nodes ... */ } /* while (!work_queue.empty()) */
/* cleanup Sets of nodes used computing the DFA as they are no longer /* cleanup Sets of nodes used computing the DFA as they are no longer
* needed. * needed.
@ -215,37 +214,37 @@ DFA::DFA(Node *root, dfaflags_t flags) : root(root)
nodemap.clear(); nodemap.clear();
if (flags & (DFA_DUMP_STATS)) if (flags & (DFA_DUMP_STATS))
fprintf(stderr, "\033[2KCreated dfa: states %ld,\teliminated duplicates %d,\tprotostate sets: longest %u, avg %u\n", states.size(), stats.duplicates, stats.proto_max, (unsigned int) (stats.proto_sum/states.size())); fprintf(stderr, "\033[2KCreated dfa: states %ld,\teliminated duplicates %d,\tprotostate sets: longest %u, avg %u\n",
states.size(), stats.duplicates, stats.proto_max,
(unsigned int)(stats.proto_sum / states.size()));
} }
DFA::~DFA() DFA::~DFA()
{ {
for (Partition::iterator i = states.begin(); i != states.end(); i++) for (Partition::iterator i = states.begin(); i != states.end(); i++)
delete *i; delete *i;
} }
void DFA::dump_uniq_perms(const char *s) void DFA::dump_uniq_perms(const char *s)
{ {
set < pair<uint32_t, uint32_t> > uniq; set<pair<uint32_t, uint32_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(make_pair((*i)->accept, (*i)->audit));
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<pair<uint32_t, uint32_t> >::iterator i = uniq.begin();
i != uniq.end(); i++) { i != uniq.end(); i++) {
cerr << " " << hex << i->first << " " << i->second << dec <<"\n"; cerr << " " << hex << i->first << " " << i->second << dec << "\n";
} }
} }
/* Remove dead or unreachable states */ /* Remove dead or unreachable states */
void DFA::remove_unreachable(dfaflags_t flags) void DFA::remove_unreachable(dfaflags_t flags)
{ {
set <State *> reachable; set<State *> reachable;
list <State *> work_queue; list<State *> work_queue;
/* find the set of reachable states */ /* find the set of reachable states */
reachable.insert(nonmatching); reachable.insert(nonmatching);
@ -259,8 +258,7 @@ void DFA::remove_unreachable(dfaflags_t flags)
(reachable.find(from->cases.otherwise) == reachable.end())) (reachable.find(from->cases.otherwise) == reachable.end()))
work_queue.push_back(from->cases.otherwise); work_queue.push_back(from->cases.otherwise);
for (Cases::iterator j = from->cases.begin(); for (Cases::iterator j = from->cases.begin(); j != from->cases.end(); j++) {
j != from->cases.end(); j++) {
if (reachable.find(j->second) == reachable.end()) if (reachable.find(j->second) == reachable.end())
work_queue.push_back(j->second); work_queue.push_back(j->second);
} }
@ -276,14 +274,16 @@ void DFA::remove_unreachable(dfaflags_t flags)
next++; next++;
if (reachable.find(*i) == reachable.end()) { if (reachable.find(*i) == reachable.end()) {
if (flags & DFA_DUMP_UNREACHABLE) { if (flags & DFA_DUMP_UNREACHABLE) {
cerr << "unreachable: "<< **i; cerr << "unreachable: " << **i;
if (*i == start) if (*i == start)
cerr << " <=="; cerr << " <==";
if ((*i)->accept) { if ((*i)->accept) {
cerr << " (0x" << hex << (*i)->accept cerr << " (0x" << hex
<< " " << (*i)->audit << dec << ')'; << (*i)->accept << " "
<< (*i)->audit << dec
<< ')';
} }
cerr << endl; cerr << "\n";
} }
State *current = *i; State *current = *i;
states.erase(i); states.erase(i);
@ -314,8 +314,7 @@ bool DFA::same_mappings(State *s1, State *s2)
if (s1->cases.cases.size() != s2->cases.cases.size()) if (s1->cases.cases.size() != s2->cases.cases.size())
return false; return false;
for (Cases::iterator j1 = s1->cases.begin(); j1 != s1->cases.end(); for (Cases::iterator j1 = s1->cases.begin(); j1 != s1->cases.end(); j1++) {
j1++){
Cases::iterator j2 = s2->cases.cases.find(j1->first); Cases::iterator j2 = s2->cases.cases.find(j1->first);
if (j2 == s2->cases.end()) if (j2 == s2->cases.end())
return false; return false;
@ -337,9 +336,9 @@ bool DFA::same_mappings(State *s1, State *s2)
*/ */
size_t DFA::hash_trans(State *s) size_t DFA::hash_trans(State *s)
{ {
unsigned long hash = 5381; unsigned long hash = 5381;
for (Cases::iterator j = s->cases.begin(); j != s->cases.end(); j++){ for (Cases::iterator j = s->cases.begin(); j != s->cases.end(); j++) {
hash = ((hash << 5) + hash) + j->first; hash = ((hash << 5) + hash) + j->first;
State *k = j->second; State *k = j->second;
hash = ((hash << 5) + hash) + k->cases.cases.size(); hash = ((hash << 5) + hash) + k->cases.cases.size();
@ -352,15 +351,15 @@ size_t DFA::hash_trans(State *s)
} }
hash = (hash << 8) | s->cases.cases.size(); hash = (hash << 8) | s->cases.cases.size();
return hash; return hash;
} }
/* minimize the number of dfa states */ /* minimize the number of dfa states */
void DFA::minimize(dfaflags_t flags) void DFA::minimize(dfaflags_t flags)
{ {
map <pair <uint64_t, size_t>, Partition *> perm_map; map<pair<uint64_t, size_t>, Partition *> perm_map;
list <Partition *> partitions; list<Partition *> partitions;
/* Set up the initial partitions /* Set up the initial partitions
* minimium of - 1 non accepting, and 1 accepting * minimium of - 1 non accepting, and 1 accepting
* if trans hashing is used the accepting and non-accepting partitions * if trans hashing is used the accepting and non-accepting partitions
@ -377,18 +376,17 @@ 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) (*i)->audit) << 32 |
(uint64_t)(*i)->accept; (uint64_t) (*i)->accept;
} else if ((*i)->audit || (*i)->accept) { } else if ((*i)->audit || (*i)->accept) {
/* 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 */
size_t trans_hash = 0; size_t trans_hash = 0;
if (flags & DFA_CONTROL_MINIMIZE_HASH_TRANS) if (flags & DFA_CONTROL_MINIMIZE_HASH_TRANS)
trans_hash = hash_trans(*i); trans_hash = hash_trans(*i);
pair <uint64_t, size_t> group = make_pair(perm_hash, trans_hash); pair<uint64_t, size_t> group = make_pair(perm_hash, trans_hash);
map <pair <uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group); map<pair<uint64_t, size_t>, Partition *>::iterator p = perm_map.find(group);
if (p == perm_map.end()) { if (p == perm_map.end()) {
Partition *part = new Partition(); Partition *part = new Partition();
part->push_back(*i); part->push_back(*i);
@ -402,9 +400,10 @@ void DFA::minimize(dfaflags_t flags)
p->second->push_back(*i); p->second->push_back(*i);
} }
if ((flags & DFA_DUMP_PROGRESS) && if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 1000 == 0))
(partitions.size() % 1000 == 0)) cerr << "\033[2KMinimize dfa: partitions "
cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << partitions.size() << " (accept " << accept_count << ")\r"; << partitions.size() << "\tinit " << partitions.size()
<< " (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.
@ -414,7 +413,9 @@ void DFA::minimize(dfaflags_t flags)
int init_count = partitions.size(); int init_count = partitions.size();
if (flags & DFA_DUMP_PROGRESS) if (flags & DFA_DUMP_PROGRESS)
cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\r"; cerr << "\033[2KMinimize dfa: partitions " << partitions.size()
<< "\tinit " << init_count << " (accept "
<< accept_count << ")\r";
/* Now do repartitioning until each partition contains the set of /* Now do repartitioning until each partition contains the set of
* states that are the same. This will happen when the partition * states that are the same. This will happen when the partition
@ -425,20 +426,19 @@ void DFA::minimize(dfaflags_t flags)
int new_part_count; int new_part_count;
do { do {
new_part_count = 0; new_part_count = 0;
for (list <Partition *>::iterator p = partitions.begin(); for (list<Partition *>::iterator p = partitions.begin();
p != partitions.end(); p++) { p != partitions.end(); p++) {
new_part = NULL; new_part = NULL;
State *rep = *((*p)->begin()); State *rep = *((*p)->begin());
Partition::iterator next; Partition::iterator next;
for (Partition::iterator s = ++(*p)->begin(); for (Partition::iterator s = ++(*p)->begin(); s != (*p)->end();) {
s != (*p)->end(); ) {
if (same_mappings(rep, *s)) { if (same_mappings(rep, *s)) {
++s; ++s;
continue; continue;
} }
if (!new_part) { if (!new_part) {
new_part = new Partition; new_part = new Partition;
list <Partition *>::iterator tmp = p; list<Partition *>::iterator tmp = p;
partitions.insert(++tmp, new_part); partitions.insert(++tmp, new_part);
new_part_count++; new_part_count++;
} }
@ -454,16 +454,19 @@ void DFA::minimize(dfaflags_t flags)
(*m)->partition = new_part; (*m)->partition = new_part;
} }
} }
if ((flags & DFA_DUMP_PROGRESS) && if ((flags & DFA_DUMP_PROGRESS) && (partitions.size() % 100 == 0))
(partitions.size() % 100 == 0)) cerr << "\033[2KMinimize dfa: partitions "
cerr << "\033[2KMinimize dfa: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\r"; << partitions.size() << "\tinit "
<< init_count << " (accept "
<< accept_count << ")\r";
} }
} while(new_part_count); } while (new_part_count);
if (partitions.size() == states.size()) { if (partitions.size() == states.size()) {
if (flags & DFA_DUMP_STATS) if (flags & DFA_DUMP_STATS)
cerr << "\033[2KDfa minimization no states removed: partitions " << partitions.size() << "\tinit " << init_count << " (accept " << accept_count << ")\n"; cerr << "\033[2KDfa minimization no states removed: partitions "
<< partitions.size() << "\tinit " << init_count
<< " (accept " << accept_count << ")\n";
goto out; goto out;
} }
@ -474,7 +477,7 @@ void DFA::minimize(dfaflags_t flags)
* to states within the same partitions, however this can slow * to states within the same partitions, however this can slow
* down compressed dfa compression as there are more states, * down compressed dfa compression as there are more states,
*/ */
for (list <Partition *>::iterator p = partitions.begin(); for (list<Partition *>::iterator p = partitions.begin();
p != partitions.end(); p++) { p != partitions.end(); p++) {
/* representative state for this partition */ /* representative state for this partition */
State *rep = *((*p)->begin()); State *rep = *((*p)->begin());
@ -484,8 +487,7 @@ void DFA::minimize(dfaflags_t flags)
Partition *partition = rep->cases.otherwise->partition; Partition *partition = rep->cases.otherwise->partition;
rep->cases.otherwise = *partition->begin(); rep->cases.otherwise = *partition->begin();
} }
for (Cases::iterator c = rep->cases.begin(); for (Cases::iterator c = rep->cases.begin(); c != rep->cases.end(); c++) {
c != rep->cases.end(); c++) {
Partition *partition = c->second->partition; Partition *partition = c->second->partition;
c->second = *partition->begin(); c->second = *partition->begin();
} }
@ -506,9 +508,10 @@ void DFA::minimize(dfaflags_t flags)
//cerr << "\n"; //cerr << "\n";
} }
if (flags & DFA_DUMP_STATS) if (flags & DFA_DUMP_STATS)
cerr << "\033[2KMinimized dfa: final partitions " << partitions.size() << " (accept " << final_accept << ")" << "\tinit " << init_count << " (accept " << accept_count << ")\n"; cerr << "\033[2KMinimized dfa: final partitions "
<< partitions.size() << " (accept " << final_accept
<< ")" << "\tinit " << init_count << " (accept "
<< accept_count << ")\n";
/* make sure nonmatching and start state are up to date with the /* make sure nonmatching and start state are up to date with the
* mappings */ * mappings */
@ -528,7 +531,7 @@ void DFA::minimize(dfaflags_t flags)
* that are not the representive states for their partition, they * that are not the representive states for their partition, they
* will have a label == -1 * will have a label == -1
*/ */
for (Partition::iterator i = states.begin(); i != states.end(); ) { for (Partition::iterator i = states.begin(); i != states.end();) {
if ((*i)->label == -1) { if ((*i)->label == -1) {
State *s = *i; State *s = *i;
i = states.erase(i); i = states.erase(i);
@ -549,83 +552,85 @@ out:
/** /**
* text-dump the DFA (for debugging). * text-dump the DFA (for debugging).
*/ */
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)->accept) {
os << **i; os << **i;
if (*i == start) if (*i == start)
os << " <=="; os << " <==";
if ((*i)->accept) { if ((*i)->accept) {
os << " (0x" << hex << (*i)->accept << " " << (*i)->audit << dec << ')'; os << " (0x" << hex << (*i)->accept << " "
} << (*i)->audit << dec << ')';
os << endl; }
os << "\n";
}
} }
} os << "\n";
os << endl;
for (Partition::iterator i = states.begin(); i != states.end(); i++) { for (Partition::iterator i = states.begin(); i != states.end(); i++) {
if ((*i)->cases.otherwise) if ((*i)->cases.otherwise)
os << **i << " -> " << (*i)->cases.otherwise << endl; os << **i << " -> " << (*i)->cases.otherwise << "\n";
for (Cases::iterator j = (*i)->cases.begin(); j != (*i)->cases.end(); j++) { for (Cases::iterator j = (*i)->cases.begin();
os << **i << " -> " << j->second << ": " << j->first << endl; j != (*i)->cases.end(); j++) {
os << **i << " -> " << j->second << ": "
<< j->first << "\n";
}
} }
} os << "\n";
os << endl;
} }
/** /**
* Create a dot (graphviz) graph from the DFA (for debugging). * Create a dot (graphviz) graph from the DFA (for debugging).
*/ */
void DFA::dump_dot_graph(ostream& os) void DFA::dump_dot_graph(ostream & os)
{ {
os << "digraph \"dfa\" {" << endl; os << "digraph \"dfa\" {" << "\n";
for (Partition::iterator i = states.begin(); i != states.end(); i++) { for (Partition::iterator i = states.begin(); i != states.end(); i++) {
if (*i == nonmatching) if (*i == nonmatching)
continue; continue;
os << "\t\"" << **i << "\" [" << endl; os << "\t\"" << **i << "\" [" << "\n";
if (*i == start) { if (*i == start) {
os << "\t\tstyle=bold" << endl; os << "\t\tstyle=bold" << "\n";
}
uint32_t perms = (*i)->accept;
if (perms) {
os << "\t\tlabel=\"" << **i << "\\n("
<< perms << ")\"" << endl;
}
os << "\t]" << endl;
}
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
Cases& cases = (*i)->cases;
Chars excluded;
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
if (j->second == nonmatching)
excluded.insert(j->first);
else {
os << "\t\"" << **i << "\" -> \"";
os << j->second << "\" [" << endl;
os << "\t\tlabel=\"" << j->first << "\"" << endl;
os << "\t]" << endl;
}
}
if (cases.otherwise && cases.otherwise != nonmatching) {
os << "\t\"" << **i << "\" -> \"" << cases.otherwise
<< "\" [" << endl;
if (!excluded.empty()) {
os << "\t\tlabel=\"[^";
for (Chars::iterator i = excluded.begin();
i != excluded.end();
i++) {
os << *i;
} }
os << "]\"" << endl; uint32_t perms = (*i)->accept;
} if (perms) {
os << "\t]" << endl; os << "\t\tlabel=\"" << **i << "\\n("
<< perms << ")\"" << "\n";
}
os << "\t]" << "\n";
} }
} for (Partition::iterator i = states.begin(); i != states.end(); i++) {
os << '}' << endl; Cases &cases = (*i)->cases;
Chars excluded;
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
if (j->second == nonmatching)
excluded.insert(j->first);
else {
os << "\t\"" << **i << "\" -> \"" << j->second
<< "\" [" << "\n";
os << "\t\tlabel=\"" << j-> first << "\"\n";
os << "\t]" << "\n";
}
}
if (cases.otherwise && cases.otherwise != nonmatching) {
os << "\t\"" << **i << "\" -> \"" << cases.otherwise
<< "\" [" << "\n";
if (!excluded.empty()) {
os << "\t\tlabel=\"[^";
for (Chars::iterator i = excluded.begin();
i != excluded.end(); i++) {
os << *i;
}
os << "]\"" << "\n";
}
os << "\t]" << "\n";
}
}
os << '}' << "\n";
} }
/** /**
@ -634,144 +639,137 @@ void DFA::dump_dot_graph(ostream& os)
*/ */
map<uchar, uchar> DFA::equivalence_classes(dfaflags_t flags) map<uchar, uchar> DFA::equivalence_classes(dfaflags_t flags)
{ {
map<uchar, uchar> classes; map<uchar, uchar> classes;
uchar next_class = 1; uchar next_class = 1;
for (Partition::iterator i = states.begin(); i != states.end(); i++) { for (Partition::iterator i = states.begin(); i != states.end(); i++) {
Cases& cases = (*i)->cases; Cases & cases = (*i)->cases;
/* Group edges to the same next state together */ /* Group edges to the same next state together */
map<const State *, Chars> node_sets; map<const State *, Chars> node_sets;
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) for (Cases::iterator j = cases.begin(); j != cases.end(); j++)
node_sets[j->second].insert(j->first); node_sets[j->second].insert(j->first);
for (map<const State *, Chars>::iterator j = node_sets.begin(); for (map<const State *, Chars>::iterator j = node_sets.begin();
j != node_sets.end(); j != node_sets.end(); j++) {
j++) { /* Group edges to the same next state together by class */
/* Group edges to the same next state together by class */ map<uchar, Chars> node_classes;
map<uchar, Chars> node_classes; bool class_used = false;
bool class_used = false; for (Chars::iterator k = j->second.begin();
for (Chars::iterator k = j->second.begin(); k != j->second.end(); k++) {
k != j->second.end(); pair<map<uchar, uchar>::iterator, bool> x = classes.insert(make_pair(*k, next_class));
k++) { if (x.second)
pair<map<uchar, uchar>::iterator, bool> x = class_used = true;
classes.insert(make_pair(*k, next_class)); pair<map<uchar, Chars>::iterator, bool> y = node_classes.insert(make_pair(x.first->second, Chars()));
if (x.second) y.first->second.insert(*k);
class_used = true; }
pair<map<uchar, Chars>::iterator, bool> y = if (class_used) {
node_classes.insert(make_pair(x.first->second, Chars())); next_class++;
y.first->second.insert(*k); class_used = false;
} }
if (class_used) { for (map<uchar, Chars>::iterator k = node_classes.begin();
next_class++; k != node_classes.end(); k++) {
class_used = false; /**
} * If any other characters are in the same class, move
for (map<uchar, Chars>::iterator k = node_classes.begin(); * the characters in this class into their own new
k != node_classes.end(); * class
k++) { */
/** map<uchar, uchar>::iterator l;
* If any other characters are in the same class, move for (l = classes.begin(); l != classes.end(); l++) {
* the characters in this class into their own new class if (l->second == k->first &&
*/ k->second.find(l->first) == k->second.end()) {
map<uchar, uchar>::iterator l; class_used = true;
for (l = classes.begin(); l != classes.end(); l++) { break;
if (l->second == k->first && }
k->second.find(l->first) == k->second.end()) { }
class_used = true; if (class_used) {
break; for (Chars::iterator l = k->second.begin();
} l != k->second.end(); l++) {
classes[*l] = next_class;
}
next_class++;
class_used = false;
}
}
} }
if (class_used) {
for (Chars::iterator l = k->second.begin();
l != k->second.end();
l++) {
classes[*l] = next_class;
}
next_class++;
class_used = false;
}
}
} }
}
if (flags & DFA_DUMP_EQUIV_STATS) if (flags & DFA_DUMP_EQUIV_STATS)
fprintf(stderr, "Equiv class reduces to %d classes\n", next_class - 1); fprintf(stderr, "Equiv class reduces to %d classes\n",
return classes; next_class - 1);
return classes;
} }
/** /**
* Text-dump the equivalence classes (for debugging). * Text-dump the equivalence classes (for debugging).
*/ */
void dump_equivalence_classes(ostream& os, map<uchar, uchar>& eq) void dump_equivalence_classes(ostream &os, map<uchar, uchar> &eq)
{ {
map<uchar, Chars> rev; map<uchar, Chars> rev;
for (map<uchar, uchar>::iterator i = eq.begin(); i != eq.end(); i++) { for (map<uchar, uchar>::iterator i = eq.begin(); i != eq.end(); i++) {
Chars& chars = rev.insert(make_pair(i->second, Chars &chars = rev.insert(make_pair(i->second, Chars())).first->second;
Chars())).first->second; chars.insert(i->first);
chars.insert(i->first); }
} os << "(eq):" << "\n";
os << "(eq):" << endl; for (map<uchar, Chars>::iterator i = rev.begin(); i != rev.end(); i++) {
for (map<uchar, Chars>::iterator i = rev.begin(); i != rev.end(); i++) { os << (int)i->first << ':';
os << (int)i->first << ':'; Chars &chars = i->second;
Chars& chars = i->second; for (Chars::iterator j = chars.begin(); j != chars.end(); j++) {
for (Chars::iterator j = chars.begin(); j != chars.end(); j++) { os << ' ' << *j;
os << ' ' << *j; }
os << "\n";
} }
os << endl;
}
} }
/** /**
* Replace characters with classes (which are also represented as * Replace characters with classes (which are also represented as
* characters) in the DFA transition table. * characters) in the DFA transition table.
*/ */
void DFA::apply_equivalence_classes(map<uchar, uchar>& eq) void DFA::apply_equivalence_classes(map<uchar, uchar> &eq)
{ {
/** /**
* Note: We only transform the transition table; the nodes continue to * Note: We only transform the transition table; the nodes continue to
* contain the original characters. * contain the original characters.
*/ */
for (Partition::iterator i = states.begin(); i != states.end(); i++) { for (Partition::iterator i = states.begin(); i != states.end(); i++) {
map<uchar, State *> tmp; map<uchar, State *> tmp;
tmp.swap((*i)->cases.cases); tmp.swap((*i)->cases.cases);
for (Cases::iterator j = tmp.begin(); j != tmp.end(); j++) for (Cases::iterator j = tmp.begin(); j != tmp.end(); j++)
(*i)->cases.cases.insert(make_pair(eq[j->first], j->second)); (*i)->cases.cases.
} insert(make_pair(eq[j->first], j->second));
}
} }
#if 0 #if 0
typedef set<ImportantNode *> AcceptNodes; typedef set <ImportantNode *>AcceptNodes;
map<ImportantNode *, AcceptNodes> dominance(DFA& dfa) map<ImportantNode *, AcceptNodes> dominance(DFA & dfa)
{ {
map<ImportantNode *, AcceptNodes> is_dominated; map<ImportantNode *, AcceptNodes> is_dominated;
for (States::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) { for (States::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
AcceptNodes set1; AcceptNodes set1;
for (State::iterator j = (*i)->begin(); j != (*i)->end(); j++) { for (State::iterator j = (*i)->begin(); j != (*i)->end(); j++) {
if (AcceptNode *accept = dynamic_cast<AcceptNode *>(*j)) if (AcceptNode * accept = dynamic_cast<AcceptNode *>(*j))
set1.insert(accept); set1.insert(accept);
} }
for (AcceptNodes::iterator j = set1.begin(); j != set1.end(); j++) { for (AcceptNodes::iterator j = set1.begin(); j != set1.end(); j++) {
pair<map<ImportantNode *, AcceptNodes>::iterator, bool> x = pair<map<ImportantNode *, AcceptNodes>::iterator, bool> x = is_dominated.insert(make_pair(*j, set1));
is_dominated.insert(make_pair(*j, set1)); if (!x.second) {
if (!x.second) { AcceptNodes & set2(x.first->second), set3;
AcceptNodes &set2(x.first->second), set3; for (AcceptNodes::iterator l = set2.begin();
for (AcceptNodes::iterator l = set2.begin(); l != set2.end(); l++) {
l != set2.end(); if (set1.find(*l) != set1.end())
l++) { set3.insert(*l);
if (set1.find(*l) != set1.end()) }
set3.insert(*l); set3.swap(set2);
}
} }
set3.swap(set2);
}
} }
} return is_dominated;
return is_dominated;
} }
#endif #endif
static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2) static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
{ {
return ((perm1 & AA_EXEC_TYPE) && (perm2 & AA_EXEC_TYPE) && return ((perm1 & AA_EXEC_TYPE) && (perm2 & AA_EXEC_TYPE) &&
@ -785,79 +783,79 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
*/ */
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error) uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
{ {
uint32_t perms = 0, exact_match_perms = 0, audit = 0, exact_audit = 0, uint32_t perms = 0, exact_match_perms = 0;
quiet = 0, deny = 0; uint32_t audit = 0, exact_audit = 0, quiet = 0, deny = 0;
if (error) if (error)
*error = 0; *error = 0;
for (NodeSet::iterator i = state->begin(); i != state->end(); i++) { for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
MatchFlag *match; MatchFlag *match;
if (!(match= dynamic_cast<MatchFlag *>(*i))) if (!(match = dynamic_cast<MatchFlag *>(*i)))
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_perms,
match->flag) && error) match->flag) && error)
*error = 1;; *error = 1;;
exact_match_perms |= match->flag; exact_match_perms |= 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) && error) if (!is_merged_x_consistent(perms, match->flag)
*error = 1; && error)
perms |= match->flag; *error = 1;
audit |= match->audit; perms |= match->flag;
} 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, "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);
perms |= exact_match_perms & perms |= exact_match_perms & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
if (exact_match_perms & AA_USER_EXEC_TYPE) { if (exact_match_perms & AA_USER_EXEC_TYPE) {
perms = (exact_match_perms & AA_USER_EXEC_TYPE) | perms = (exact_match_perms & AA_USER_EXEC_TYPE) |
(perms & ~AA_USER_EXEC_TYPE); (perms & ~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_perms & AA_OTHER_EXEC_TYPE) {
perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) | perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) |
(perms & ~AA_OTHER_EXEC_TYPE); (perms & ~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 (perms & AA_USER_EXEC & deny)
perms &= ~AA_USER_EXEC_TYPE; perms &= ~AA_USER_EXEC_TYPE;
if (perms & AA_OTHER_EXEC & deny) if (perms & AA_OTHER_EXEC & deny)
perms &= ~AA_OTHER_EXEC_TYPE; perms &= ~AA_OTHER_EXEC_TYPE;
perms &= ~deny; perms &= ~deny;
if (audit_ctl) if (audit_ctl)
*audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny); *audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny);
// if (perms & AA_ERROR_BIT) { // if (perms & AA_ERROR_BIT) {
// fprintf(stderr, "error bit 0x%x\n", perms); // fprintf(stderr, "error bit 0x%x\n", perms);
// exit(255); // exit(255);
//} //}
//if (perms & AA_EXEC_BITS) //if (perms & AA_EXEC_BITS)
//fprintf(stderr, "accept perm: 0x%x\n", perms); //fprintf(stderr, "accept perm: 0x%x\n", perms);
/* /*
if (perms & ~AA_VALID_PERMS) if (perms & ~AA_VALID_PERMS)
yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), perms); yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), perms);
*/ */
//if (perms & AA_CHANGE_HAT) //if (perms & AA_CHANGE_HAT)
// fprintf(stderr, "change_hat 0x%x\n", perms); // fprintf(stderr, "change_hat 0x%x\n", perms);
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 perms;
} }

View File

@ -46,14 +46,14 @@ typedef struct Cases {
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<uchar, State *> cases; map<uchar, State *> cases;
State *otherwise; State *otherwise;
} Cases; } Cases;
typedef list<State *> Partition; typedef list<State *> Partition;
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error); uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
/* /*
@ -72,9 +72,9 @@ uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
*/ */
class State { class State {
public: public:
State() : label (0), audit(0), accept(0), cases(), nodes(NULL) { }; State(): label(0), audit(0), accept(0), cases(), nodes(NULL) { };
State(int l): label (l), audit(0), accept(0), cases(), nodes(NULL) { }; State(int l): label(l), audit(0), accept(0), cases(), nodes(NULL) { };
State(int l, NodeSet *n) throw (int): State(int l, NodeSet * n) throw(int):
label(l), audit(0), accept(0), cases(), nodes(n) label(l), audit(0), accept(0), cases(), nodes(n)
{ {
int error; int error;
@ -82,7 +82,7 @@ public:
/* Compute permissions associated with the State. */ /* Compute permissions associated with the State. */
accept = accept_perms(nodes, &audit, &error); accept = accept_perms(nodes, &audit, &error);
if (error) { if (error) {
//cerr << "Failing on accept perms " << error << "\n"; //cerr << "Failing on accept perms " << error << "\n";
throw error; throw error;
} }
}; };
@ -96,9 +96,9 @@ public:
}; };
}; };
ostream& operator<<(ostream& os, const State& state); ostream &operator<<(ostream &os, const State &state);
typedef map<pair<unsigned long, NodeSet *>, State *, deref_less_than > NodeMap; typedef map<pair<unsigned long, NodeSet *>, State *, deref_less_than> NodeMap;
/* Transitions in the DFA. */ /* Transitions in the DFA. */
/* dfa_stats - structure to group various stats about dfa creation /* dfa_stats - structure to group various stats about dfa creation
@ -112,28 +112,32 @@ typedef struct dfa_stats {
} dfa_stats_t; } dfa_stats_t;
class DFA { class DFA {
void dump_node_to_dfa(void); void dump_node_to_dfa(void);
State* add_new_state(NodeMap &nodemap, pair <unsigned long, NodeSet *> index, NodeSet *nodes, dfa_stats_t &stats); State *add_new_state(NodeMap &nodemap,
void update_state_transitions(NodeMap &nodemap, list <State *> &work_queue, State *state, dfa_stats_t &stats); pair<unsigned long, NodeSet *> index,
State *find_target_state(NodeMap &nodemap, list <State *> &work_queue,
NodeSet *nodes, dfa_stats_t &stats); NodeSet *nodes, dfa_stats_t &stats);
void update_state_transitions(NodeMap &nodemap,
list<State *> &work_queue,
State *state, dfa_stats_t &stats);
State *find_target_state(NodeMap &nodemap, list<State *> &work_queue,
NodeSet *nodes, dfa_stats_t &stats);
public: public:
DFA(Node *root, dfaflags_t flags); DFA(Node *root, dfaflags_t flags);
virtual ~DFA(); virtual ~DFA();
void remove_unreachable(dfaflags_t flags); void remove_unreachable(dfaflags_t flags);
bool same_mappings(State *s1, State *s2); bool same_mappings(State *s1, State *s2);
size_t hash_trans(State *s); size_t hash_trans(State *s);
void minimize(dfaflags_t flags); void minimize(dfaflags_t flags);
void dump(ostream& os); void dump(ostream &os);
void dump_dot_graph(ostream& os); void dump_dot_graph(ostream &os);
void dump_uniq_perms(const char *s); void dump_uniq_perms(const char *s);
map<uchar, uchar> equivalence_classes(dfaflags_t flags); map<uchar, uchar> equivalence_classes(dfaflags_t flags);
void apply_equivalence_classes(map<uchar, uchar>& eq); void apply_equivalence_classes(map<uchar, uchar> &eq);
Node *root; Node *root;
State *nonmatching, *start; State *nonmatching, *start;
Partition states; Partition states;
}; };
void dump_equivalence_classes(ostream& os, map<uchar, uchar>& eq); void dump_equivalence_classes(ostream &os, map<uchar, uchar> &eq);
#endif /* __LIBAA_RE_HFA_H */ #endif /* __LIBAA_RE_HFA_H */