Browse Source

apparmor: add a default null dfa

Instead of testing whether a given dfa exists in every code path, have
a default null dfa that is used when loaded policy doesn't provide a
dfa.

This will let us get rid of special casing and avoid dereference bugs
when special casing is missed.

Signed-off-by: John Johansen <john.johansen@canonical.com>
John Johansen 8 years ago
parent
commit
11c236b89d

+ 5 - 0
security/apparmor/include/match.h

@@ -100,6 +100,8 @@ struct aa_dfa {
 	struct table_header *tables[YYTD_ID_TSIZE];
 };
 
+extern struct aa_dfa *nulldfa;
+
 #define byte_to_byte(X) (X)
 
 #define UNPACK_ARRAY(TABLE, BLOB, LEN, TYPE, NTOHX) \
@@ -117,6 +119,9 @@ static inline size_t table_size(size_t len, size_t el_size)
 	return ALIGN(sizeof(struct table_header) + len * el_size, 8);
 }
 
+int aa_setup_dfa_engine(void);
+void aa_teardown_dfa_engine(void);
+
 struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags);
 unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
 			      const char *str, int len);

+ 7 - 0
security/apparmor/lsm.c

@@ -878,6 +878,12 @@ static int __init apparmor_init(void)
 		return 0;
 	}
 
+	error = aa_setup_dfa_engine();
+	if (error) {
+		AA_ERROR("Unable to setup dfa engine\n");
+		goto alloc_out;
+	}
+
 	error = aa_alloc_root_ns();
 	if (error) {
 		AA_ERROR("Unable to allocate default profile namespace\n");
@@ -905,6 +911,7 @@ static int __init apparmor_init(void)
 
 alloc_out:
 	aa_destroy_aafs();
+	aa_teardown_dfa_engine();
 
 	apparmor_enabled = 0;
 	return error;

+ 27 - 0
security/apparmor/match.c

@@ -25,6 +25,33 @@
 
 #define base_idx(X) ((X) & 0xffffff)
 
+static char nulldfa_src[] = {
+	#include "nulldfa.in"
+};
+struct aa_dfa *nulldfa;
+
+int aa_setup_dfa_engine(void)
+{
+	int error;
+
+	nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
+				TO_ACCEPT1_FLAG(YYTD_DATA32) |
+				TO_ACCEPT2_FLAG(YYTD_DATA32));
+	if (!IS_ERR(nulldfa))
+		return 0;
+
+	error = PTR_ERR(nulldfa);
+	nulldfa = NULL;
+
+	return error;
+}
+
+void aa_teardown_dfa_engine(void)
+{
+	aa_put_dfa(nulldfa);
+	nulldfa = NULL;
+}
+
 /**
  * unpack_table - unpack a dfa table (one of accept, default, base, next check)
  * @blob: data to unpack (NOT NULL)

File diff suppressed because it is too large
+ 0 - 0
security/apparmor/nulldfa.in


+ 2 - 0
security/apparmor/policy.c

@@ -348,6 +348,8 @@ name:
 	/* released on free_profile */
 	rcu_assign_pointer(profile->parent, aa_get_profile(parent));
 	profile->ns = aa_get_ns(parent->ns);
+	profile->file.dfa = aa_get_dfa(nulldfa);
+	profile->policy.dfa = aa_get_dfa(nulldfa);
 
 	mutex_lock(&profile->ns->lock);
 	__list_add_profile(&parent->base.profiles, profile);

+ 4 - 2
security/apparmor/policy_unpack.c

@@ -603,7 +603,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
 		}
 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
 			goto fail;
-	}
+	} else
+		profile->policy.dfa = aa_get_dfa(nulldfa);
 
 	/* get file rules */
 	profile->file.dfa = unpack_dfa(e);
@@ -619,7 +620,8 @@ static struct aa_profile *unpack_profile(struct aa_ext *e)
 		   profile->policy.start[AA_CLASS_FILE]) {
 		profile->file.dfa = aa_get_dfa(profile->policy.dfa);
 		profile->file.start = profile->policy.start[AA_CLASS_FILE];
-	}
+	} else
+		profile->file.dfa = aa_get_dfa(nulldfa);
 
 	if (!unpack_trans_table(e, profile))
 		goto fail;

Some files were not shown because too many files changed in this diff