diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc index 75699ce8a..83aa19783 100644 --- a/parser/libapparmor_re/hfa.cc +++ b/parser/libapparmor_re/hfa.cc @@ -334,7 +334,16 @@ State *DFA::add_new_state(optflags const &opts, NodeSet *anodes, ProtoState proto; proto.init(nnodev, anodev); - State *state = new State(opts, node_map.size(), proto, other, filedfa); + State *state; + try { + state = new State(opts, node_map.size(), proto, other, filedfa); + } catch(int error) { + /* this function is called in the DFA object creation, + * and the exception prevents the destructor from + * being called, so call the helper here */ + cleanup(); + throw error; + } pair x = node_map.insert(proto, state); if (x.second == false) { delete state; @@ -392,7 +401,17 @@ void DFA::update_state_transitions(optflags const &opts, State *state) */ for (Cases::iterator j = cases.begin(); j != cases.end(); j++) { State *target; - target = add_new_state(opts, j->second, nonmatching); + try { + target = add_new_state(opts, j->second, nonmatching); + } catch (int error) { + /* when add_new_state fails, there could still + * be NodeSets in the rest of cases, so clean + * them up before re-throwing the exception */ + for (Cases::iterator k = ++j; k != cases.end(); k++) { + delete k->second; + } + throw error; + } /* Don't insert transition that the otherwise transition * already covers @@ -522,11 +541,7 @@ DFA::DFA(Node *root, optflags const &opts, bool buildfiledfa): root(root), filed DFA::~DFA() { - anodes_cache.clear(); - nnodes_cache.clear(); - - for (Partition::iterator i = states.begin(); i != states.end(); i++) - delete *i; + cleanup(); } State *DFA::match_len(State *state, const char *str, size_t len) diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h index 5bdd00bb5..8a9ea7e70 100644 --- a/parser/libapparmor_re/hfa.h +++ b/parser/libapparmor_re/hfa.h @@ -368,6 +368,15 @@ class DFA { NodeMap node_map; std::list work_queue; + void cleanup(void) { + anodes_cache.clear(); + nnodes_cache.clear(); + + for (Partition::iterator i = states.begin(); i != states.end(); i++) { + delete *i; + } + states.clear(); + } public: DFA(Node *root, optflags const &flags, bool filedfa); virtual ~DFA(); diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 0b5d4111f..0e4e4a643 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -577,6 +577,7 @@ flags: opt_flags TOK_OPENPAREN flagvals TOK_CLOSEPAREN flagvals: flagvals flagval { $1.merge($2); + $2.clear(); $$ = $1; }; diff --git a/parser/profile.cc b/parser/profile.cc index 52a195b9d..2e46ddf22 100644 --- a/parser/profile.cc +++ b/parser/profile.cc @@ -78,6 +78,7 @@ void ProfileList::dump_profile_names(bool children) Profile::~Profile() { hat_table.clear(); + flags.clear(); free_cod_entries(entries); free_cond_entry_list(xattrs); @@ -97,10 +98,6 @@ Profile::~Profile() free(name); if (attachment) free(attachment); - if (flags.disconnected_path) - free(flags.disconnected_path); - if (flags.disconnected_ipc) - free(flags.disconnected_ipc); if (ns) free(ns); for (int i = (AA_EXEC_LOCAL >> 10) + 1; i < AA_EXEC_COUNT; i++) diff --git a/parser/profile.h b/parser/profile.h index e7df0f90e..313940167 100644 --- a/parser/profile.h +++ b/parser/profile.h @@ -175,6 +175,12 @@ public: signal = 0; error = 0; } + + void clear(void) { + free(disconnected_path); + free(disconnected_ipc); + } + void init(const char *str) { init(); @@ -301,7 +307,7 @@ public: } // same ignore rhs.disconnect_path } else { - disconnected_path = rhs.disconnected_path; + disconnected_path = strdup(rhs.disconnected_path); } } if (rhs.disconnected_ipc) { @@ -311,7 +317,7 @@ public: } // same so do nothing } else { - disconnected_ipc = rhs.disconnected_ipc; + disconnected_ipc = strdup(rhs.disconnected_ipc); } } if (rhs.signal) {