From dce395e7adbc47221e4700f9f19b81842d2f3b16 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 8 Jan 2010 04:30:56 -0800 Subject: [PATCH] Add basic controls for dfa optimization --- parser/libapparmor_re/apparmor_re.h | 8 ++++-- parser/libapparmor_re/regexp.y | 34 ++++++++++++++-------- parser/parser_main.c | 44 ++++++++++++++++++++++++++++- parser/parser_regex.c | 4 +-- 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/parser/libapparmor_re/apparmor_re.h b/parser/libapparmor_re/apparmor_re.h index ad8d0a998..caa7d1d85 100644 --- a/parser/libapparmor_re/apparmor_re.h +++ b/parser/libapparmor_re/apparmor_re.h @@ -12,6 +12,11 @@ #define APPARMOR_RE_H typedef enum dfaflags { + DFA_CONTROL_EQUIV = 1 << 0, + DFA_CONTROL_NO_TREE_NORMAL = 1 << 1, + DFA_CONTROL_NO_TREE_SIMPLE = 1 << 2, + DFA_CONTROL_TREE_LEFT = 1 << 3, + DFA_DUMP_TREE_STATS = 1 << 8, DFA_DUMP_TREE = 1 << 9, DFA_DUMP_SIMPLE_TREE = 1 << 10, @@ -40,8 +45,7 @@ int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny, uint32_t perms, uint32_t audit); int aare_add_rule_vec(aare_ruleset_t *rules, int deny, uint32_t perms, uint32_t audit, int count, char **rulev); -void *aare_create_dfa(aare_ruleset_t *rules, int equiv_classes, size_t *size, - dfaflags_t flags); +void *aare_create_dfa(aare_ruleset_t *rules, size_t *size, dfaflags_t flags); void aare_reset_matchflags(void); #ifdef __cplusplus diff --git a/parser/libapparmor_re/regexp.y b/parser/libapparmor_re/regexp.y index 884d19f83..743430294 100644 --- a/parser/libapparmor_re/regexp.y +++ b/parser/libapparmor_re/regexp.y @@ -858,21 +858,29 @@ Node *simplify_tree(Node *t, dfaflags_t flags) } do { update = false; - //do right normalize first as this reduces the number + //default to right normalize first as this reduces the number //of trailing nodes which might follow an internal * //or **, which is where state explosion can happen //eg. in one test this makes the difference between // the dfa having about 7 thousands states, // and it having about 1.25 million states - for (int dir = 1; dir >= 0 ; dir--) { + int dir = 1; + if (flags & DFA_CONTROL_TREE_LEFT) + dir = 0; + for (int count = 0; count < 2; count++) { bool modified; do { modified = false; - normalize_tree(t, dir); + if (!(flags & DFA_CONTROL_NO_TREE_NORMAL)) + normalize_tree(t, dir); t = simplify_tree_base(t, dir, modified); if (modified) update = true; } while (modified); + if (flags & DFA_CONTROL_TREE_LEFT) + dir++; + else + dir--; } } while(update); if (flags & DFA_DUMP_TREE_STATS) { @@ -2308,8 +2316,7 @@ extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny, * returns: buffer contain dfa tables, @size set to the size of the tables * else NULL on failure */ -extern "C" void *aare_create_dfa(aare_ruleset_t *rules, int equiv_classes, - size_t *size, dfaflags_t flags) +extern "C" void *aare_create_dfa(aare_ruleset_t *rules, size_t *size, dfaflags_t flags) { char *buffer = NULL; @@ -2320,12 +2327,14 @@ extern "C" void *aare_create_dfa(aare_ruleset_t *rules, int equiv_classes, cerr << "\n\n"; } - rules->root = simplify_tree(rules->root, flags); + if (!(flags & DFA_CONTROL_NO_TREE_SIMPLE)) { + rules->root = simplify_tree(rules->root, flags); - if (flags & DFA_DUMP_SIMPLE_TREE) { - cerr << "\nDFA: Simplified Expression Tree\n"; - rules->root->dump(cerr); - cerr << "\n\n"; + if (flags & DFA_DUMP_SIMPLE_TREE) { + cerr << "\nDFA: Simplified Expression Tree\n"; + rules->root->dump(cerr); + cerr << "\n\n"; + } } DFA dfa(rules->root, flags); @@ -2337,13 +2346,14 @@ extern "C" void *aare_create_dfa(aare_ruleset_t *rules, int equiv_classes, dfa.dump_dot_graph(cerr); map eq; - if (equiv_classes) { + if (flags & DFA_CONTROL_EQUIV) { eq = dfa.equivalence_classes(flags); dfa.apply_equivalence_classes(eq); - if (flags & DFA_DUMP_EQUIV) + if (flags & DFA_DUMP_EQUIV) { cerr << "\nDFA equivalence class\n"; dump_equivalence_classes(cerr, eq); + } } else if (flags & DFA_DUMP_EQUIV) cerr << "\nDFA did not generate an equivalence class\n"; diff --git a/parser/parser_main.c b/parser/parser_main.c index 3d0c275eb..c92d4e1ba 100644 --- a/parser/parser_main.c +++ b/parser/parser_main.c @@ -159,6 +159,7 @@ static void display_usage(char *command) "-V, --version Display version info and exit\n" "-d, --debug Debug apparmor definitions\n" "-D [n], --dump Dump internal info for debugging\n" + "-O [n], --Optimize Control dfa optimizations\n" "-h [command], --help Display this text or info about command\n" ,command); } @@ -187,6 +188,24 @@ static void display_dump(char *command) ,command); } +static void display_optimize(char *command) +{ + display_version(); + printf("\n%s: -O [Option]\n\n" + "Options:\n" + "--------\n" + "0 no optimizations\n" + "equiv use equivalent classes\n" + "no-equiv don't use equivalent classes\n" + "expr-normalize do expr normalization\n" + "expr-simplify do expr tree simplification\n" + "no-expr-normalize don't do expr normalization\n" + "no-expr-simplify don't do expr tree simplification\n" + "expr-left-simplify do left simplification first\n" + "expr-right-simplify do right simplification first\n" + ,command); +} + void pwarn(char *fmt, ...) { va_list arg; @@ -216,7 +235,7 @@ static int process_args(int argc, char *argv[]) int count = 0; option = OPTION_ADD; - while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWk", long_options, &o)) != -1) + while ((c = getopt_long(argc, argv, "adf:h::rRVvI:b:BCD:NSm:qQn:XKTWkO:", long_options, &o)) != -1) { switch (c) { case 0: @@ -319,6 +338,29 @@ static int process_args(int argc, char *argv[]) exit(1); } break; + case 'O': + skip_cache = 1; + if (strcmp(optarg, "0") == 0) { + dfaflags |= DFA_CONTROL_NO_TREE_NORMAL | + DFA_CONTROL_NO_TREE_SIMPLE; + } else if (strcmp(optarg, "equiv") == 0) { + dfaflags |= DFA_CONTROL_EQUIV; + } else if (strcmp(optarg, "no-equiv") == 0) { + dfaflags &= ~DFA_CONTROL_EQUIV; + } else if (strcmp(optarg, "expr-normalize") == 0) { + dfaflags &= ~DFA_CONTROL_NO_TREE_NORMAL; + } else if (strcmp(optarg, "no-expr-normalize") == 0) { + dfaflags |= DFA_CONTROL_NO_TREE_NORMAL; + } else if (strcmp(optarg, "expr-simplify") == 0) { + dfaflags &= ~DFA_CONTROL_NO_TREE_SIMPLE; + } else if (strcmp(optarg, "no-expr-simplify") == 0) { + dfaflags |= DFA_CONTROL_NO_TREE_SIMPLE; + } else if (strcmp(optarg, "expr-left-simplify") == 0) { + dfaflags |= DFA_CONTROL_TREE_LEFT; + } else if (strcmp(optarg, "expr-right-simplify") == 0) { + dfaflags &= ~DFA_CONTROL_TREE_LEFT; + } + break; case 'm': match_string = strdup(optarg); break; diff --git a/parser/parser_regex.c b/parser/parser_regex.c index 9f9708ae4..993204130 100644 --- a/parser/parser_regex.c +++ b/parser/parser_regex.c @@ -523,7 +523,7 @@ static int process_profile_name_xmatch(struct codomain *cod) aare_delete_ruleset(rule); return FALSE; } - cod->xmatch = aare_create_dfa(rule, 0, &cod->xmatch_size, + cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size, dfaflags); aare_delete_ruleset(rule); if (!cod->xmatch) @@ -667,7 +667,7 @@ int process_regex(struct codomain *cod) goto out; if (regex_type == AARE_DFA && cod->dfarule_count > 0) { - cod->dfa = aare_create_dfa(cod->dfarules, 0, &cod->dfa_size, + cod->dfa = aare_create_dfa(cod->dfarules, &cod->dfa_size, dfaflags); aare_delete_ruleset(cod->dfarules); cod->dfarules = NULL;