[apparmor] [Patch] Bug 888077 - aliases being partially applied

John Johansen john.johansen at canonical.com
Mon Jul 8 09:06:42 UTC 2013


Below is a mostly complete patch for https://bugs.launchpad.net/apparmor/+bug/888077

It is currently missing support for link and mount rules. This patch is
done against the 2.8 branch, and the question is, is this something we
want in 2.8.2/3. It is rather large, and I want to rework it some before
it goes to the 2.9/3.0 branch. So the two branch will differ on this
point if we pull it into 2.8

---

diff --git a/parser/libapparmor_re/aare_rules.cc b/parser/libapparmor_re/aare_rules.cc
index 45664c0..5e6d652 100644
--- a/parser/libapparmor_re/aare_rules.cc
+++ b/parser/libapparmor_re/aare_rules.cc
@@ -76,6 +76,9 @@ DenyMatchFlag *deny_flags[FLAGS_WIDTH][MATCH_FLAGS_SIZE];
 MatchFlag *exec_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE];	/* mods + unsafe + ix + pux * u::o */
 ExactMatchFlag *exact_match_flags[FLAGS_WIDTH][EXEC_MATCH_FLAGS_SIZE];	/* mods + unsafe + ix + pux *u::o */
 
+typedef map<pair<const char *, const char *>, AliasToNode *> AliasMap;
+AliasMap alias_map;
+
 extern "C" void aare_reset_matchflags(void)
 {
 	uint32_t i, j;
@@ -92,6 +95,42 @@ extern "C" void aare_reset_matchflags(void)
 	RESET_FLAGS(exec_match_flags, EXEC_MATCH_FLAGS_SIZE);
 	RESET_FLAGS(exact_match_flags, EXEC_MATCH_FLAGS_SIZE);
 #undef RESET_FLAGS
+	alias_map.clear();
+}
+
+extern "C" int aare_add_alias(aare_ruleset_t *rules, const char *from,
+			      const char *to)
+{
+	Node *tree_from = NULL, *tree_to = NULL;
+	AliasToNode *node = NULL;
+
+	AliasMap::iterator i = alias_map.find(make_pair(from, to));
+	if (i == alias_map.end()) {
+		node = new AliasToNode();
+		alias_map.insert(make_pair(make_pair(from, to), node));
+	} else {
+		node = i->second;
+	}
+
+	if (regex_parse(&tree_from, from))
+		return 0;
+	if (rules->reverse)
+		flip_tree(tree_from);
+	if (rules->root)
+		rules->root = new AltNode(rules->root, new CatNode(tree_from, &node->from));
+	else
+		rules->root = new CatNode(tree_from, &node->from);
+
+	if (regex_parse(&tree_to, to))
+		return 0;
+	if (rules->reverse)
+		flip_tree(tree_to);
+	if (rules->root)
+		rules->root = new AltNode(rules->root, new CatNode(tree_to, node));
+	else
+		rules->root = new CatNode(tree_to, node);
+
+	return 1;
 }
 
 extern "C" int aare_add_rule_vec(aare_ruleset_t *rules, int deny,
diff --git a/parser/libapparmor_re/aare_rules.h b/parser/libapparmor_re/aare_rules.h
index 33e554c..c053530 100644
--- a/parser/libapparmor_re/aare_rules.h
+++ b/parser/libapparmor_re/aare_rules.h
@@ -40,6 +40,7 @@ int aare_add_rule(aare_ruleset_t *rules, char *rule, int deny, uint32_t perms,
 int aare_add_rule_vec(aare_ruleset_t *rules, int deny, uint32_t perms,
 		      uint32_t audit, int count, char **rulev,
 		      dfaflags_t flags);
+int aare_add_alias(aare_ruleset_t *rules, const char *from, const char *to);
 void *aare_create_dfa(aare_ruleset_t *rules, size_t *size, dfaflags_t flags);
 void aare_reset_matchflags(void);
 
diff --git a/parser/libapparmor_re/apparmor_re.h b/parser/libapparmor_re/apparmor_re.h
index 186899c..1fdb915 100644
--- a/parser/libapparmor_re/apparmor_re.h
+++ b/parser/libapparmor_re/apparmor_re.h
@@ -30,6 +30,10 @@ typedef enum dfaflags {
   DFA_CONTROL_REMOVE_UNREACHABLE =	1 << 7,
   DFA_CONTROL_TRANS_HIGH =	1 << 8,
 
+  DFA_COMPAT_OLD_ALIAS =	1 << 10,
+
+  DFA_DUMP_ALIAS_INFO =		1 << 11,
+  DFA_DUMP_PRE_ALIAS =		1 << 12,
   DFA_DUMP_MIN_PARTS =		1 << 13,
   DFA_DUMP_UNIQ_PERMS =		1 << 14,
   DFA_DUMP_MIN_UNIQ_PERMS =	1 << 15,
diff --git a/parser/libapparmor_re/expr-tree.h b/parser/libapparmor_re/expr-tree.h
index 29c2ded..651a02d 100644
--- a/parser/libapparmor_re/expr-tree.h
+++ b/parser/libapparmor_re/expr-tree.h
@@ -205,6 +205,7 @@ public:
 	void compute_lastpos() { lastpos.insert(this); }
 	virtual void follow(Cases &cases) = 0;
 	virtual int is_accept(void) = 0;
+	virtual int is_postprocess(void) = 0;
 };
 
 /* common base class for all the different classes that contain
@@ -214,6 +215,7 @@ class CNode: public ImportantNode {
 public:
 	CNode(): ImportantNode() { }
 	int is_accept(void) { return false; }
+	int is_postprocess(void) { return false; }
 };
 
 /* Match one specific character (/c/). */
@@ -358,35 +360,6 @@ public:
 	ostream &dump(ostream &os) { return os << "."; }
 };
 
-/**
- * Indicate that a regular expression matches. An AcceptNode itself
- * doesn't match anything, so it will never generate any transitions.
- */
-class AcceptNode: public ImportantNode {
-public:
-	AcceptNode() { }
-	int is_accept(void) { return true; }
-	void release(void)
-	{
-		/* don't delete AcceptNode via release as they are shared, and
-		 * will be deleted when the table the are stored in is deleted
-		 */
-	}
-
-	void follow(Cases &cases __attribute__ ((unused)))
-	{
-		/* Nothing to follow. */
-	}
-
-	/* requires accept nodes to be common by pointer */
-	int eq(Node *other)
-	{
-		if (dynamic_cast<AcceptNode *>(other))
-			return (this == other);
-		return 0;
-	}
-};
-
 /* Match a node zero or more times. (This is a unary operator.) */
 class StarNode: public OneChildNode {
 public:
@@ -523,6 +496,55 @@ public:
 	}
 };
 
+class SharedNode: public ImportantNode {
+public:
+	SharedNode() { }
+	void release(void)
+	{
+		/* don't delete SharedNodes via release as they are shared, and
+		 * will be deleted when the table they are stored in is deleted
+		 */
+	}
+
+	void follow(Cases &cases __attribute__ ((unused)))
+	{
+		/* Nothing to follow. */
+	}
+
+	/* requires shared nodes to be common by pointer */
+	int eq(Node *other) { return (this == other); }
+};
+
+/**
+ * Indicate that a regular expression matches. An AcceptNode itself
+ * doesn't match anything, so it will never generate any transitions.
+ */
+class AcceptNode: public SharedNode {
+public:
+	AcceptNode() { }
+	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) { }
+	ostream &dump(ostream &os) { return os << '<' << flag << '>'; }
+
+	uint32_t flag;
+	uint32_t audit;
+};
+
+class ExactMatchFlag: public MatchFlag {
+public:
+	ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
+};
+
+class DenyMatchFlag: public MatchFlag {
+public:
+	DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
+};
+
 /* Traverse the syntax tree depth-first in an iterator-like manner. */
 class depth_first_traversal {
 	stack<Node *>pos;
@@ -574,24 +596,4 @@ void label_nodes(Node *root);
 unsigned long hash_NodeSet(NodeSet *ns);
 void flip_tree(Node *node);
 
-
-class MatchFlag: public AcceptNode {
-public:
-	MatchFlag(uint32_t flag, uint32_t audit): flag(flag), audit(audit) { }
-	ostream &dump(ostream &os) { return os << '<' << flag << '>'; }
-
-	uint32_t flag;
-	uint32_t audit;
-};
-
-class ExactMatchFlag: public MatchFlag {
-public:
-	ExactMatchFlag(uint32_t flag, uint32_t audit): MatchFlag(flag, audit) {}
-};
-
-class DenyMatchFlag: public MatchFlag {
-public:
-	DenyMatchFlag(uint32_t flag, uint32_t quiet): MatchFlag(flag, quiet) {}
-};
-
 #endif /* __LIBAA_RE_EXPR */
diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc
index e779dd3..34a18d9 100644
--- a/parser/libapparmor_re/hfa.cc
+++ b/parser/libapparmor_re/hfa.cc
@@ -73,10 +73,13 @@ ostream &operator<<(ostream &os, const State &state)
 	return os;
 }
 
-static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
-)
+typedef set<PostProcessNode *> PostNodeSet;
+
+static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes,
+			     PostNodeSet **postnodes)
 {
 	*anodes = *nnodes = NULL;
+	*postnodes = NULL;
 	for (NodeSet::iterator i = nodes->begin(); i != nodes->end(); ) {
 		if ((*i)->is_accept()) {
 			if (!*anodes)
@@ -84,20 +87,21 @@ static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
 			(*anodes)->insert(*i);
 			NodeSet::iterator k = i++;
 			nodes->erase(k);
+		} else if ((*i)->is_postprocess()) {
+			if (!*postnodes)
+				*postnodes = new PostNodeSet;
+			(*postnodes)->insert((PostProcessNode *) *i);
+			NodeSet::iterator k = i++;
+			nodes->erase(k);
 		} else
 			i++;
 	}
 	*nnodes = nodes;
 }
 
-State *DFA::add_new_state(NodeSet *nodes, State *other)
+State *DFA::add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other)
 {
-	/* The splitting of nodes should probably get pushed down into
-	 * follow(), ie. put in separate lists from the start
-	 */
-	NodeSet *anodes, *nnodes;
 	hashedNodeVec *nnodev;
-	split_node_types(nodes, &anodes, &nnodes);
 	nnodev = nnodes_cache.insert(nnodes);
 	anodes = anodes_cache.insert(anodes);
 
@@ -115,6 +119,30 @@ State *DFA::add_new_state(NodeSet *nodes, State *other)
 	return x.first->second;
 }
 
+State *DFA::add_new_state(NodeSet *nodes, State *other)
+{
+	/* The splitting of nodes should probably get pushed down into
+	 * follow(), ie. put in separate lists from the start
+	 */
+	NodeSet *anodes, *nnodes;
+	PostNodeSet *postnodes;
+	split_node_types(nodes, &anodes, &nnodes, &postnodes);
+
+	State *state = add_new_state(anodes, nnodes, other);
+
+	/* add state to each unique post process node */
+	if (postnodes && state != nonmatching) {
+		for (PostNodeSet::iterator i = postnodes->begin();
+		     i != postnodes->end(); i++) {
+//cerr << "adding state " << *state << " to postnode " << *i << "\n";
+			(*i)->states.insert(state);
+		}
+		dfa_postnodes.insert(postnodes->begin(), postnodes->end());
+	}
+
+	return state;
+}
+
 void DFA::update_state_transitions(State *state)
 {
 	/* Compute possible transitions for state->nodes.  This is done by
@@ -169,13 +197,138 @@ void DFA::dump_node_to_dfa(void)
 		cerr << "  " << (*i)->label << " <= " << (*i)->proto << "\n";
 }
 
+class NodeSetPair {
+public:
+	NodeSet *anodes;
+	NodeSet *nnodes;
+
+	NodeSetPair(void) { anodes = nnodes = NULL; }
+	NodeSetPair(NodeSet *a, NodeSet *n) { anodes = a; nnodes = n; }
+
+	void insert(ProtoState &proto) {
+		if (proto.nnodes) {
+			if (!nnodes)
+				nnodes = new NodeSet();
+			nnodes->insert(proto.nnodes->begin(), proto.nnodes->end());
+		}
+		if (proto.anodes) {
+			if (!anodes)
+				anodes = new NodeSet();
+			anodes->insert(proto.anodes->begin(), proto.anodes->end());
+		}
+	}
+};
+//typedef pair<NodeSet *, NodeSet *> NodeSetPair;
+typedef map<uchar, NodeSetPair> NodeSetPairMap;
+
+
+void alias_add_transitions(State &state, NodeSetPair &otherwise,
+			   NodeSetPairMap &trans)
+{
+	otherwise.insert(state.otherwise->proto);
+
+	for (StateTrans::iterator k = state.trans.begin(); k != state.trans.end(); k++) {
+		trans[k->first].insert(k->second->proto);
+	}
+}
+
+void DFA::update_state_for_alias(State &state, set<State *> &from,
+				 dfaflags_t flags)
+{
+	NodeSetPairMap trans;
+	NodeSetPair otherwise(NULL, NULL);
+	State *target;
+
+	if (flags & DFA_DUMP_ALIAS_INFO) {
+		cerr << "Updating state " << state << " for alias from ";
+		for (set<State *>::iterator i = from.begin(); i != from.end(); i++) {
+			if ((*i) == nonmatching)
+				continue;
+			cerr << (**i) << " ";
+		}
+		cerr << "\n";
+	}
+
+	alias_add_transitions(state, otherwise, trans);
+	for (set<State *>::iterator i = from.begin(); i != from.end(); i++) {
+		if ((*i) == nonmatching)
+			continue;
+		alias_add_transitions(**i, otherwise, trans);
+	}
+
+	/* now update state transitions, to the updated transitions */
+	if (otherwise.nnodes || otherwise.anodes) {
+		target = add_new_state(otherwise.anodes, otherwise.nnodes, nonmatching);
+		if (target != state.otherwise) {
+			if (flags & DFA_DUMP_ALIAS_INFO) {
+				cerr << "  updating trans otherwise from ";
+				if (state.otherwise)
+					cerr << *state.otherwise;
+				else
+					cerr << "<null>";
+				cerr << " to " << *target << "\n";
+			}
+			state.otherwise = target;
+		}
+	}
+
+	for (NodeSetPairMap::iterator i = trans.begin(); i != trans.end(); i++) {
+		target = add_new_state(i->second.anodes, i->second.nnodes, nonmatching);
+		if (target == state.otherwise) {
+			if (flags & DFA_DUMP_ALIAS_INFO) {
+				cerr << "  removing trans " << i->first << " to ";
+				if (state.trans[i->first])
+					cerr << state.trans[i->first];
+				else
+					cerr << "<null>";
+				cerr << "\n";
+			}
+			state.trans.erase(i->first);
+		} else if (target != state.trans[i->first]) {
+			if (flags & DFA_DUMP_ALIAS_INFO) {
+				cerr << "  updating trans " << i->first << " from ";
+				if (state.trans[i->first])
+					cerr << *state.trans[i->first];
+				else
+					cerr << "<null>";
+				cerr << " to " << *target << "\n";
+			}
+			state.trans[i->first] = target;
+		}
+	}
+}
+
+void DFA::process_work_queue(const char *header, dfaflags_t flags)
+{
+	int i = 0;
+
+	while (!work_queue.empty()) {
+		if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
+			cerr << "\033[2K" << header << ": queue "
+			     << work_queue.size()
+			     << "\tstates "
+			     << states.size()
+			     << "\teliminated duplicates "
+			     << node_map.dup
+			     << "\r";
+		}
+		i++;
+
+		State *from = work_queue.front();
+		work_queue.pop_front();
+
+		/* Update 'from's transitions, and if it transitions to any
+		 * unknown State create it and add it to the work_queue
+		 */
+		update_state_transitions(from);
+	}  /* while (!work_queue.empty()) */
+}
+
 /**
  * Construct a DFA from a syntax tree.
  */
 DFA::DFA(Node *root, dfaflags_t flags): root(root)
 {
-	int i = 0;
-
 	if (flags & DFA_DUMP_PROGRESS)
 		fprintf(stderr, "Creating dfa:\r");
 
@@ -205,28 +358,28 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
 	 *       work_queue at any given time, thus reducing peak memory use.
 	 */
 	work_queue.push_back(start);
+	process_work_queue("Creating dfa", flags);
 
-	while (!work_queue.empty()) {
-		if (i % 1000 == 0 && (flags & DFA_DUMP_PROGRESS)) {
-			cerr << "\033[2KCreating dfa: queue "
-			     << work_queue.size()
-			     << "\tstates "
-			     << states.size()
-			     << "\teliminated duplicates "
-			     << node_map.dup
-			     << "\r";
-		}
-		i++;
+	/* apply post process nodes before minimization. This lets us remove
+	 * nodes/states in minimization that are made no longer reachable
+	 * by post processing
+	 */
 
-		State *from = work_queue.front();
-		work_queue.pop_front();
+	if (!dfa_postnodes.empty()) {
+		if (flags & DFA_DUMP_PRE_ALIAS) {
+			cerr << "DFA before alias rewrite\n";
+			this->dump(cerr);
+		}
+		for (set<PostProcessNode *>::iterator i = dfa_postnodes.begin();
+		     i != dfa_postnodes.end(); i++) {
+			(*i)->apply(*this, flags);
+		}
 
-		/* Update 'from's transitions, and if it transitions to any
-		 * unknown State create it and add it to the work_queue
+		/* post processing could have added new states that need
+		 * transitions created. So reprocess work_queue
 		 */
-		update_state_transitions(from);
-
-	}  /* while (!work_queue.empty()) */
+		process_work_queue("Postprocessing dfa", flags);
+	}
 
 	/* cleanup Sets of nodes used computing the DFA as they are no longer
 	 * needed.
@@ -256,6 +409,7 @@ DFA::DFA(Node *root, dfaflags_t flags): root(root)
 	 * Do not clear out uniq_anodes, as we need them for minimizations
 	 * diffs, unions, ...
 	 */
+	dfa_postnodes.clear();
 	nnodes_cache.clear();
 	node_map.clear();
 }
@@ -264,6 +418,7 @@ DFA::~DFA()
 {
 	anodes_cache.clear();
 	nnodes_cache.clear();
+	dfa_postnodes.clear();
 
 	for (Partition::iterator i = states.begin(); i != states.end(); i++)
 		delete *i;
diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h
index cbcb46f..f73dca8 100644
--- a/parser/libapparmor_re/hfa.h
+++ b/parser/libapparmor_re/hfa.h
@@ -429,18 +429,23 @@ public:
 	}
 };
 
+class PostProcessNode;
+
 /* Transitions in the DFA. */
 
 class DFA {
 	void dump_node_to_dfa(void);
 	State *add_new_state(NodeSet *nodes, State *other);
+	State *add_new_state(NodeSet *anodes, NodeSet *nnodes, State *other);
 	void update_state_transitions(State *state);
+	void process_work_queue(const char *header, dfaflags_t);
 
 	/* temporary values used during computations */
 	NodeCache anodes_cache;
 	NodeVecCache nnodes_cache;
 	NodeMap node_map;
 	list<State *> work_queue;
+	set<PostProcessNode *> dfa_postnodes;
 
 public:
 	DFA(Node *root, dfaflags_t flags);
@@ -460,6 +465,8 @@ public:
 	void dump_uniq_perms(const char *s);
 	map<uchar, uchar> equivalence_classes(dfaflags_t flags);
 	void apply_equivalence_classes(map<uchar, uchar> &eq);
+	void update_state_for_alias(State &state, set<State *> &from,
+				    dfaflags_t flags);
 	Node *root;
 	State *nonmatching, *start;
 	Partition states;
@@ -467,4 +474,47 @@ public:
 
 void dump_equivalence_classes(ostream &os, map<uchar, uchar> &eq);
 
+
+/* special post dfa construction nodes that can rewrite parts of the dfa
+ * and or cause more dfa construction. These nodes are removed as they
+ * are processed.  We use these for operations like alias and set operations
+ * on regular expressions.
+ */
+
+class PostProcessNode: public SharedNode {
+public:
+	PostProcessNode(): states() { }
+	int is_accept(void) { return false; }
+	int is_postprocess(void) { return true; }
+	virtual void apply(DFA &dfa, dfaflags_t flags) = 0;
+	ostream &dump(ostream &os) { return os << "<<" << this << ">>"; }
+
+	set<State *> states;
+};
+
+/* Alias does nothing but store a list of states that it tags, is always
+ * paired with an AliasToNode
+ */
+class AliasFromNode: public PostProcessNode {
+public:
+	AliasFromNode(): PostProcessNode() { }
+	virtual void apply(DFA &dfa, dfaflags_t flags) { }
+};
+
+/* Handle actual processing of an alias */
+class AliasToNode: public PostProcessNode {
+public:
+	AliasToNode(): PostProcessNode() { }
+	virtual void apply(DFA &dfa, dfaflags_t flags)
+	{
+		/* For each alias_to state update its transitions */
+		for (set<State *>::iterator i = states.begin();
+		     i != states.end(); i++) {
+			dfa.update_state_for_alias(**i, from.states, flags);
+		}
+	}
+
+	AliasFromNode from;
+};
+
 #endif /* __LIBAA_RE_HFA_H */
diff --git a/parser/parser.h b/parser/parser.h
index 8199f43..38198f2 100644
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -362,7 +362,8 @@ void free_symtabs(void);
 
 /* parser_alias.c */
 extern int new_alias(const char *from, const char *to);
-extern void replace_aliases(struct codomain *cod);
+extern void setup_name_aliases(struct codomain *cod);
+extern void replace_aliases(aare_ruleset_t *rules, struct codomain *cod);
 extern void free_aliases(void);
 
 /* parser_merge.c */
diff --git a/parser/parser_alias.c b/parser/parser_alias.c
index 00a4ced..d7d0c5c 100644
--- a/parser/parser_alias.c
+++ b/parser/parser_alias.c
@@ -152,7 +152,6 @@ static void process_entries(const void *nodep, VISIT value, int __unused level)
 	}
 }
 
-static struct codomain *target_cod;
 static void process_name(const void *nodep, VISIT value, int __unused level)
 {
 	struct alias_rule **t = (struct alias_rule **) nodep;
@@ -185,15 +184,42 @@ static void process_name(const void *nodep, VISIT value, int __unused level)
 	}
 }
 
-void replace_aliases(struct codomain *cod)
+static aare_ruleset_t *target_rules;
+static void process_new_alias(const void *nodep, VISIT value, int __unused level)
+{
+	struct alias_rule **t = (struct alias_rule **) nodep;
+
+	if (!aare_add_alias(target_rules, (*t)->from, (*t)->to))
+		return;
+
+	return;
+}
+
+void setup_name_aliases(struct codomain *cod)
 {
 	target_cod = cod;
 	twalk(alias_table, process_name);
+}
 
-	if (cod->entries) {
-		target_list = cod->entries;
-		target_cod = cod;
-		twalk(alias_table, process_entries);
+void replace_aliases(aare_ruleset_t *rules, struct codomain *cod)
+{
+	target_cod = cod;
+	if (!(dfaflags & DFA_COMPAT_OLD_ALIAS)) {
+		/* forces creation of xmatch dfa if it finds an alias
+		 * this does not catch all alias possibilities but
+		 * the dfa alias handling in process_profile_name_xmatch
+		 * handles all cases taht are missing.
+		 * Probably should go to always just having an xmatch
+		 */
+
+		target_rules = rules;
+		twalk(alias_table, process_new_alias);
+	} else {
+		if (cod->entries) {
+			target_list = cod->entries;
+			target_cod = cod;
+			twalk(alias_table, process_entries);
+		}
 	}
 }
 
diff --git a/parser/parser_main.c b/parser/parser_main.c
index 9cbfccf..6ac25f9 100644
--- a/parser/parser_main.c
+++ b/parser/parser_main.c
@@ -219,6 +219,9 @@ optflag_table_t dumpflag_table[] = {
 	{ 1, "equiv-stats", "Dump equivance class stats",
 	  DFA_DUMP_EQUIV_STATS },
 	{ 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
+	{ 1, "dfa-prealias", "Dump dfa before alias rewrite",
+	  DFA_DUMP_PRE_ALIAS },
+	{ 1, "alias-info", "Dump alias info", DFA_DUMP_ALIAS_INFO },
 	{ 0, NULL, NULL, 0 },
 };
 
@@ -248,6 +251,7 @@ optflag_table_t optflag_table[] = {
 	  DFA_CONTROL_TRANS_HIGH },
 	{ 2, "compress-fast", "do faster dfa transition table compression",
 	  DFA_CONTROL_TRANS_HIGH },
+	{ 0, "old-alias", "use old alias processesing", DFA_COMPAT_OLD_ALIAS },
 	{ 0, NULL, NULL, 0 },
 };
 
diff --git a/parser/parser_policy.c b/parser/parser_policy.c
index dce1b0d..4f5bb54 100644
--- a/parser/parser_policy.c
+++ b/parser/parser_policy.c
@@ -328,7 +328,6 @@ static void __process_regex(const void *nodep, const VISIT value,
 
 	if (value == preorder || value == endorder)
 		return;
-
 	if (process_regex(*t) != 0) {
 		PERROR(_("ERROR processing regexs for profile %s, failed to load\n"),
 		       (*t)->name);
@@ -411,7 +410,7 @@ static void __process_alias(const void *nodep, const VISIT value,
 	if (value == preorder || value == endorder)
 		return;
 
-	replace_aliases((*t));
+	replace_aliases(NULL, (*t));
 
 	if ((*t)->hat_table)
 		twalk((*t)->hat_table, __process_alias);
@@ -764,11 +763,14 @@ int post_process_policy(int debug_only)
 		return retval;
 	}
 
-	retval = post_process_alias();
-	if (retval != 0) {
-		PERROR(_("%s: Errors found during postprocess.  Aborting.\n"),
-		       progname);
-		return retval;
+	/* only use old alias technique if new aliasing is disabled */
+	if (dfaflags & DFA_COMPAT_OLD_ALIAS) {
+		retval = post_process_alias();
+		if (retval != 0) {
+			PERROR(_("%s: Errors found during postprocess.  Aborting.\n"),
+			       progname);
+			return retval;
+		}
 	}
 
 	retval = post_merge_rules();
diff --git a/parser/parser_regex.c b/parser/parser_regex.c
index 0ba8114..77be150 100644
--- a/parser/parser_regex.c
+++ b/parser/parser_regex.c
@@ -389,6 +389,8 @@ static int process_profile_name_xmatch(struct codomain *cod)
 	pattern_t ptype;
 	const char *name;
 
+	setup_name_aliases(cod);
+
 	/* don't filter_slashes for profile names */
 	if (cod->attachment)
 		name = cod->attachment;
@@ -434,6 +436,12 @@ static int process_profile_name_xmatch(struct codomain *cod)
 				}
 			}
 		}
+
+		/* create aliases if there is an xmatch - alias ensures */
+		if (!(dfaflags & DFA_COMPAT_OLD_ALIAS)) {
+			replace_aliases(rule, cod);
+		}
+
 		cod->xmatch = aare_create_dfa(rule, &cod->xmatch_size,
 					      dfaflags);
 		aare_delete_ruleset(rule);
@@ -570,14 +578,20 @@ int process_regex(struct codomain *cod)
 {
 	int error = -1;
 
-	if (regex_type == AARE_DFA) {
-		if (!process_profile_name_xmatch(cod))
-			goto out;
+	if (!process_profile_name_xmatch(cod))
+		goto out;
 
+	if (regex_type == AARE_DFA) {
 		cod->dfarules = aare_new_ruleset(0);
 		if (!cod->dfarules)
 			goto out;
 	}
+
+	if (!(dfaflags & DFA_COMPAT_OLD_ALIAS)) {
+		replace_aliases(cod->dfarules, cod);
+/* TODO: alias for link rules*/
+	}
+
 	if (!post_process_entries(cod))
 		goto out;
 
@@ -1075,6 +1089,8 @@ int process_policydb(struct codomain *cod)
 	if (!post_process_policydb_ents(cod))
 		goto out;
 
+	/* TODO: alias processing for mount rules */
+
 	if (regex_type == AARE_DFA && cod->policy_rule_count > 0) {
 		cod->policy_dfa = aare_create_dfa(cod->policy_rules,
 						  &cod->policy_dfa_size,



More information about the AppArmor mailing list