[apparmor] [PATCH 1/3] Track deny and quiet perms during DFA construction

John Johansen john.johansen at canonical.com
Tue Feb 14 17:57:26 UTC 2012


Delay the packing of audit and quiet permissions until chfa construction,
and track deny and quiet perms during DFA construction, so that we will
be able to do full minimization.  Also delay the packing of audit and

Signed-off-by: John Johansen <john.johansen at canonical.com>
---
 parser/libapparmor_re/chfa.cc |    9 ++-
 parser/libapparmor_re/hfa.cc  |  128 +++++++++++++++++++++-------------------
 parser/libapparmor_re/hfa.h   |   37 +++++++++++-
 3 files changed, 105 insertions(+), 69 deletions(-)

diff --git a/parser/libapparmor_re/chfa.cc b/parser/libapparmor_re/chfa.cc
index 5f069e4..262d777 100644
--- a/parser/libapparmor_re/chfa.cc
+++ b/parser/libapparmor_re/chfa.cc
@@ -31,6 +31,7 @@
 
 #include "hfa.h"
 #include "chfa.h"
+#include "../immunix.h"
 
 void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
 				     size_t prev, size_t start)
@@ -112,8 +113,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
 		for (Partition::iterator i = dfa.states.begin(); i != dfa.states.end(); i++) {
 			if (*i != dfa.nonmatching && *i != dfa.start) {
 				insert_state(free_list, *i, dfa);
-				accept[num.size()] = (*i)->accept;
-				accept2[num.size()] = (*i)->audit;
+				accept[num.size()] = (*i)->perms.allow;
+				accept2[num.size()] = PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny);
 				num.insert(make_pair(*i, num.size()));
 			}
 			if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
@@ -129,8 +130,8 @@ CHFA::CHFA(DFA &dfa, map<uchar, uchar> &eq, dfaflags_t flags): eq(eq)
 			if (i->second != dfa.nonmatching &&
 			    i->second != dfa.start) {
 				insert_state(free_list, i->second, dfa);
-				accept[num.size()] = i->second->accept;
-				accept2[num.size()] = i->second->audit;
+				accept[num.size()] = i->second->perms.allow;
+				accept2[num.size()] = PACK_AUDIT_CTL(i->second->perms.audit, i->second->perms.quiet & i->second->perms.deny);
 				num.insert(make_pair(i->second, num.size()));
 			}
 			if (flags & (DFA_DUMP_TRANS_PROGRESS)) {
diff --git a/parser/libapparmor_re/hfa.cc b/parser/libapparmor_re/hfa.cc
index 86e5bd5..e4604a4 100644
--- a/parser/libapparmor_re/hfa.cc
+++ b/parser/libapparmor_re/hfa.cc
@@ -283,15 +283,16 @@ State *DFA::match(const char *str)
 
 void DFA::dump_uniq_perms(const char *s)
 {
-	set<pair<uint32_t, uint32_t> > uniq;
+	set<perms_t> uniq;
 	for (Partition::iterator i = states.begin(); i != states.end(); i++)
-		uniq.insert(make_pair((*i)->accept, (*i)->audit));
+		uniq.insert((*i)->perms);
 
 	cerr << "Unique Permission sets: " << s << " (" << uniq.size() << ")\n";
 	cerr << "----------------------\n";
-	for (set<pair<uint32_t, uint32_t> >::iterator i = uniq.begin();
-	     i != uniq.end(); i++) {
-		cerr << "  " << hex << i->first << " " << i->second << dec << "\n";
+	for (set<perms_t >::iterator i = uniq.begin(); i != uniq.end(); i++) {
+		cerr << "  allow:" << hex << i->allow << " deny:"
+		     << i->deny << " audit:" << i->audit
+		     << " quiet:" << i->quiet << dec << "\n";
 	}
 }
 
@@ -331,10 +332,12 @@ void DFA::remove_unreachable(dfaflags_t flags)
 					cerr << "unreachable: " << **i;
 					if (*i == start)
 						cerr << " <==";
-					if ((*i)->accept) {
+					if (!(*i)->perms.is_null()) {
 						cerr << " (0x" << hex 
-						     << (*i)->accept << " " 
-						     << (*i)->audit << dec
+						     << (*i)->perms.allow << " " 
+						     << (*i)->perms.deny << " "
+						     << (*i)->perms.audit << " "
+						     << (*i)->perms.quiet << dec
 						     << ')';
 					}
 					cerr << "\n";
@@ -430,9 +433,9 @@ void DFA::minimize(dfaflags_t flags)
 		uint64_t perm_hash = 0;
 		if (flags & DFA_CONTROL_MINIMIZE_HASH_PERMS) {
 			/* make every unique perm create a new partition */
-			perm_hash = ((uint64_t) (*i)->audit) << 32 |
-				    (uint64_t) (*i)->accept;
-		} else if ((*i)->audit || (*i)->accept) {
+			perm_hash = ((uint64_t) PACK_AUDIT_CTL((*i)->perms.audit, (*i)->perms.quiet & (*i)->perms.deny)) << 32 |
+				    (uint64_t) (*i)->perms.allow;
+		} else if (!(*i)->perms.is_null()) {
 			/* combine all perms together into a single parition */
 			perm_hash = 1;
 		} /* else not an accept state so 0 for perm_hash */
@@ -459,7 +462,6 @@ void DFA::minimize(dfaflags_t flags)
 			     << partitions.size() << "\tinit " << partitions.size()
 			     << " (accept " << accept_count << ")\r";
 	}
-
 	/* perm_map is no longer needed so free the memory it is using.
 	 * Don't remove - doing it manually here helps reduce peak memory usage.
 	 */
@@ -559,10 +561,12 @@ void DFA::minimize(dfaflags_t flags)
 			if (flags & DFA_DUMP_MIN_PARTS)
 				cerr << **i << ", ";
 			(*i)->label = -1;
-			rep->accept |= (*i)->accept;
-			rep->audit |= (*i)->audit;
+			rep->perms.allow |= (*i)->perms.allow;
+			rep->perms.deny |= (*i)->perms.deny;
+			rep->perms.audit |= (*i)->perms.audit;
+			rep->perms.quiet |= (*i)->perms.quiet;
 		}
-		if (rep->accept || rep->audit)
+		if (rep->perms.allow || rep->perms.audit || rep->perms.quiet)
 			final_accept++;
 //if ((*p)->size() > 1)
 //cerr << "\n";
@@ -617,13 +621,15 @@ out:
 void DFA::dump(ostream & os)
 {
 	for (Partition::iterator i = states.begin(); i != states.end(); i++) {
-		if (*i == start || (*i)->accept) {
+		if (*i == start || !(*i)->perms.is_null()) {
 			os << **i;
 			if (*i == start)
 				os << " <==";
-			if ((*i)->accept) {
-				os << " (0x" << hex << (*i)->accept << " "
-				   << (*i)->audit << dec << ')';
+			if ((*i)->perms.allow) {
+				os << " (0x" << hex << (*i)->perms.allow << " "
+				   << (*i)->perms.deny << " "
+				   << (*i)->perms.audit << " "
+				   << (*i)->perms.audit << dec << ')';
 			}
 			os << "\n";
 		}
@@ -657,7 +663,7 @@ void DFA::dump_dot_graph(ostream & os)
 		if (*i == start) {
 			os << "\t\tstyle=bold" << "\n";
 		}
-		uint32_t perms = (*i)->accept;
+		uint32_t perms = (*i)->perms.allow;
 		if (perms) {
 			os << "\t\tlabel=\"" << **i << "\\n("
 			   << perms << ")\"" << "\n";
@@ -839,17 +845,16 @@ static inline int diff_qualifiers(uint32_t perm1, uint32_t perm2)
  * have any exact matches, then they override the execute and safe
  * execute flags.
  */
-uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
+int accept_perms(NodeSet *state, perms_t &perms)
 {
-	uint32_t perms = 0, exact_match_perms = 0;
+	int error = 0;
+	uint32_t allow = 0, exact_match_allow = 0;
 	uint32_t audit = 0, exact_audit = 0, quiet = 0, deny = 0;
 
-	if (error)
-		*error = 0;
-	if (!state) {
-		*audit_ctl = 0;
-		return perms;
-	}
+	perms.clear();
+
+	if (!state)
+		return error;
 
 	for (NodeSet::iterator i = state->begin(); i != state->end(); i++) {
 		MatchFlag *match;
@@ -857,68 +862,69 @@ uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error)
 			continue;
 		if (dynamic_cast<ExactMatchFlag *>(match)) {
 			/* exact match only ever happens with x */
-			if (!is_merged_x_consistent(exact_match_perms,
-						    match->flag) && error)
-				*error = 1;;
-			exact_match_perms |= match->flag;
+			if (!is_merged_x_consistent(exact_match_allow,
+						    match->flag))
+				error = 1;;
+			exact_match_allow |= match->flag;
 			exact_audit |= match->audit;
 		} else if (dynamic_cast<DenyMatchFlag *>(match)) {
 			deny |= match->flag;
 			quiet |= match->audit;
 		} else {
-			if (!is_merged_x_consistent(perms, match->flag)
-			    && error)
-				*error = 1;
-			perms |= match->flag;
+			if (!is_merged_x_consistent(allow, match->flag))
+				error = 1;
+			allow |= match->flag;
 			audit |= match->audit;
 		}
 	}
 
 //if (audit || quiet)
-//fprintf(stderr, "perms: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", perms, audit, exact_match_perms, exact_audit, deny, quiet);
+//fprintf(stderr, "allow: 0x%x, audit: 0x%x exact: 0x%x eaud: 0x%x deny: 0x%x quiet: 0x%x\n", allow, audit, exact_match_allow, exact_audit, deny, quiet);
 
-	perms |= exact_match_perms & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
+	allow |= exact_match_allow & ~(AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE);
 
-	if (exact_match_perms & AA_USER_EXEC_TYPE) {
-		perms = (exact_match_perms & AA_USER_EXEC_TYPE) |
-			(perms & ~AA_USER_EXEC_TYPE);
+	if (exact_match_allow & AA_USER_EXEC_TYPE) {
+		allow = (exact_match_allow & AA_USER_EXEC_TYPE) |
+			(allow & ~AA_USER_EXEC_TYPE);
 		audit = (exact_audit & AA_USER_EXEC_TYPE) |
 			(audit & ~AA_USER_EXEC_TYPE);
 	}
-	if (exact_match_perms & AA_OTHER_EXEC_TYPE) {
-		perms = (exact_match_perms & AA_OTHER_EXEC_TYPE) |
-			(perms & ~AA_OTHER_EXEC_TYPE);
+	if (exact_match_allow & AA_OTHER_EXEC_TYPE) {
+		allow = (exact_match_allow & AA_OTHER_EXEC_TYPE) |
+			(allow & ~AA_OTHER_EXEC_TYPE);
 		audit = (exact_audit & AA_OTHER_EXEC_TYPE) |
 			(audit & ~AA_OTHER_EXEC_TYPE);
 	}
-	if (perms & AA_USER_EXEC & deny)
-		perms &= ~AA_USER_EXEC_TYPE;
+	if (allow & AA_USER_EXEC & deny)
+		allow &= ~AA_USER_EXEC_TYPE;
 
-	if (perms & AA_OTHER_EXEC & deny)
-		perms &= ~AA_OTHER_EXEC_TYPE;
+	if (allow & AA_OTHER_EXEC & deny)
+		allow &= ~AA_OTHER_EXEC_TYPE;
 
-	perms &= ~deny;
+	allow &= ~deny;
 
-	if (audit_ctl)
-		*audit_ctl = PACK_AUDIT_CTL(audit, quiet & deny);
+	perms.allow = allow & ~deny;
+	perms.deny = deny;
+	perms.audit = audit;
+	perms.quiet = quiet & deny;
 
-// if (perms & AA_ERROR_BIT) {
-//     fprintf(stderr, "error bit 0x%x\n", perms);
+// if (allow & AA_ERROR_BIT) {
+//     fprintf(stderr, "error bit 0x%x\n", allow);
 //     exit(255);
 //}
 
-	//if (perms & AA_EXEC_BITS)
-	//fprintf(stderr, "accept perm: 0x%x\n", perms);
+	//if (allow & AA_EXEC_BITS)
+	//fprintf(stderr, "accept perm: 0x%x\n", allow);
 	/*
-	   if (perms & ~AA_VALID_PERMS)
-	   yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), perms);
+	   if (allow & ~AA_VALID_PERMS)
+	   yyerror(_("Internal error accumulated invalid perm 0x%llx\n"), allow);
 	 */
 
-//if (perms & AA_CHANGE_HAT)
-//     fprintf(stderr, "change_hat 0x%x\n", perms);
+//if (allow & AA_CHANGE_HAT)
+//     fprintf(stderr, "change_hat 0x%x\n", allow);
 
-	if (*error)
+	if (error)
 		fprintf(stderr, "profile has merged rule with conflicting x modifiers\n");
 
-	return perms;
+	return error;
 }
diff --git a/parser/libapparmor_re/hfa.h b/parser/libapparmor_re/hfa.h
index 3e8d99b..ebb4a3e 100644
--- a/parser/libapparmor_re/hfa.h
+++ b/parser/libapparmor_re/hfa.h
@@ -37,7 +37,36 @@ class State;
 typedef map<uchar, State *> StateTrans;
 typedef list<State *> Partition;
 
-uint32_t accept_perms(NodeSet *state, uint32_t *audit_ctl, int *error);
+class perms_t {
+public:
+	perms_t(void): allow(0), deny(0), audit(0), quiet(0) { };
+
+	bool is_null(void) { return !(allow | deny | audit | quiet); }
+
+	void clear(void) { allow = deny = audit = quiet = 0; }
+	void add(perms_t &rhs)
+	{
+		deny |= rhs.deny;
+		allow = (allow | rhs.audit) & ~deny;
+		audit |= rhs.audit;
+		quiet = (quiet | rhs.quiet) & deny;
+	}
+
+	bool operator<(perms_t const &rhs)const
+	{
+		if (allow < rhs.allow)
+			return allow < rhs.allow;
+		if (deny < rhs.deny)
+			return deny < rhs.deny;
+		if (audit < rhs.audit)
+			return audit < rhs.audit;
+		return quiet < rhs.quiet;
+	}
+
+	uint32_t allow, deny, audit, quiet;
+};
+
+int accept_perms(NodeSet *state, perms_t &perms);
 
 /*
  * hashedNodes - for efficient set comparison
@@ -256,7 +285,7 @@ public:
 class State {
 public:
 	State(int l, ProtoState &n, State *other) throw(int):
-		label(l), audit(0), accept(0), trans()
+	label(l), perms(), trans()
 	{
 		int error;
 
@@ -268,7 +297,7 @@ public:
 		proto = n;
 
 		/* Compute permissions associated with the State. */
-		accept = accept_perms(n.anodes, &audit, &error);
+		error = accept_perms(n.anodes, perms);
 		if (error) {
 			//cerr << "Failing on accept perms " << error << "\n";
 			throw error;
@@ -283,7 +312,7 @@ public:
 	};
 
 	int label;
-	uint32_t audit, accept;
+	perms_t perms;
 	StateTrans trans;
 	State *otherwise;
 
-- 
1.7.9




More information about the AppArmor mailing list