From 50452e114729cfcfb07945015e41f36430b4ab2f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 30 Dec 2024 01:27:21 -0800 Subject: [PATCH] parser: add a hfa dump that matches the renumbered chfa Construction of the chfa can reorder states from what the numbering given during the hfa constuctions because of reordering for better compression, dead state removal to ensure better packing etc. This however means the dfa dump is difficult (it is possible using multiple dumpes) to match up to the chfa that the kernel is using. Make this easier by making the dfa dump be able to take the emapping as input, and provide an option to dump the chfa equivalent hfa. Renumbered states will show up as {new <== {orig}} in the dump Eg. --D dfa-states {1} <== priority (allow/deny/prompt/audit/quiet) {5} 0 (0x 4/0//0/0/0) {1} perms: none 0x2 -> {5} 0 (0x 4/0//0/0/0) 0x4 -> {5} 0 (0x 4/0//0/0/0) \a 0x7 -> {5} 0 (0x 4/0//0/0/0) \t 0x9 -> {5} 0 (0x 4/0//0/0/0) \n 0xa -> {5} 0 (0x 4/0//0/0/0) \ 0x20 -> {5} 0 (0x 4/0//0/0/0) 4 0x34 -> {3} {3} perms: none 0x0 -> {6} {6} perms: none 1 0x31 -> {5} 0 (0x 4/0//0/0/0) -D dfa-compressed-states {1} <== priority (allow/deny/prompt/audit/quiet) {2 == {5}} 0 (0x 4/0//0/0/0) {1} perms: none 0x2 -> {2 == {5}} 0 (0x 4/0//0/0/0) 0x4 -> {2 == {5}} 0 (0x 4/0//0/0/0) \a 0x7 -> {2 == {5}} 0 (0x 4/0//0/0/0) \t 0x9 -> {2 == {5}} 0 (0x 4/0//0/0/0) \n 0xa -> {2 == {5}} 0 (0x 4/0//0/0/0) \ 0x20 -> {2 == {5}} 0 (0x 4/0//0/0/0) 4 0x34 -> {3} {3} perms: none 0x0 -> {4 == {6}} {4 == {6}} perms: none 1 0x31 -> {2 == {5}} 0 (0x 4/0//0/0/0) Signed-off-by: John Johansen --- parser/common_optarg.c | 1 + parser/libapparmor_re/aare_rules.cc | 12 +++++++----- parser/libapparmor_re/apparmor_re.h | 1 + parser/libapparmor_re/chfa.h | 2 +- parser/libapparmor_re/hfa.cc | 27 +++++++++++++++++++++------ parser/libapparmor_re/hfa.h | 4 +++- 6 files changed, 34 insertions(+), 13 deletions(-) diff --git a/parser/common_optarg.c b/parser/common_optarg.c index 5ddd25da2..a9dc13fdb 100644 --- a/parser/common_optarg.c +++ b/parser/common_optarg.c @@ -44,6 +44,7 @@ optflag_table_t dumpflag_table[] = { DUMP_DFA_PROGRESS | DUMP_DFA_STATS }, { 1, "dfa-stats", "Dump dfa creation stats", DUMP_DFA_STATS }, { 1, "dfa-states", "Dump final dfa state information", DUMP_DFA_STATES }, + { 1, "dfa-compressed-states", "Dump compressed dfa state information", DUMP_DFA_COMPTRESSED_STATES }, { 1, "dfa-states-initial", "Dump dfa state immediately after initial build", DUMP_DFA_STATES_INIT }, { 1, "dfa-states-post-filter", "Dump dfa state immediately after filtering deny", DUMP_DFA_STATES_POST_FILTER }, { 1, "dfa-states-post-minimize", "Dump dfa state immediately after initial build", DUMP_DFA_STATES_POST_MINIMIZE }, diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc index f6ce6832e..d5546dde4 100644 --- a/parser/libapparmor_re/aare_rules.cc +++ b/parser/libapparmor_re/aare_rules.cc @@ -259,7 +259,7 @@ CHFA *aare_rules::create_chfa(int *min_match_len, dfa.dump_uniq_perms("dfa"); if (opts.dump & DUMP_DFA_STATES_INIT) - dfa.dump(cerr); + dfa.dump(cerr, NULL); /* since we are building a chfa, use the info about * whether the chfa supports extended perms to help @@ -271,23 +271,23 @@ CHFA *aare_rules::create_chfa(int *min_match_len, ((opts.control & CONTROL_DFA_FILTER_DENY))) { dfa.apply_and_clear_deny(); if (opts.dump & DUMP_DFA_STATES_POST_FILTER) - dfa.dump(cerr); + dfa.dump(cerr, NULL); } if (opts.control & CONTROL_DFA_MINIMIZE) { dfa.minimize(opts); if (opts.dump & DUMP_DFA_MIN_UNIQ_PERMS) dfa.dump_uniq_perms("minimized dfa"); if (opts.dump & DUMP_DFA_STATES_POST_MINIMIZE) - dfa.dump(cerr); + dfa.dump(cerr, NULL); } if (opts.control & CONTROL_DFA_REMOVE_UNREACHABLE) { dfa.remove_unreachable(opts); if (opts.dump & DUMP_DFA_STATES_POST_UNREACHABLE) - dfa.dump(cerr); + dfa.dump(cerr, NULL); } if (opts.dump & DUMP_DFA_STATES) - dfa.dump(cerr); + dfa.dump(cerr, NULL); if (opts.dump & DUMP_DFA_GRAPH) dfa.dump_dot_graph(cerr); @@ -331,6 +331,8 @@ CHFA *aare_rules::create_chfa(int *min_match_len, chfa = new CHFA(dfa, eq, opts, extended_perms, prompt); if (opts.dump & DUMP_DFA_TRANS_TABLE) chfa->dump(cerr); + if (opts.dump & DUMP_DFA_COMPTRESSED_STATES) + dfa.dump(cerr, &chfa->num); } catch(int error) { return NULL; diff --git a/parser/libapparmor_re/apparmor_re.h b/parser/libapparmor_re/apparmor_re.h index 843400c48..edd29aafe 100644 --- a/parser/libapparmor_re/apparmor_re.h +++ b/parser/libapparmor_re/apparmor_re.h @@ -64,5 +64,6 @@ #define DUMP_DFA_STATES_POST_FILTER (1 << 26) #define DUMP_DFA_STATES_POST_MINIMIZE (1 << 27) #define DUMP_DFA_STATES_POST_UNREACHABLE (1 << 28) +#define DUMP_DFA_COMPTRESSED_STATES (1 << 29) #endif /* APPARMOR_RE_H */ diff --git a/parser/libapparmor_re/chfa.h b/parser/libapparmor_re/chfa.h index fe621bd9f..cc36e8580 100644 --- a/parser/libapparmor_re/chfa.h +++ b/parser/libapparmor_re/chfa.h @@ -63,7 +63,7 @@ class CHFA { DefaultBase default_base; NextCheck next_check; const State *start; - map num; + Renumber_Map num; map eq; unsigned int chfaflags; private: diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 575d72073..827d225cf 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -83,6 +83,21 @@ ostream &operator<<(ostream &os, State &state) return os; } +ostream &operator<<(ostream &os, + const std::pair &p) +{ + /* dump the state label */ + if (p.second && (*p.second)[p.first] != (size_t) p.first->label) { + os << '{'; + os << (*p.second)[p.first]; + os << " == " << *(p.first); + os << '}'; + } else { + os << *(p.first); + } + return os; +} + /** * diff_weight - Find differential compression distance between @rel and @this * @rel: State to compare too @@ -1075,11 +1090,11 @@ void DFA::dump_diff_encode(ostream &os) /** * text-dump the DFA (for debugging). */ -void DFA::dump(ostream & os) +void DFA::dump(ostream &os, Renumber_Map *renum) { for (Partition::iterator i = states.begin(); i != states.end(); i++) { if (*i == start || (*i)->perms.is_accept()) { - os << **i; + os << make_pair(*i, renum); if (*i == start) { os << " <== "; (*i)->perms.dump_header(os); @@ -1102,7 +1117,7 @@ void DFA::dump(ostream & os) } else { if (first) { first = false; - os << **i << " perms: "; + os << make_pair(*i, renum) << " perms: "; if ((*i)->perms.is_accept()) (*i)->perms.dump(os); else @@ -1110,7 +1125,7 @@ void DFA::dump(ostream & os) os << "\n"; } os << " "; j->first.dump(os) << " -> " << - *(j)->second; + make_pair(j->second, renum); if ((j)->second->perms.is_accept()) os << " ", (j->second)->perms.dump(os); os << "\n"; @@ -1120,7 +1135,7 @@ void DFA::dump(ostream & os) if ((*i)->otherwise != nonmatching) { if (first) { first = false; - os << **i << " perms: "; + os << make_pair(*i, renum) << " perms: "; if ((*i)->perms.is_accept()) (*i)->perms.dump(os); else @@ -1135,7 +1150,7 @@ void DFA::dump(ostream & os) os << *k; } } - os << "] -> " << *(*i)->otherwise; + os << "] -> " << make_pair((*i)->otherwise, renum); if ((*i)->otherwise->perms.is_accept()) os << " ", (*i)->otherwise->perms.dump(os); os << "\n"; diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index ba0edeabf..79cc0ede1 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -349,6 +349,8 @@ public: } }; +typedef map Renumber_Map; + /* Transitions in the DFA. */ class DFA { void dump_node_to_dfa(void); @@ -385,7 +387,7 @@ public: void undiff_encode(void); void dump_diff_encode(ostream &os); - void dump(ostream &os); + void dump(ostream &os, Renumber_Map *renum); void dump_dot_graph(ostream &os); void dump_uniq_perms(const char *s);