mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-08-23 02:27:12 +00:00
This helps make the meaning of things a little clearer and provides a clear
distinction betwen NodeCases, and State transitions Signed-off-by: John Johansen <john.johansen@canonical.com> Acked-by: Kees Cook <kees@ubuntu.com>
This commit is contained in:
parent
3c11c66ff2
commit
bd66fba55f
@ -74,14 +74,14 @@ TransitionTable::TransitionTable(DFA &dfa, map<uchar, uchar> &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.start || *i == dfa.nonmatching)
|
if (*i == dfa.start || *i == dfa.nonmatching)
|
||||||
continue;
|
continue;
|
||||||
optimal += (*i)->cases.cases.size();
|
optimal += (*i)->trans.size();
|
||||||
if (flags & DFA_CONTROL_TRANS_HIGH) {
|
if (flags & DFA_CONTROL_TRANS_HIGH) {
|
||||||
size_t range = 0;
|
size_t range = 0;
|
||||||
if ((*i)->cases.cases.size())
|
if ((*i)->trans.size())
|
||||||
range =
|
range =
|
||||||
(*i)->cases.cases.rbegin()->first -
|
(*i)->trans.rbegin()->first -
|
||||||
(*i)->cases.begin()->first;
|
(*i)->trans.begin()->first;
|
||||||
size_t ord = ((256 - (*i)->cases.cases.size()) << 8) | (256 - range);
|
size_t ord = ((256 - (*i)->trans.size()) << 8) | (256 - range);
|
||||||
/* reverse sort by entry count, most entries first */
|
/* reverse sort by entry count, most entries first */
|
||||||
order.insert(make_pair(ord, *i));
|
order.insert(make_pair(ord, *i));
|
||||||
}
|
}
|
||||||
@ -154,14 +154,14 @@ TransitionTable::TransitionTable(DFA &dfa, map<uchar, uchar> &eq,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does <cases> fit into position <base> of the transition table?
|
* Does <trans> fit into position <base> of the transition table?
|
||||||
*/
|
*/
|
||||||
bool TransitionTable::fits_in(vector<pair<size_t, size_t> > &free_list
|
bool TransitionTable::fits_in(vector<pair<size_t, size_t> > &free_list
|
||||||
__attribute__ ((unused)), size_t pos,
|
__attribute__ ((unused)), size_t pos,
|
||||||
Cases &cases)
|
StateTrans &trans)
|
||||||
{
|
{
|
||||||
size_t c, base = pos - cases.begin()->first;
|
size_t c, base = pos - trans.begin()->first;
|
||||||
for (Cases::iterator i = cases.begin(); i != cases.end(); i++) {
|
for (StateTrans::iterator i = trans.begin(); i != trans.end(); i++) {
|
||||||
c = base + i->first;
|
c = base + i->first;
|
||||||
/* if it overflows the next_check array it fits in as we will
|
/* if it overflows the next_check array it fits in as we will
|
||||||
* resize */
|
* resize */
|
||||||
@ -184,14 +184,14 @@ void TransitionTable::insert_state(vector<pair<size_t, size_t> > &free_list,
|
|||||||
size_t base = 0;
|
size_t base = 0;
|
||||||
int resize;
|
int resize;
|
||||||
|
|
||||||
Cases &cases = from->cases;
|
StateTrans &trans = from->trans;
|
||||||
size_t c = cases.begin()->first;
|
size_t c = trans.begin()->first;
|
||||||
size_t prev = 0;
|
size_t prev = 0;
|
||||||
size_t x = first_free;
|
size_t x = first_free;
|
||||||
|
|
||||||
if (cases.otherwise)
|
if (from->otherwise)
|
||||||
default_state = cases.otherwise;
|
default_state = from->otherwise;
|
||||||
if (cases.cases.empty())
|
if (trans.empty())
|
||||||
goto do_insert;
|
goto do_insert;
|
||||||
|
|
||||||
repeat:
|
repeat:
|
||||||
@ -203,16 +203,16 @@ repeat:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* try inserting until we succeed. */
|
/* try inserting until we succeed. */
|
||||||
while (x && !fits_in(free_list, x, cases)) {
|
while (x && !fits_in(free_list, x, trans)) {
|
||||||
prev = x;
|
prev = x;
|
||||||
x = free_list[x].second;
|
x = free_list[x].second;
|
||||||
}
|
}
|
||||||
if (!x) {
|
if (!x) {
|
||||||
resize = 256 - cases.begin()->first;
|
resize = 256 - trans.begin()->first;
|
||||||
x = free_list.size();
|
x = free_list.size();
|
||||||
/* set prev to last free */
|
/* set prev to last free */
|
||||||
} else if (x + 255 - cases.begin()->first >= next_check.size()) {
|
} else if (x + 255 - trans.begin()->first >= next_check.size()) {
|
||||||
resize = (255 - cases.begin()->first - (next_check.size() - 1 - x));
|
resize = (255 - trans.begin()->first - (next_check.size() - 1 - x));
|
||||||
for (size_t y = x; y; y = free_list[y].second)
|
for (size_t y = x; y; y = free_list[y].second)
|
||||||
prev = y;
|
prev = y;
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ repeat:
|
|||||||
}
|
}
|
||||||
|
|
||||||
base = x - c;
|
base = x - c;
|
||||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
for (StateTrans::iterator j = trans.begin(); j != trans.end(); j++) {
|
||||||
next_check[base + j->first] = make_pair(j->second, from);
|
next_check[base + j->first] = make_pair(j->second, from);
|
||||||
size_t prev = free_list[base + j->first].first;
|
size_t prev = free_list[base + j->first].first;
|
||||||
size_t next = free_list[base + j->first].second;
|
size_t next = free_list[base + j->first].second;
|
||||||
|
@ -38,7 +38,7 @@ class TransitionTable {
|
|||||||
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
void init_free_list(vector<pair<size_t, size_t> > &free_list,
|
||||||
size_t prev, size_t start);
|
size_t prev, size_t start);
|
||||||
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
bool fits_in(vector<pair<size_t, size_t> > &free_list, size_t base,
|
||||||
Cases &cases);
|
StateTrans &cases);
|
||||||
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
void insert_state(vector<pair<size_t, size_t> > &free_list,
|
||||||
State *state, DFA &dfa);
|
State *state, DFA &dfa);
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ void DFA::update_state_transitions(NodeMap &nodemap, list<State *> &work_queue,
|
|||||||
|
|
||||||
/* check the default transition first */
|
/* check the default transition first */
|
||||||
if (cases.otherwise)
|
if (cases.otherwise)
|
||||||
state->cases.otherwise = find_target_state(nodemap, work_queue,
|
state->otherwise = find_target_state(nodemap, work_queue,
|
||||||
cases.otherwise,
|
cases.otherwise,
|
||||||
stats);;
|
stats);;
|
||||||
|
|
||||||
@ -114,11 +114,11 @@ void DFA::update_state_transitions(NodeMap &nodemap, list<State *> &work_queue,
|
|||||||
State *target;
|
State *target;
|
||||||
target = find_target_state(nodemap, work_queue, j->second, stats);
|
target = find_target_state(nodemap, work_queue, j->second, stats);
|
||||||
|
|
||||||
/* Don't insert transition that the default transition
|
/* Don't insert transition that the otherwise transition
|
||||||
* already covers
|
* already covers
|
||||||
*/
|
*/
|
||||||
if (target != state->cases.otherwise)
|
if (target != state->otherwise)
|
||||||
state->cases.cases[j->first] = target;
|
state->trans[j->first] = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,11 +254,11 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
|||||||
work_queue.pop_front();
|
work_queue.pop_front();
|
||||||
reachable.insert(from);
|
reachable.insert(from);
|
||||||
|
|
||||||
if (from->cases.otherwise &&
|
if (from->otherwise &&
|
||||||
(reachable.find(from->cases.otherwise) == reachable.end()))
|
(reachable.find(from->otherwise) == reachable.end()))
|
||||||
work_queue.push_back(from->cases.otherwise);
|
work_queue.push_back(from->otherwise);
|
||||||
|
|
||||||
for (Cases::iterator j = from->cases.begin(); j != from->cases.end(); j++) {
|
for (StateTrans::iterator j = from->trans.begin(); j != from->trans.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);
|
||||||
}
|
}
|
||||||
@ -301,22 +301,22 @@ void DFA::remove_unreachable(dfaflags_t flags)
|
|||||||
/* test if two states have the same transitions under partition_map */
|
/* test if two states have the same transitions under partition_map */
|
||||||
bool DFA::same_mappings(State *s1, State *s2)
|
bool DFA::same_mappings(State *s1, State *s2)
|
||||||
{
|
{
|
||||||
if (s1->cases.otherwise && s1->cases.otherwise != nonmatching) {
|
if (s1->otherwise && s1->otherwise != nonmatching) {
|
||||||
if (!s2->cases.otherwise || s2->cases.otherwise == nonmatching)
|
if (!s2->otherwise || s2->otherwise == nonmatching)
|
||||||
return false;
|
return false;
|
||||||
Partition *p1 = s1->cases.otherwise->partition;
|
Partition *p1 = s1->otherwise->partition;
|
||||||
Partition *p2 = s2->cases.otherwise->partition;
|
Partition *p2 = s2->otherwise->partition;
|
||||||
if (p1 != p2)
|
if (p1 != p2)
|
||||||
return false;
|
return false;
|
||||||
} else if (s2->cases.otherwise && s2->cases.otherwise != nonmatching) {
|
} else if (s2->otherwise && s2->otherwise != nonmatching) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s1->cases.cases.size() != s2->cases.cases.size())
|
if (s1->trans.size() != s2->trans.size())
|
||||||
return false;
|
return false;
|
||||||
for (Cases::iterator j1 = s1->cases.begin(); j1 != s1->cases.end(); j1++) {
|
for (StateTrans::iterator j1 = s1->trans.begin(); j1 != s1->trans.end(); j1++) {
|
||||||
Cases::iterator j2 = s2->cases.cases.find(j1->first);
|
StateTrans::iterator j2 = s2->trans.find(j1->first);
|
||||||
if (j2 == s2->cases.end())
|
if (j2 == s2->trans.end())
|
||||||
return false;
|
return false;
|
||||||
Partition *p1 = j1->second->partition;
|
Partition *p1 = j1->second->partition;
|
||||||
Partition *p2 = j2->second->partition;
|
Partition *p2 = j2->second->partition;
|
||||||
@ -330,7 +330,7 @@ bool DFA::same_mappings(State *s1, State *s2)
|
|||||||
/* Do simple djb2 hashing against a States transition cases
|
/* Do simple djb2 hashing against a States transition cases
|
||||||
* this provides a rough initial guess at state equivalence as if a state
|
* this provides a rough initial guess at state equivalence as if a state
|
||||||
* has a different number of transitions or has transitions on different
|
* has a different number of transitions or has transitions on different
|
||||||
* cases they will never be equivalent.
|
* trans they will never be equivalent.
|
||||||
* Note: this only hashes based off of the alphabet (not destination)
|
* Note: this only hashes based off of the alphabet (not destination)
|
||||||
* as different destinations could end up being equiv
|
* as different destinations could end up being equiv
|
||||||
*/
|
*/
|
||||||
@ -338,19 +338,19 @@ 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 (StateTrans::iterator j = s->trans.begin(); j != s->trans.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->trans.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->cases.otherwise && s->cases.otherwise != nonmatching) {
|
if (s->otherwise && s->otherwise != nonmatching) {
|
||||||
hash = ((hash << 5) + hash) + 5381;
|
hash = ((hash << 5) + hash) + 5381;
|
||||||
State *k = s->cases.otherwise;
|
State *k = s->otherwise;
|
||||||
hash = ((hash << 5) + hash) + k->cases.cases.size();
|
hash = ((hash << 5) + hash) + k->trans.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = (hash << 8) | s->cases.cases.size();
|
hash = (hash << 8) | s->trans.size();
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,11 +487,11 @@ void DFA::minimize(dfaflags_t flags)
|
|||||||
cerr << *rep << " : ";
|
cerr << *rep << " : ";
|
||||||
|
|
||||||
/* update representative state's transitions */
|
/* update representative state's transitions */
|
||||||
if (rep->cases.otherwise) {
|
if (rep->otherwise) {
|
||||||
Partition *partition = rep->cases.otherwise->partition;
|
Partition *partition = rep->otherwise->partition;
|
||||||
rep->cases.otherwise = *partition->begin();
|
rep->otherwise = *partition->begin();
|
||||||
}
|
}
|
||||||
for (Cases::iterator c = rep->cases.begin(); c != rep->cases.end(); c++) {
|
for (StateTrans::iterator c = rep->trans.begin(); c != rep->trans.end(); c++) {
|
||||||
Partition *partition = c->second->partition;
|
Partition *partition = c->second->partition;
|
||||||
c->second = *partition->begin();
|
c->second = *partition->begin();
|
||||||
}
|
}
|
||||||
@ -577,10 +577,10 @@ void DFA::dump(ostream & os)
|
|||||||
os << "\n";
|
os << "\n";
|
||||||
|
|
||||||
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)->otherwise)
|
||||||
os << **i << " -> " << (*i)->cases.otherwise << "\n";
|
os << **i << " -> " << (*i)->otherwise << "\n";
|
||||||
for (Cases::iterator j = (*i)->cases.begin();
|
for (StateTrans::iterator j = (*i)->trans.begin();
|
||||||
j != (*i)->cases.end(); j++) {
|
j != (*i)->trans.end(); j++) {
|
||||||
os << **i << " -> " << j->second << ": "
|
os << **i << " -> " << j->second << ": "
|
||||||
<< j->first << "\n";
|
<< j->first << "\n";
|
||||||
}
|
}
|
||||||
@ -611,10 +611,9 @@ void DFA::dump_dot_graph(ostream & os)
|
|||||||
os << "\t]" << "\n";
|
os << "\t]" << "\n";
|
||||||
}
|
}
|
||||||
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
for (Partition::iterator i = states.begin(); i != states.end(); i++) {
|
||||||
Cases &cases = (*i)->cases;
|
|
||||||
Chars excluded;
|
Chars excluded;
|
||||||
|
|
||||||
for (Cases::iterator j = cases.begin(); j != cases.end(); j++) {
|
for (StateTrans::iterator j = (*i)->trans.begin(); j != (*i)->trans.end(); j++) {
|
||||||
if (j->second == nonmatching)
|
if (j->second == nonmatching)
|
||||||
excluded.insert(j->first);
|
excluded.insert(j->first);
|
||||||
else {
|
else {
|
||||||
@ -624,8 +623,8 @@ void DFA::dump_dot_graph(ostream & os)
|
|||||||
os << "\t]" << "\n";
|
os << "\t]" << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cases.otherwise && cases.otherwise != nonmatching) {
|
if ((*i)->otherwise && (*i)->otherwise != nonmatching) {
|
||||||
os << "\t\"" << **i << "\" -> \"" << *cases.otherwise
|
os << "\t\"" << **i << "\" -> \"" << *(*i)->otherwise
|
||||||
<< "\" [" << "\n";
|
<< "\" [" << "\n";
|
||||||
if (!excluded.empty()) {
|
if (!excluded.empty()) {
|
||||||
os << "\t\tlabel=\"[^";
|
os << "\t\tlabel=\"[^";
|
||||||
@ -651,11 +650,9 @@ map<uchar, uchar> DFA::equivalence_classes(dfaflags_t flags)
|
|||||||
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;
|
|
||||||
|
|
||||||
/* 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 (StateTrans::iterator j = (*i)->trans.begin(); j != (*i)->trans.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();
|
||||||
@ -742,10 +739,9 @@ void DFA::apply_equivalence_classes(map<uchar, uchar> &eq)
|
|||||||
*/
|
*/
|
||||||
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)->trans);
|
||||||
for (Cases::iterator j = tmp.begin(); j != tmp.end(); j++)
|
for (StateTrans::iterator j = tmp.begin(); j != tmp.end(); j++)
|
||||||
(*i)->cases.cases.
|
(*i)->trans.insert(make_pair(eq[j->first], j->second));
|
||||||
insert(make_pair(eq[j->first], j->second));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,25 +33,8 @@
|
|||||||
#include "expr-tree.h"
|
#include "expr-tree.h"
|
||||||
|
|
||||||
class State;
|
class State;
|
||||||
/**
|
|
||||||
* State cases are identical to NodesCases except they map to State *
|
|
||||||
* instead of NodeSet.
|
|
||||||
* Out-edges from a state to another: we store the follow State
|
|
||||||
* for each input character that is not a default match in cases and
|
|
||||||
* default matches in otherwise as well as in all matching explicit cases
|
|
||||||
* This avoids enumerating all the explicit tranitions for default matches.
|
|
||||||
*/
|
|
||||||
typedef struct Cases {
|
|
||||||
typedef map<uchar, State *>::iterator iterator;
|
|
||||||
iterator begin() { return cases.begin(); }
|
|
||||||
iterator end() { return cases.end(); }
|
|
||||||
|
|
||||||
Cases(): otherwise(0) { }
|
|
||||||
|
|
||||||
map<uchar, State *> cases;
|
|
||||||
State *otherwise;
|
|
||||||
} Cases;
|
|
||||||
|
|
||||||
|
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);
|
uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
|
||||||
@ -63,7 +46,8 @@ uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
|
|||||||
* the start state is setup to have label == 1
|
* the start state is setup to have label == 1
|
||||||
* audit: the audit permission mask for the state
|
* audit: the audit permission mask for the state
|
||||||
* accept: the accept permissions for the state
|
* accept: the accept permissions for the state
|
||||||
* cases: set of transitions from this state
|
* trans: set of transitions from this state
|
||||||
|
* otherwise: the default state for transitions not in @trans
|
||||||
* parition: Is a temporary work variable used during dfa minimization.
|
* parition: Is a temporary work variable used during dfa minimization.
|
||||||
* it can be replaced with a map, but that is slower and uses more
|
* it can be replaced with a map, but that is slower and uses more
|
||||||
* memory.
|
* memory.
|
||||||
@ -72,10 +56,10 @@ 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), trans(), otherwise(NULL), nodes(NULL) { };
|
||||||
State(int l): label(l), audit(0), accept(0), cases(), nodes(NULL) { };
|
State(int l): label(l), audit(0), accept(0), trans(), otherwise(NULL), 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), trans(), otherwise(NULL), nodes(n)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
@ -89,7 +73,8 @@ public:
|
|||||||
|
|
||||||
int label;
|
int label;
|
||||||
uint32_t audit, accept;
|
uint32_t audit, accept;
|
||||||
Cases cases;
|
StateTrans trans;
|
||||||
|
State *otherwise;
|
||||||
union {
|
union {
|
||||||
Partition *partition;
|
Partition *partition;
|
||||||
NodeSet *nodes;
|
NodeSet *nodes;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user