diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index 1d56b3cb0..b250e1013 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -97,11 +97,11 @@ bool aare_rules::add_rule_vec(int deny, uint32_t perms, uint32_t audit, */ exact_match = 1; for (depth_first_traversal i(tree); i && exact_match; i++) { - if (dynamic_cast(*i) || - dynamic_cast(*i) || - dynamic_cast(*i) || - dynamic_cast(*i) || - dynamic_cast(*i)) + if ((*i)->is_type(NODE_TYPE_STAR) || + (*i)->is_type(NODE_TYPE_PLUS) || + (*i)->is_type(NODE_TYPE_ANYCHAR) || + (*i)->is_type(NODE_TYPE_CHARSET) || + (*i)->is_type(NODE_TYPE_NOTCHARSET)) exact_match = 0; } diff --git a/parser/libapparmor_re/expr-tree.cc b/parser/libapparmor_re/expr-tree.cc index 28aa35000..7dc18b041 100644 --- a/parser/libapparmor_re/expr-tree.cc +++ b/parser/libapparmor_re/expr-tree.cc @@ -210,7 +210,7 @@ int TwoChildNode::normalize_eps(int dir) // Test for E | (E | E) and E . (E . E) which will // result in an infinite loop Node *c = child[!dir]; - if (dynamic_cast(c) && + if (c->is_type(NODE_TYPE_TWOCHILD) && &epsnode == c->child[dir] && &epsnode == c->child[!dir]) { c->release(); @@ -229,7 +229,7 @@ void CatNode::normalize(int dir) for (;;) { if (normalize_eps(dir)) { continue; - } else if (dynamic_cast(child[dir])) { + } else if (child[dir]->is_type(NODE_TYPE_CAT)) { // (ab)c -> a(bc) rotate_node(this, dir); } else { @@ -248,11 +248,11 @@ void AltNode::normalize(int dir) for (;;) { if (normalize_eps(dir)) { continue; - } else if (dynamic_cast(child[dir])) { + } else if (child[dir]->is_type(NODE_TYPE_ALT)) { // (a | b) | c -> a | (b | c) rotate_node(this, dir); - } else if (dynamic_cast(child[dir]) && - dynamic_cast(child[!dir])) { + } else if (child[dir]->is_type(NODE_TYPE_CHARSET) && + child[!dir]->is_type(NODE_TYPE_CHAR)) { // [a] | b -> b | [a] Node *c = child[dir]; child[dir] = child[!dir]; @@ -344,7 +344,7 @@ static Node *alt_to_charsets(Node *t, int dir) static Node *basic_alt_factor(Node *t, int dir) { - if (!dynamic_cast(t)) + if (!t->is_type(NODE_TYPE_ALT)) return t; if (t->child[dir]->eq(t->child[!dir])) { @@ -355,8 +355,8 @@ static Node *basic_alt_factor(Node *t, int dir) return tmp; } // (ab) | (ac) -> a(b|c) - if (dynamic_cast(t->child[dir]) && - dynamic_cast(t->child[!dir]) && + if (t->child[dir]->is_type(NODE_TYPE_CAT) && + t->child[!dir]->is_type(NODE_TYPE_CAT) && t->child[dir]->child[dir]->eq(t->child[!dir]->child[dir])) { // (ab) | (ac) -> a(b|c) Node *left = t->child[dir]; @@ -369,7 +369,7 @@ static Node *basic_alt_factor(Node *t, int dir) return left; } // a | (ab) -> a (E | b) -> a (b | E) - if (dynamic_cast(t->child[!dir]) && + if (t->child[!dir]->is_type(NODE_TYPE_CAT) && t->child[dir]->eq(t->child[!dir]->child[dir])) { Node *c = t->child[!dir]; t->child[dir]->release(); @@ -379,7 +379,7 @@ static Node *basic_alt_factor(Node *t, int dir) return c; } // ab | (a) -> a (b | E) - if (dynamic_cast(t->child[dir]) && + if (t->child[dir]->is_type(NODE_TYPE_CAT) && t->child[dir]->child[dir]->eq(t->child[!dir])) { Node *c = t->child[dir]; t->child[!dir]->release(); @@ -394,7 +394,7 @@ static Node *basic_alt_factor(Node *t, int dir) static Node *basic_simplify(Node *t, int dir) { - if (dynamic_cast(t) && &epsnode == t->child[!dir]) { + if (t->is_type(NODE_TYPE_CAT) && &epsnode == t->child[!dir]) { // aE -> a Node *tmp = t->child[dir]; t->child[dir] = NULL; @@ -419,7 +419,7 @@ static Node *basic_simplify(Node *t, int dir) */ Node *simplify_tree_base(Node *t, int dir, bool &mod) { - if (dynamic_cast(t)) + if (t->is_type(NODE_TYPE_IMPORTANT)) return t; for (int i = 0; i < 2; i++) { @@ -442,15 +442,15 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod) } /* all tests after this must meet 2 alt node condition */ - if (!dynamic_cast(t) || - !dynamic_cast(t->child[!dir])) + if (!t->is_type(NODE_TYPE_ALT) || + !t->child[!dir]->is_type(NODE_TYPE_ALT)) break; // a | (a | b) -> (a | b) // a | (b | (c | a)) -> (b | (c | a)) Node *p = t; Node *i = t->child[!dir]; - for (; dynamic_cast(i); p = i, i = i->child[!dir]) { + for (; i->is_type(NODE_TYPE_ALT); p = i, i = i->child[!dir]) { if (t->child[dir]->eq(i->child[dir])) { Node *tmp = t->child[!dir]; t->child[!dir] = NULL; @@ -475,19 +475,19 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod) int count = 0; Node *subject = t->child[dir]; Node *a = subject; - if (dynamic_cast(subject)) + if (subject->is_type(NODE_TYPE_CAT)) a = subject->child[dir]; for (pp = p = t, i = t->child[!dir]; - dynamic_cast(i);) { - if ((dynamic_cast(i->child[dir]) && + i->is_type(NODE_TYPE_ALT);) { + if ((i->child[dir]->is_type(NODE_TYPE_CAT) && a->eq(i->child[dir]->child[dir])) || (a->eq(i->child[dir]))) { // extract matching alt node p->child[!dir] = i->child[!dir]; i->child[!dir] = subject; subject = basic_simplify(i, dir); - if (dynamic_cast(subject)) + if (subject->is_type(NODE_TYPE_CAT)) a = subject->child[dir]; else a = subject; @@ -502,7 +502,7 @@ Node *simplify_tree_base(Node *t, int dir, bool &mod) } // last altnode in chain check other dir as well - if ((dynamic_cast(i) && + if ((i->is_type(NODE_TYPE_CAT) && a->eq(i->child[dir])) || (a->eq(i))) { count++; if (t == p) { @@ -528,7 +528,7 @@ int debug_tree(Node *t) { int nodes = 1; - if (!dynamic_cast(t)) { + if (!t->is_type(NODE_TYPE_IMPORTANT)) { if (t->child[0]) nodes += debug_tree(t->child[0]); if (t->child[1]) @@ -539,30 +539,30 @@ int debug_tree(Node *t) static void count_tree_nodes(Node *t, struct node_counts *counts) { - if (dynamic_cast(t)) { + if (t->is_type(NODE_TYPE_ALT)) { counts->alt++; count_tree_nodes(t->child[0], counts); count_tree_nodes(t->child[1], counts); - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_CAT)) { counts->cat++; count_tree_nodes(t->child[0], counts); count_tree_nodes(t->child[1], counts); - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_PLUS)) { counts->plus++; count_tree_nodes(t->child[0], counts); - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_STAR)) { counts->star++; count_tree_nodes(t->child[0], counts); - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_OPTIONAL)) { counts->optional++; count_tree_nodes(t->child[0], counts); - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_CHAR)) { counts->charnode++; - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_ANYCHAR)) { counts->any++; - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_CHARSET)) { counts->charset++; - } else if (dynamic_cast(t)) { + } else if (t->is_type(NODE_TYPE_NOTCHARSET)) { counts->notcharset++; } } @@ -635,7 +635,8 @@ Node *simplify_tree(Node *t, dfaflags_t flags) void flip_tree(Node *node) { for (depth_first_traversal i(node); i; i++) { - if (CatNode *cat = dynamic_cast(*i)) { + if ((*i)->is_type(NODE_TYPE_CAT)) { + CatNode *cat = static_cast(*i); swap(cat->child[0], cat->child[1]); } } diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h index 551dd0eeb..8ada4a4a7 100644 --- a/parser/libapparmor_re/expr-tree.h +++ b/parser/libapparmor_re/expr-tree.h @@ -222,16 +222,43 @@ typedef struct Cases { ostream &operator<<(ostream &os, Node &node); +#define NODE_TYPE_NODE 0 +#define NODE_TYPE_INNER (1 << 0) +#define NODE_TYPE_ONECHILD (1 << 1) +#define NODE_TYPE_TWOCHILD (1 << 2) +#define NODE_TYPE_LEAF (1 << 3) +#define NODE_TYPE_EPS (1 << 4) +#define NODE_TYPE_IMPORTANT (1 << 5) +#define NODE_TYPE_C (1 << 6) +#define NODE_TYPE_CHAR (1 << 7) +#define NODE_TYPE_CHARSET (1 << 8) +#define NODE_TYPE_NOTCHARSET (1 << 9) +#define NODE_TYPE_ANYCHAR (1 << 10) +#define NODE_TYPE_STAR (1 << 11) +#define NODE_TYPE_OPTIONAL (1 << 12) +#define NODE_TYPE_PLUS (1 << 13) +#define NODE_TYPE_CAT (1 << 14) +#define NODE_TYPE_ALT (1 << 15) +#define NODE_TYPE_SHARED (1 << 16) +#define NODE_TYPE_ACCEPT (1 << 17) +#define NODE_TYPE_MATCHFLAG (1 << 18) +#define NODE_TYPE_EXACTMATCHFLAG (1 << 19) +#define NODE_TYPE_DENYMATCHFLAG (1 << 20) + /* An abstract node in the syntax tree. */ class Node { public: - Node(): nullable(false), label(0) { child[0] = child[1] = 0; } - Node(Node *left): nullable(false), label(0) + Node(): nullable(false), type_flags(NODE_TYPE_NODE), label(0) + { + child[0] = child[1] = 0; + } + Node(Node *left): nullable(false), type_flags(NODE_TYPE_NODE), label(0) { child[0] = left; child[1] = 0; } - Node(Node *left, Node *right): nullable(false), label(0) + Node(Node *left, Node *right): nullable(false), + type_flags(NODE_TYPE_NODE), label(0) { child[0] = left; child[1] = right; @@ -302,6 +329,13 @@ public: NodeSet firstpos, lastpos, followpos; /* child 0 is left, child 1 is right */ Node *child[2]; + /* + * Bitmap that stores supported pointer casts for the Node, composed + * by the NODE_TYPE_* flags. This is used by is_type() as a substitute + * of costly dynamic_cast calls. + */ + unsigned type_flags; + bool is_type(unsigned type) { return type_flags & type; } unsigned int label; /* unique number for debug etc */ /** @@ -315,25 +349,34 @@ public: class InnerNode: public Node { public: - InnerNode(): Node() { }; - InnerNode(Node *left): Node(left) { }; - InnerNode(Node *left, Node *right): Node(left, right) { }; + InnerNode(): Node() { type_flags |= NODE_TYPE_INNER; }; + InnerNode(Node *left): Node(left) { type_flags |= NODE_TYPE_INNER; }; + InnerNode(Node *left, Node *right): Node(left, right) + { + type_flags |= NODE_TYPE_INNER; + }; }; class OneChildNode: public InnerNode { public: - OneChildNode(Node *left): InnerNode(left) { }; + OneChildNode(Node *left): InnerNode(left) + { + type_flags |= NODE_TYPE_ONECHILD; + }; }; class TwoChildNode: public InnerNode { public: - TwoChildNode(Node *left, Node *right): InnerNode(left, right) { }; + TwoChildNode(Node *left, Node *right): InnerNode(left, right) + { + type_flags |= NODE_TYPE_TWOCHILD; + }; virtual int normalize_eps(int dir); }; class LeafNode: public Node { public: - LeafNode(): Node() { }; + LeafNode(): Node() { type_flags |= NODE_TYPE_LEAF; }; virtual void normalize(int dir __attribute__((unused))) { return; } }; @@ -342,6 +385,7 @@ class EpsNode: public LeafNode { public: EpsNode(): LeafNode() { + type_flags |= NODE_TYPE_EPS; nullable = true; label = 0; } @@ -356,7 +400,7 @@ public: void compute_lastpos() { } int eq(Node *other) { - if (dynamic_cast(other)) + if (other->is_type(NODE_TYPE_EPS)) return 1; return 0; } @@ -373,7 +417,7 @@ public: */ class ImportantNode: public LeafNode { public: - ImportantNode(): LeafNode() { } + ImportantNode(): LeafNode() { type_flags |= NODE_TYPE_IMPORTANT; } void compute_firstpos() { firstpos.insert(this); } void compute_lastpos() { lastpos.insert(this); } virtual void follow(Cases &cases) = 0; @@ -386,7 +430,7 @@ public: */ class CNode: public ImportantNode { public: - CNode(): ImportantNode() { } + CNode(): ImportantNode() { type_flags |= NODE_TYPE_C; } int is_accept(void) { return false; } int is_postprocess(void) { return false; } }; @@ -394,7 +438,7 @@ public: /* Match one specific character (/c/). */ class CharNode: public CNode { public: - CharNode(transchar c): c(c) { } + CharNode(transchar c): c(c) { type_flags |= NODE_TYPE_CHAR; } void follow(Cases &cases) { NodeSet **x = &cases.cases[c]; @@ -408,8 +452,8 @@ public: } int eq(Node *other) { - CharNode *o = dynamic_cast(other); - if (o) { + if (other->is_type(NODE_TYPE_CHAR)) { + CharNode *o = static_cast(other); return c == o->c; } return 0; @@ -439,7 +483,10 @@ public: /* Match a set of characters (/[abc]/). */ class CharSetNode: public CNode { public: - CharSetNode(Chars &chars): chars(chars) { } + CharSetNode(Chars &chars): chars(chars) + { + type_flags |= NODE_TYPE_CHARSET; + } void follow(Cases &cases) { for (Chars::iterator i = chars.begin(); i != chars.end(); i++) { @@ -455,8 +502,11 @@ public: } int eq(Node *other) { - CharSetNode *o = dynamic_cast(other); - if (!o || chars.size() != o->chars.size()) + if (!other->is_type(NODE_TYPE_CHARSET)) + return 0; + + CharSetNode *o = static_cast(other); + if (chars.size() != o->chars.size()) return 0; for (Chars::iterator i = chars.begin(), j = o->chars.begin(); @@ -498,7 +548,10 @@ public: /* Match all except one character (/[^abc]/). */ class NotCharSetNode: public CNode { public: - NotCharSetNode(Chars &chars): chars(chars) { } + NotCharSetNode(Chars &chars): chars(chars) + { + type_flags |= NODE_TYPE_NOTCHARSET; + } void follow(Cases &cases) { if (!cases.otherwise) @@ -522,8 +575,11 @@ public: } int eq(Node *other) { - NotCharSetNode *o = dynamic_cast(other); - if (!o || chars.size() != o->chars.size()) + if (!other->is_type(NODE_TYPE_NOTCHARSET)) + return 0; + + NotCharSetNode *o = static_cast(other); + if (chars.size() != o->chars.size()) return 0; for (Chars::iterator i = chars.begin(), j = o->chars.begin(); @@ -565,7 +621,7 @@ public: /* Match any character (/./). */ class AnyCharNode: public CNode { public: - AnyCharNode() { } + AnyCharNode() { type_flags |= NODE_TYPE_ANYCHAR; } void follow(Cases &cases) { if (!cases.otherwise) @@ -579,7 +635,7 @@ public: } int eq(Node *other) { - if (dynamic_cast(other)) + if (other->is_type(NODE_TYPE_ANYCHAR)) return 1; return 0; } @@ -589,7 +645,11 @@ public: /* Match a node zero or more times. (This is a unary operator.) */ class StarNode: public OneChildNode { public: - StarNode(Node *left): OneChildNode(left) { nullable = true; } + StarNode(Node *left): OneChildNode(left) + { + type_flags |= NODE_TYPE_STAR; + nullable = true; + } void compute_firstpos() { firstpos = child[0]->firstpos; } void compute_lastpos() { lastpos = child[0]->lastpos; } void compute_followpos() @@ -601,7 +661,7 @@ public: } int eq(Node *other) { - if (dynamic_cast(other)) + if (other->is_type(NODE_TYPE_STAR)) return child[0]->eq(other->child[0]); return 0; } @@ -618,12 +678,16 @@ public: /* Match a node zero or one times. */ class OptionalNode: public OneChildNode { public: - OptionalNode(Node *left): OneChildNode(left) { nullable = true; } + OptionalNode(Node *left): OneChildNode(left) + { + type_flags |= NODE_TYPE_OPTIONAL; + nullable = true; + } void compute_firstpos() { firstpos = child[0]->firstpos; } void compute_lastpos() { lastpos = child[0]->lastpos; } int eq(Node *other) { - if (dynamic_cast(other)) + if (other->is_type(NODE_TYPE_OPTIONAL)) return child[0]->eq(other->child[0]); return 0; } @@ -638,7 +702,9 @@ public: /* Match a node one or more times. (This is a unary operator.) */ class PlusNode: public OneChildNode { public: - PlusNode(Node *left): OneChildNode(left) { + PlusNode(Node *left): OneChildNode(left) + { + type_flags |= NODE_TYPE_PLUS; } void compute_nullable() { nullable = child[0]->nullable; } void compute_firstpos() { firstpos = child[0]->firstpos; } @@ -651,7 +717,7 @@ public: } } int eq(Node *other) { - if (dynamic_cast(other)) + if (other->is_type(NODE_TYPE_PLUS)) return child[0]->eq(other->child[0]); return 0; } @@ -667,7 +733,10 @@ public: /* Match a pair of consecutive nodes. */ class CatNode: public TwoChildNode { public: - CatNode(Node *left, Node *right): TwoChildNode(left, right) { } + CatNode(Node *left, Node *right): TwoChildNode(left, right) + { + type_flags |= NODE_TYPE_CAT; + } void compute_nullable() { nullable = child[0]->nullable && child[1]->nullable; @@ -695,7 +764,7 @@ public: } int eq(Node *other) { - if (dynamic_cast(other)) { + if (other->is_type(NODE_TYPE_CAT)) { if (!child[0]->eq(other->child[0])) return 0; return child[1]->eq(other->child[1]); @@ -730,7 +799,10 @@ public: /* Match one of two alternative nodes. */ class AltNode: public TwoChildNode { public: - AltNode(Node *left, Node *right): TwoChildNode(left, right) { } + AltNode(Node *left, Node *right): TwoChildNode(left, right) + { + type_flags |= NODE_TYPE_ALT; + } void compute_nullable() { nullable = child[0]->nullable || child[1]->nullable; @@ -745,7 +817,7 @@ public: } int eq(Node *other) { - if (dynamic_cast(other)) { + if (other->is_type(NODE_TYPE_ALT)) { if (!child[0]->eq(other->child[0])) return 0; return child[1]->eq(other->child[1]); @@ -780,7 +852,10 @@ public: class SharedNode: public ImportantNode { public: - SharedNode() { } + SharedNode() + { + type_flags |= NODE_TYPE_SHARED; + } void release(void) { /* don't delete SharedNodes via release as they are shared, and @@ -803,14 +878,17 @@ public: */ class AcceptNode: public SharedNode { public: - AcceptNode() { } + AcceptNode() { type_flags |= NODE_TYPE_ACCEPT; } int is_accept(void) { return true; } int is_postprocess(void) { return false; } }; class MatchFlag: public AcceptNode { public: - MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { } + MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) + { + type_flags |= NODE_TYPE_MATCHFLAG; + } ostream &dump(ostream &os) { return os << "< 0x" << hex << flag << '>'; } uint32_t flag; @@ -819,12 +897,18 @@ public: class ExactMatchFlag: public MatchFlag { public: - ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {} + ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) + { + type_flags |= NODE_TYPE_EXACTMATCHFLAG; + } }; class DenyMatchFlag: public MatchFlag { public: - DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {} + DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) + { + type_flags |= NODE_TYPE_DENYMATCHFLAG; + } }; /* Traverse the syntax tree depth-first in an iterator-like manner. */ @@ -833,7 +917,7 @@ class depth_first_traversal { void push_left(Node *node) { pos.push(node); - while (dynamic_cast(node)) { + while (node->is_type(NODE_TYPE_INNER)) { pos.push(node->child[0]); node = node->child[0]; } diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 9cea4c3fc..e1ef1803b 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -1352,17 +1352,18 @@ int accept_perms(NodeSet *state, perms_t &perms, bool filedfa) return error; for (NodeSet::iterator i = state->begin(); i != state->end(); i++) { - MatchFlag *match; - if (!(match = dynamic_cast(*i))) + if (!(*i)->is_type(NODE_TYPE_MATCHFLAG)) continue; - if (dynamic_cast(match)) { + + MatchFlag *match = static_cast(*i); + if (match->is_type(NODE_TYPE_EXACTMATCHFLAG)) { /* exact match only ever happens with x */ if (filedfa && !is_merged_x_consistent(exact_match_allow, match->flag)) error = 1;; exact_match_allow |= match->flag; exact_audit |= match->audit; - } else if (dynamic_cast(match)) { + } else if (match->is_type(NODE_TYPE_DENYMATCHFLAG)) { perms.deny |= match->flag; perms.quiet |= match->audit; } else {