Merge upstream sepolicy into AOSP

Change-Id: If3ed9998033378de5b47472315444f5b8bd4743e
diff --git a/Android.mk b/Android.mk
index 119c6ef..194dbf7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,6 +1,9 @@
 ifeq ($(HAVE_SELINUX),true)
 
 LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
 include $(CLEAR_VARS)
 
 # SELinux policy version.
@@ -20,6 +23,7 @@
 LOCAL_POLICY_PORT_CONTEXTS := $(wildcard $(addsuffix sepolicy.port_contexts, $(LOCAL_POLICY_DIRS)))
 LOCAL_POLICY_GENFS_CONTEXTS := $(wildcard $(addsuffix sepolicy.genfs_contexts, $(LOCAL_POLICY_DIRS)))
 LOCAL_POLICY_INITIAL_SID_CONTEXTS := $(wildcard $(addsuffix sepolicy.initial_sid_contexts, $(LOCAL_POLICY_DIRS)))
+LOCAL_POLICY_SC := $(wildcard $(addsuffix seapp_contexts, $(LOCAL_POLICY_DIRS)))
 
 ##################################
 include $(CLEAR_VARS)
@@ -60,17 +64,26 @@
 	$(hide) m4 -s $^ > $@
 
 file_contexts :=
+
 ##################################
 include $(CLEAR_VARS)
-
 LOCAL_MODULE := seapp_contexts
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
 
-include $(BUILD_PREBUILT)
+include $(BUILD_SYSTEM)/base_rules.mk
 
+seapp_contexts.tmp := $(intermediates)/seapp_contexts.tmp
+$(seapp_contexts.tmp): $(LOCAL_PATH)/seapp_contexts $(LOCAL_POLICY_SC)
+	@mkdir -p $(dir $@)
+	$(hide) m4 -s $^ > $@
+
+$(LOCAL_BUILT_MODULE) : $(seapp_contexts.tmp) $(TARGET_ROOT_OUT)/sepolicy.$(POLICYVERS) $(HOST_OUT_EXECUTABLES)/checkseapp
+	@mkdir -p $(dir $@)
+	$(HOST_OUT_EXECUTABLES)/checkseapp -p $(TARGET_ROOT_OUT)/sepolicy.24 -o $@ $<
+
+seapp_contexts.tmp :=
 ##################################
 include $(CLEAR_VARS)
 
diff --git a/check_seapp/Android.mk b/check_seapp/Android.mk
new file mode 100644
index 0000000..e4a4acc
--- /dev/null
+++ b/check_seapp/Android.mk
@@ -0,0 +1,15 @@
+##
+# checkseapp
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := checkseapp
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/../libsepol/include/ 
+LOCAL_CFLAGS := -DLINK_SEPOL_STATIC 
+LOCAL_SRC_FILES := check_seapp/check_seapp.c
+LOCAL_STATIC_LIBRARIES := libsepol
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/check_seapp/check_seapp.c b/check_seapp/check_seapp.c
new file mode 100644
index 0000000..5865bd0
--- /dev/null
+++ b/check_seapp/check_seapp.c
@@ -0,0 +1,968 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <search.h>
+#include <sepol/sepol.h>
+#include <sepol/policydb/policydb.h>
+
+#define TABLE_SIZE 1024
+#define KVP_NUM_OF_RULES (sizeof(rules) / sizeof(key_map))
+#define log_set_verbose() do { logging_verbose = 1; log_info("Enabling verbose\n"); } while(0)
+#define log_error(fmt, ...) log_msg(stderr, "Error: ", fmt, ##__VA_ARGS__)
+#define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__)
+#define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
+
+typedef struct line_order_list line_order_list;
+typedef struct hash_entry hash_entry;
+typedef enum key_dir key_dir;
+typedef enum data_type data_type;
+typedef enum rule_map_switch rule_map_switch;
+typedef enum map_match map_match;
+typedef struct key_map key_map;
+typedef struct kvp kvp;
+typedef struct rule_map rule_map;
+typedef struct policy_info policy_info;
+
+enum map_match {
+	map_no_matches,
+	map_input_matched,
+	map_matched
+};
+
+/**
+ * Whether or not the "key" from a key vaue pair is considered an
+ * input or an output.
+ */
+enum key_dir {
+	dir_in, dir_out
+};
+
+/**
+ * Used as options to rule_map_free()
+ *
+ * This is needed to get around the fact that GNU C's hash_map doesn't copy the key, so
+ * we cannot free a key when overrding rule_map's in the table.
+ */
+enum rule_map_switch {
+	rule_map_preserve_key, /** Used to preserve the key in the rule_map, ie don't free it*/
+	rule_map_destroy_key   /** Used when you need a full free of the rule_map structure*/
+};
+
+/**
+ * The expected "type" of data the value in the key
+ * value pair should be.
+ */
+enum data_type {
+	dt_bool, dt_string
+};
+
+/**
+ * This list is used to store a double pointer to each
+ * hash table / line rule combination. This way a replacement
+ * in the hash table automatically updates the list. The list
+ * is also used to keep "first encountered" ordering amongst
+ * the encountered key value pairs in the rules file.
+ */
+struct line_order_list {
+	hash_entry *e;
+	line_order_list *next;
+};
+
+/**
+ * The workhorse of the logic. This struct maps key value pairs to
+ * an associated set of meta data maintained in rule_map_new()
+ */
+struct key_map {
+	char *name;
+	key_dir dir;
+	data_type type;
+	char *data;
+};
+
+/**
+ * Key value pair struct, this represents the raw kvp values coming
+ * from the rules files.
+ */
+struct kvp {
+	char *key;
+	char *value;
+};
+
+/**
+ * Rules are made up of meta data and an associated set of kvp stored in a
+ * key_map array.
+ */
+struct rule_map {
+	char *key; /** key value before hashing */
+	int length; /** length of the key map */
+	int lineno; /** Line number rule was encounter on */
+	rule_map *next; /** next pointer used in hash table for chaining on collision */
+	key_map m[]; /** key value mapping */
+};
+
+struct hash_entry {
+	rule_map *r; /** The rule map to store at that location */
+};
+
+/**
+ * Data associated for a policy file
+ */
+struct policy_info {
+
+	char *policy_file_name; /** policy file path name */
+	FILE *policy_file;      /** file handle to the policy file */
+	sepol_policydb_t *db;
+	sepol_policy_file_t *pf;
+	sepol_handle_t *handle;
+	sepol_context_t *con;
+};
+
+/** Set to !0 to enable verbose logging */
+static int logging_verbose = 0;
+
+/** file handle to the output file */
+static FILE *output_file = NULL;
+
+/** file handle to the input file */
+static FILE *input_file = NULL;
+
+/** output file path name */
+static char *out_file_name = NULL;
+
+/** input file path name */
+static char *in_file_name = NULL;
+
+static policy_info pol = {
+	.policy_file_name = NULL,
+	.policy_file = NULL,
+	.db = NULL,
+	.pf = NULL,
+	.handle = NULL,
+	.con = NULL
+};
+
+/**
+ * The heart of the mapping process, this must be updated if a new key value pair is added
+ * to a rule.
+ */
+key_map rules[] = {
+                /*Inputs*/
+                { .name = "isSystemServer", .type = dt_bool,   .dir = dir_in,  .data = NULL },
+                { .name = "user",           .type = dt_string, .dir = dir_in,  .data = NULL },
+                { .name = "seinfo",         .type = dt_string, .dir = dir_in,  .data = NULL },
+                { .name = "name",           .type = dt_string, .dir = dir_in,  .data = NULL },
+                { .name = "sebool",         .type = dt_string, .dir = dir_in,  .data = NULL },
+                /*Outputs*/
+                { .name = "domain",         .type = dt_string, .dir = dir_out, .data = NULL },
+                { .name = "type",           .type = dt_string, .dir = dir_out, .data = NULL },
+                { .name = "levelFromUid",   .type = dt_bool,   .dir = dir_out, .data = NULL },
+                { .name = "level",          .type = dt_string, .dir = dir_out, .data = NULL },
+			};
+
+/**
+ * Head pointer to a linked list of
+ * rule map table entries, used for
+ * preserving the order of entries
+ * based on "first encounter"
+ */
+static line_order_list *list_head = NULL;
+
+/**
+ * Pointer to the tail of the list for
+ * quick appends to the end of the list
+ */
+static line_order_list *list_tail = NULL;
+
+/**
+ * Send a logging message to a file
+ * @param out
+ * 	Output file to send message too
+ * @param prefix
+ * 	A special prefix to write to the file, such as "Error:"
+ * @param fmt
+ * 	The printf style formatter to use, such as "%d"
+ */
+static void log_msg(FILE *out, const char *prefix, const char *fmt, ...) {
+	fprintf(out, "%s", prefix);
+	va_list args;
+	va_start(args, fmt);
+	vfprintf(out, fmt, args);
+	va_end(args);
+}
+
+/**
+ * Checks for a type in the policy.
+ * @param db
+ * 	The policy db to search
+ * @param type
+ * 	The type to search for
+ * @return
+ * 	1 if the type is found, 0 otherwise.
+ * @warning
+ * 	This function always returns 1 if libsepol is not linked
+ * 	statically to this executable and LINK_SEPOL_STATIC is not
+ * 	defined.
+ */
+int check_type(sepol_policydb_t *db, char *type) {
+
+	int rc = 1;
+#if defined(LINK_SEPOL_STATIC)
+	policydb_t *d = (policydb_t *)db;
+	hashtab_datum_t dat;
+	dat = hashtab_search(d->p_types.table, type);
+	rc = (dat == NULL) ? 0 : 1;
+#endif
+	return rc;
+}
+
+/**
+ * Validates a key_map against a set of enforcement rules, this
+ * function exits the application on a type that cannot be properly
+ * checked
+ *
+ * @param m
+ * 	The key map to check
+ * @param lineno
+ * 	The line number in the source file for the corresponding key map
+ */
+static int key_map_validate(key_map *m, int lineno) {
+
+	int rc = 1;
+	int ret = 1;
+	int resp;
+	char *key = m->name;
+	char *value = m->data;
+	data_type type = m->type;
+	sepol_bool_key_t *se_key;
+
+	log_info("Validating %s=%s\n", key, value);
+
+	 /* Booleans can always be checked for sanity */
+	if (type == dt_bool && (!strcmp("true", value) || !strcmp("false", value))) {
+		goto out;
+	}
+	else if (type == dt_bool) {
+		log_error("Expected boolean value got: %s=%s on line: %d in file: %s\n",
+				key, value, lineno, out_file_name);
+		rc = 0;
+		goto out;
+	}
+
+	/*
+	 * If their is no policy file present,
+	 * then it is not in strict mode so just return.
+	 * User and name cannot really be checked.
+	 */
+	if (!pol.policy_file) {
+		goto out;
+	}
+	else if (!strcasecmp(key, "sebool")) {
+
+		ret = sepol_bool_key_create(pol.handle, value, &se_key);
+		if (ret < 0) {
+			log_error("Could not create selinux boolean key, error: %s\n",
+					strerror(errno));
+			rc = 0;
+			goto out;
+		}
+
+		ret = sepol_bool_exists(pol.handle, pol.db, se_key, &resp);
+		if (ret < 0) {
+			log_error("Could not check selinux boolean, error: %s\n",
+					strerror(errno));
+			rc = 0;
+			goto bool_err;
+		}
+
+		if(!resp) {
+			log_error("Could not find selinux boolean \"%s\" on line: %d in file: %s\n",
+					value, lineno, out_file_name);
+			rc = 0;
+			goto bool_err;
+		}
+	}
+	else if (!strcasecmp(key, "type") || !strcasecmp(key, "domain")) {
+
+		if(!check_type(pol.db, value)) {
+			log_error("Could not find selinux type \"%s\" on line: %d in file: %s\n", value,
+					lineno, out_file_name);
+			rc = 0;
+		}
+		goto out;
+	}
+
+	else if (!strcasecmp(key, "level")) {
+
+		ret = sepol_mls_check(pol.handle, pol.db, value);
+		if (ret < 0) {
+			log_error("Could not find selinux level \"%s\", on line: %d in file: %s\n", value,
+					lineno, out_file_name);
+			rc = 0;
+			goto out;
+		}
+	}
+
+bool_err:
+	sepol_bool_key_free(se_key);
+
+out:
+	log_info("Key map validate returning: %d\n", rc);
+	return rc;
+}
+
+/**
+ * Prints a rule map back to a file
+ * @param fp
+ * 	The file handle to print too
+ * @param r
+ * 	The rule map to print
+ */
+static void rule_map_print(FILE *fp, rule_map *r) {
+
+	int i;
+	key_map *m;
+
+	for (i = 0; i < r->length; i++) {
+		m = &(r->m[i]);
+		if (i < r->length - 1)
+			fprintf(fp, "%s=%s ", m->name, m->data);
+		else
+			fprintf(fp, "%s=%s", m->name, m->data);
+	}
+}
+
+/**
+ * Compare two rule maps for equality
+ * @param rmA
+ * 	a rule map to check
+ * @param rmB
+ * 	a rule map to check
+ * @return
+ *  a map_match enum indicating the result
+ */
+static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) {
+
+	int i;
+	int j;
+	int inputs_found = 0;
+	int num_of_matched_inputs = 0;
+	int input_mode = 0;
+	int matches = 0;
+	key_map *mA;
+	key_map *mB;
+
+	if (rmA->length != rmB->length)
+		return map_no_matches;
+
+	for (i = 0; i < rmA->length; i++) {
+		mA = &(rmA->m[i]);
+
+		for (j = 0; j < rmB->length; j++) {
+			mB = &(rmB->m[j]);
+			input_mode = 0;
+
+			if (mA->type != mB->type)
+				continue;
+
+			if (strcmp(mA->name, mB->name))
+				continue;
+
+			if (strcmp(mA->data, mB->data))
+				continue;
+
+			if (mB->dir != mA->dir)
+				continue;
+			else if (mB->dir == dir_in) {
+				input_mode = 1;
+				inputs_found++;
+			}
+
+			if (input_mode) {
+				log_info("Matched input lines: type=%s name=%s data=%s dir=%d\n", mA->type, mA->name, mA->data, mA->dir);
+				num_of_matched_inputs++;
+			}
+
+			/* Match found, move on */
+			log_info("Matched lines: type=%s name=%s data=%s dir=%d\n", mA->type, mA->name, mA->data, mA->dir);
+			matches++;
+			break;
+		}
+	}
+
+	/* If they all matched*/
+	if (matches == rmA->length) {
+		log_info("Rule map cmp MATCH\n");
+		return map_matched;
+	}
+
+	/* They didn't all match but the input's did */
+	else if (num_of_matched_inputs == inputs_found) {
+		log_info("Rule map cmp INPUT MATCH\n");
+		return map_input_matched;
+	}
+
+	/* They didn't all match, and the inputs didn't match, ie it didn't
+	 * match */
+	else {
+		log_info("Rule map cmp NO MATCH\n");
+		return map_no_matches;
+	}
+}
+
+/**
+ * Frees a rule map
+ * @param rm
+ * 	rule map to be freed.
+ */
+static void rule_map_free(rule_map *rm, rule_map_switch s) {
+
+	int i;
+	int len = rm->length;
+	for (i = 0; i < len; i++) {
+		key_map *m = &(rm->m[i]);
+		free(m->data);
+	}
+
+	if(s == rule_map_destroy_key && rm->key)
+		free(rm->key);
+
+	free(rm);
+}
+
+static void free_kvp(kvp *k) {
+	free(k->key);
+	free(k->value);
+}
+
+/**
+ * Given a set of key value pairs, this will construct a new rule map.
+ * On error this function calls exit.
+ * @param keys
+ * 	Keys from a rule line to map
+ * @param num_of_keys
+ * 	The length of the keys array
+ * @param lineno
+ * 	The line number the keys were extracted from
+ * @return
+ * 	A rule map pointer.
+ */
+static rule_map *rule_map_new(kvp keys[], unsigned int num_of_keys, int lineno) {
+
+	unsigned int i = 0, j = 0;
+	rule_map *new_map = NULL;
+	kvp *k = NULL;
+	key_map *r = NULL, *x = NULL;
+
+	new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map));
+	if (!new_map)
+		goto oom;
+
+	new_map->length = num_of_keys;
+	new_map->lineno = lineno;
+
+	/* For all the keys in a rule line*/
+	for (i = 0; i < num_of_keys; i++) {
+		k = &(keys[i]);
+		r = &(new_map->m[i]);
+
+		for (j = 0; j < KVP_NUM_OF_RULES; j++) {
+			x = &(rules[j]);
+
+			/* Only assign key name to map name */
+			if (strcasecmp(k->key, x->name)) {
+				if (i == KVP_NUM_OF_RULES) {
+					log_error("No match for key: %s\n", k->key);
+					goto err;
+				}
+				continue;
+			}
+
+			memcpy(r, x, sizeof(key_map));
+
+			/* Assign rule map value to one from file */
+			r->data = strdup(k->value);
+			if (!r->data)
+				goto oom;
+
+			/* Enforce type check*/
+			log_info("Validating keys!\n");
+			if (!key_map_validate(r, lineno)) {
+				log_error("Could not validate\n");
+				goto err;
+			}
+
+			/* Only build key off of inputs*/
+			if (r->dir == dir_in) {
+				char *tmp;
+				int l = strlen(k->key);
+				l += strlen(k->value);
+				l += (new_map->key) ? strlen(new_map->key) : 0;
+				l += 1;
+
+				tmp = realloc(new_map->key, l);
+				if (!tmp)
+					goto oom;
+
+				new_map->key = tmp;
+
+				strcat(new_map->key, k->key);
+				strcat(new_map->key, k->value);
+			}
+			break;
+		}
+		free_kvp(k);
+	}
+
+	if (new_map->key == NULL) {
+		log_error("Strange, no keys found, input file corrupt perhaps?\n");
+		goto err;
+	}
+
+	return new_map;
+
+oom:
+	log_error("Out of memory!\n");
+err:
+	if(new_map) {
+		rule_map_free(new_map, rule_map_destroy_key);
+		for (; i < num_of_keys; i++) {
+			k = &(keys[i]);
+			free_kvp(k);
+		}
+	}
+	exit(EXIT_FAILURE);
+}
+
+/**
+ * Print the usage of the program
+ */
+static void usage() {
+	printf(
+	        "checkseapp [options] <input file>\n"
+		        "Processes an seapp_contexts file specified by argument <input file> (default stdin) "
+		        "and allows later declarations to override previous ones on a match.\n"
+		        "Options:\n"
+		        "-h - print this help message\n"
+		        "-v - enable verbose debugging informations\n"
+		        "-p policy file - specify policy file for strict checking of output selectors\n"
+		        "-o output file - specify output file, default is stdout\n");
+}
+
+static void init() {
+
+	/* If not set on stdin already */
+	if(!input_file) {
+		log_info("Opening input file: %s\n", in_file_name);
+		input_file = fopen(in_file_name, "r");
+		if (!input_file) {
+			log_error("Could not open file: %s error: %s\n", in_file_name, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* If not set on std out already */
+	if(!output_file) {
+		output_file = fopen(out_file_name, "w+");
+		if (!output_file) {
+			log_error("Could not open file: %s error: %s\n", out_file_name, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (pol.policy_file_name) {
+
+		log_info("Opening policy file: %s\n", pol.policy_file_name);
+		pol.policy_file = fopen(pol.policy_file_name, "rb");
+		if (!pol.policy_file) {
+			log_error("Could not open file: %s error: %s\n",
+					pol.policy_file_name, strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		pol.handle = sepol_handle_create();
+		if (!pol.handle) {
+			log_error("Could not create sepolicy handle: %s\n",
+					strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		if (sepol_policy_file_create(&pol.pf) < 0) {
+			log_error("Could not create sepolicy file: %s!\n",
+					strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		sepol_policy_file_set_fp(pol.pf, pol.policy_file);
+		sepol_policy_file_set_handle(pol.pf, pol.handle);
+
+		if (sepol_policydb_create(&pol.db) < 0) {
+			log_error("Could not create sepolicy db: %s!\n",
+					strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+
+		if (sepol_policydb_read(pol.db, pol.pf) < 0) {
+			log_error("Could not lod policy file to db: %s!\n",
+					strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	log_info("Policy file set to: %s\n", (pol.policy_file_name == NULL) ? "None" : pol.policy_file_name);
+	log_info("Input file set to: %s\n", (in_file_name == NULL) ? "stdin" : in_file_name);
+	log_info("Output file set to: %s\n", (out_file_name == NULL) ? "stdout" : out_file_name);
+
+#if !defined(LINK_SEPOL_STATIC)
+	log_warning("LINK_SEPOL_STATIC is not defined\n""Not checking types!");
+#endif
+
+}
+
+/**
+ * Handle parsing and setting the global flags for the command line
+ * options. This function calls exit on failure.
+ * @param argc
+ * 	argument count
+ * @param argv
+ * 	argument list
+ */
+static void handle_options(int argc, char *argv[]) {
+
+	int c;
+	int num_of_args;
+
+	while ((c = getopt(argc, argv, "ho:p:v")) != -1) {
+		switch (c) {
+		case 'h':
+			usage();
+			exit(EXIT_SUCCESS);
+		case 'o':
+			out_file_name = optarg;
+			break;
+		case 'p':
+			pol.policy_file_name = optarg;
+			break;
+		case 'v':
+			log_set_verbose();
+			break;
+		case '?':
+			if (optopt == 'o' || optopt == 'p')
+				log_error("Option -%c requires an argument.\n", optopt);
+			else if (isprint (optopt))
+				log_error("Unknown option `-%c'.\n", optopt);
+			else {
+				log_error(
+						"Unknown option character `\\x%x'.\n",
+						optopt);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		default:
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	num_of_args = argc - optind;
+
+	if (num_of_args > 1) {
+		log_error("Too many arguments, expected 0 or 1, argument, got %d\n", num_of_args);
+		usage();
+		exit(EXIT_FAILURE);
+	} else if (num_of_args == 1) {
+		in_file_name = argv[argc - 1];
+	} else {
+		input_file = stdin;
+		in_file_name = "stdin";
+	}
+
+	if (!out_file_name) {
+		output_file = stdout;
+		out_file_name = "stdout";
+	}
+}
+
+/**
+ * Adds a rule_map double pointer, ie the hash table pointer to the list.
+ * By using a double pointer, the hash table can have a line be overridden
+ * and the value is updated in the list. This function calls exit on failure.
+ * @param rm
+ * 	the rule_map to add.
+ */
+static void list_add(hash_entry *e) {
+
+	line_order_list *node = malloc(sizeof(line_order_list));
+	if (node == NULL)
+		goto oom;
+
+	node->next = NULL;
+	node->e = e;
+
+	if (list_head == NULL)
+		list_head = list_tail = node;
+	else {
+		list_tail->next = node;
+		list_tail = list_tail->next;
+	}
+	return;
+
+oom:
+	log_error("Out of memory!\n");
+	exit(EXIT_FAILURE);
+}
+
+/**
+ * Free's the rule map list, which ultimatley contains
+ * all the malloc'd rule_maps.
+ */
+static void list_free() {
+	line_order_list *cursor, *tmp;
+	hash_entry *e;
+
+	cursor = list_head;
+	while (cursor) {
+		e = cursor->e;
+		rule_map_free(e->r, rule_map_destroy_key);
+		tmp = cursor;
+		cursor = cursor->next;
+		free(e);
+		free(tmp);
+	}
+}
+
+/**
+ * Adds a rule to the hash table and to the ordered list if needed.
+ * @param rm
+ * 	The rule map to add.
+ */
+static void rule_add(rule_map *rm) {
+
+	map_match cmp;
+	ENTRY e;
+	ENTRY *f;
+	hash_entry *entry;
+	hash_entry *tmp;
+	char *preserved_key;
+
+	e.key = rm->key;
+
+	log_info("Searching for key: %s\n", e.key);
+	/* Check to see if it has already been added*/
+	f = hsearch(e, FIND);
+
+	/*
+	 * Since your only hashing on a partial key, the inputs we need to handle
+	 * when you want to override the outputs for a given input set, as well as
+	 * checking for duplicate entries.
+	 */
+	if(f) {
+		log_info("Existing entry found!\n");
+		tmp = (hash_entry *)f->data;
+		cmp = rule_map_cmp(rm, tmp->r);
+		log_info("Comparing on rule map ret: %d\n", cmp);
+		/* Override be freeing the old rule map and updating
+		   the pointer */
+		if(cmp != map_matched) {
+
+			/*
+			 * DO NOT free key pointers given to the hash map, instead
+			 * free the new key. The ordering here is critical!
+			 */
+			preserved_key = tmp->r->key;
+			rule_map_free(tmp->r, rule_map_preserve_key);
+			free(rm->key);
+			rm->key = preserved_key;
+			tmp->r = rm;
+		}
+		/* Duplicate */
+		else {
+			log_error("Duplicate line detected in file: %s\n"
+					"Lines %d and %d match!\n",
+					out_file_name, tmp->r->lineno, rm->lineno);
+			rule_map_free(rm, rule_map_destroy_key);
+			goto err;
+		}
+	}
+	/* It wasn't found, just add the rule map to the table */
+	else {
+
+		entry = malloc(sizeof(hash_entry));
+		if (!entry)
+			goto oom;
+
+		entry->r = rm;
+		e.data = entry;
+
+		f = hsearch(e, ENTER);
+		if(f == NULL) {
+			goto oom;
+		}
+
+		/* new entries must be added to the ordered list */
+		entry->r = rm;
+		list_add(entry);
+	}
+
+	return;
+oom:
+	if (e.key)
+		free(e.key);
+	if (entry)
+		free(entry);
+	if (rm)
+		free(rm);
+	log_error("Out of memory in function: %s\n", __FUNCTION__);
+err:
+	exit(EXIT_FAILURE);
+}
+
+/**
+ * Parses the seapp_contexts file and adds them to the
+ * hash table and ordered list entries when it encounters them.
+ * Calls exit on failure.
+ */
+static void parse() {
+
+	char line_buf[BUFSIZ];
+	char *token;
+	unsigned lineno = 0;
+	char *p, *name = NULL, *value = NULL, *saveptr;
+	size_t len;
+	kvp keys[KVP_NUM_OF_RULES];
+	int token_cnt = 0;
+
+	while (fgets(line_buf, sizeof line_buf - 1, input_file)) {
+
+		lineno++;
+		log_info("Got line %d\n", lineno);
+		len = strlen(line_buf);
+		if (line_buf[len - 1] == '\n')
+			line_buf[len - 1] = 0;
+		p = line_buf;
+		while (isspace(*p))
+			p++;
+		if (*p == '#' || *p == 0)
+			continue;
+
+		token = strtok_r(p, " \t", &saveptr);
+		if (!token)
+			goto err;
+
+		token_cnt = 0;
+		memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES);
+		while (1) {
+
+			name = token;
+			value = strchr(name, '=');
+			if (!value)
+				goto err;
+			*value++ = 0;
+
+			keys[token_cnt].key = strdup(name);
+			if (!keys[token_cnt].key)
+				goto oom;
+
+			keys[token_cnt].value = strdup(value);
+			if (!keys[token_cnt].value)
+				goto oom;
+
+			token_cnt++;
+
+			token = strtok_r(NULL, " \t", &saveptr);
+			if (!token)
+				break;
+
+		} /*End token parsing */
+
+		rule_map *r = rule_map_new(keys, token_cnt, lineno);
+		rule_add(r);
+
+	} /* End file parsing */
+	return;
+
+err:
+	log_error("reading %s, line %u, name %s, value %s\n",
+			in_file_name, lineno, name, value);
+	exit(EXIT_FAILURE);
+oom:
+	log_error("In function %s:  Out of memory\n", __FUNCTION__);
+	exit(EXIT_FAILURE);
+}
+
+/**
+ * Should be called after parsing to cause the printing of the rule_maps
+ * stored in the ordered list, head first, which preserves the "first encountered"
+ * ordering.
+ */
+static void output() {
+
+	rule_map *r;
+	line_order_list *cursor;
+	cursor = list_head;
+
+	while (cursor) {
+		r = cursor->e->r;
+		rule_map_print(output_file, r);
+		cursor = cursor->next;
+		fprintf(output_file, "\n");
+	}
+}
+
+/**
+ * This function is registered to the at exit handler and should clean up
+ * the programs dynamic resources, such as memory and fd's.
+ */
+static void cleanup() {
+
+	/* Only close this when it was opened by me and not the crt */
+	if (out_file_name && output_file) {
+		log_info("Closing file: %s\n", out_file_name);
+		fclose(output_file);
+	}
+
+	/* Only close this when it was opened by me  and not the crt */
+	if (in_file_name && input_file) {
+		log_info("Closing file: %s\n", in_file_name);
+		fclose(input_file);
+	}
+
+	if (pol.policy_file) {
+
+		log_info("Closing file: %s\n", pol.policy_file_name);
+		fclose(pol.policy_file);
+
+		if (pol.db)
+			sepol_policydb_free(pol.db);
+
+		if (pol.pf)
+			sepol_policy_file_free(pol.pf);
+
+		if (pol.handle)
+			sepol_handle_destroy(pol.handle);
+	}
+
+	log_info("Freeing list\n");
+	list_free();
+	hdestroy();
+}
+
+int main(int argc, char *argv[]) {
+	if (!hcreate(TABLE_SIZE)) {
+		log_error("Could not create hash table: %s\n", strerror(errno));
+		exit(EXIT_FAILURE);
+	}
+	atexit(cleanup);
+	handle_options(argc, argv);
+	init();
+	log_info("Starting to parse\n");
+	parse();
+	log_info("Parsing completed, generating output\n");
+	output();
+	log_info("Success, generated output\n");
+	exit(EXIT_SUCCESS);
+}
diff --git a/dhcp.te b/dhcp.te
new file mode 100644
index 0000000..b596479
--- /dev/null
+++ b/dhcp.te
@@ -0,0 +1,22 @@
+type dhcp, domain;
+type dhcp_exec, exec_type, file_type;
+type dhcp_data_file, file_type, data_file_type;
+type dhcp_system_file, file_type, data_file_type;
+
+init_daemon_domain(dhcp)
+
+allow dhcp cgroup:dir { create add_name };
+allow dhcp self:capability { setgid setuid net_admin net_raw };
+allow dhcp self:packet_socket { create setopt bind write read };
+allow dhcp self:netlink_route_socket { write nlmsg_write read create bind };
+allow dhcp self:udp_socket { create ioctl };
+allow dhcp shell_exec:file { read open execute };
+allow dhcp proc:file write;
+allow dhcp property_socket:sock_file write ;
+allow dhcp system_prop:property_service set ;
+allow dhcp dhcp_system_file:file rx_file_perms;
+allow dhcp dhcp_system_file:dir r_dir_perms;
+unix_socket_connect(dhcp, property, init)
+
+type_transition dhcp system_data_file:{ dir file } dhcp_data_file;
+allow dhcp dhcp_data_file:dir { write add_name search };
diff --git a/drmserver.te b/drmserver.te
index f30033a..63286d5 100644
--- a/drmserver.te
+++ b/drmserver.te
@@ -18,3 +18,4 @@
 allow drmserver drm_data_file:dir create_dir_perms;
 allow drmserver drm_data_file:file create_file_perms;
 allow drmserver self:{ tcp_socket udp_socket } *;
+allow drmserver tee_device:chr_file rw_file_perms;
diff --git a/file_contexts b/file_contexts
index ecf6e22..8876bfe 100644
--- a/file_contexts
+++ b/file_contexts
@@ -38,6 +38,7 @@
 /dev/mtd/mtd5ro		u:object_r:radio_device:s0
 /dev/mtp_usb		u:object_r:mtp_device:s0
 /dev/pn544		u:object_r:nfc_device:s0
+/dev/ppp		u:object_r:ppp_device:s0
 /dev/ptmx		u:object_r:ptmx_device:s0
 /dev/pvrsrvkm		u:object_r:powervr_device:s0
 /dev/qemu_.*		u:object_r:qemu_device:s0
@@ -71,6 +72,7 @@
 /dev/socket/zygote	u:object_r:zygote_socket:s0
 /dev/spdif_out.*	u:object_r:audio_device:s0
 /dev/tegra.*		u:object_r:video_device:s0
+/dev/tf_driver		u:object_r:tee_device:s0
 /dev/tty[0-9]*		u:object_r:tty_device:s0
 /dev/ttyS[0-9]*		u:object_r:serial_device:s0
 /dev/uinput		u:object_r:input_device:s0
@@ -102,6 +104,12 @@
 /system/bin/wpa_supplicant	u:object_r:wpa_exec:s0
 /system/bin/qemud	u:object_r:qemud_exec:s0
 /system/bin/sdcard      u:object_r:sdcardd_exec:s0
+/system/bin/dhcpcd      u:object_r:dhcp_exec:s0
+/system/bin/mtpd	u:object_r:mtp_exec:s0
+/system/bin/pppd	u:object_r:ppp_exec:s0
+/system/bin/tf_daemon	u:object_r:tee_exec:s0
+/system/etc/ppp(/.*)?	u:object_r:ppp_system_file:s0
+/system/etc/dhcpcd(/.*)? u:object_r:dhcp_system_file:s0
 /system/xbin/su		u:object_r:su_exec:s0
 /system/vendor/bin/gpsd u:object_r:gpsd_exec:s0
 #############################
@@ -124,6 +132,7 @@
 /data/misc/systemkeys(/.*)?	u:object_r:systemkeys_data_file:s0
 /data/misc/wifi(/.*)?		u:object_r:wifi_data_file:s0
 /data/misc/camera(/.*)?	u:object_r:camera_calibration_file:s0
+/data/misc/dhcp(/.*)?           u:object_r:dhcp_data_file:s0
 # App sandboxes
 /data/data/.*		u:object_r:app_data_file:s0
 # Wallpaper file.
diff --git a/gpsd.te b/gpsd.te
index bc2893d..8010efa 100644
--- a/gpsd.te
+++ b/gpsd.te
@@ -12,3 +12,5 @@
 allow gpsd gps_socket:sock_file create_file_perms;
 # XXX Label sysfs files with a specific type?
 allow gpsd sysfs:file rw_file_perms;
+
+allow gpsd gps_device:chr_file rw_file_perms;
diff --git a/keystore.te b/keystore.te
index 6c4d610..20e7222 100644
--- a/keystore.te
+++ b/keystore.te
@@ -6,3 +6,4 @@
 allow keystore keystore_data_file:dir create_dir_perms;
 allow keystore keystore_data_file:notdevfile_class_set create_file_perms;
 allow keystore keystore_exec:file { getattr };
+allow keystore tee_device:chr_file rw_file_perms;
diff --git a/mediaserver.te b/mediaserver.te
index c8adf3a..e124db0 100644
--- a/mediaserver.te
+++ b/mediaserver.te
@@ -42,3 +42,5 @@
 allow mediaserver qtaguid_device:chr_file r_file_perms;
 # Allow abstract socket connection
 allow mediaserver rild:unix_stream_socket connectto;
+
+allow mediaserver tee_device:chr_file rw_file_perms;
diff --git a/mtp.te b/mtp.te
new file mode 100644
index 0000000..4fc04b6
--- /dev/null
+++ b/mtp.te
@@ -0,0 +1,13 @@
+# vpn tunneling protocol manager
+type mtp, domain;
+type mtp_exec, exec_type, file_type;
+
+init_daemon_domain(mtp)
+
+# pptp policy
+allow mtp self:tcp_socket { create setopt connect write read };
+allow mtp self:socket { create connect };
+allow mtp self:rawip_socket create;
+allow mtp self:capability net_raw;
+allow mtp ppp:process signal;
+allow mtp port:tcp_socket name_connect;
diff --git a/ppp.te b/ppp.te
new file mode 100644
index 0000000..115fb98
--- /dev/null
+++ b/ppp.te
@@ -0,0 +1,17 @@
+# Point to Point Protocol daemon
+type ppp, domain;
+type ppp_device, dev_type;
+type ppp_exec, exec_type, file_type;
+type ppp_system_file, file_type;
+
+domain_auto_trans(mtp, ppp_exec, ppp)
+
+allow ppp mtp:socket { read write ioctl };
+allow ppp ppp_device:chr_file rw_file_perms;
+allow ppp self:capability net_admin;
+allow ppp self:udp_socket { create ioctl };
+allow ppp ppp_system_file:dir search;
+allow ppp ppp_system_file:file rx_file_perms;
+allow ppp vpn_data_file:dir w_dir_perms;
+allow ppp vpn_data_file:file create_file_perms;
+allow ppp mtp:fd use;
diff --git a/system.te b/system.te
index 0740285..557a385 100644
--- a/system.te
+++ b/system.te
@@ -206,3 +206,6 @@
 allow system appdomain:udp_socket { read write };
 # Allow abstract socket connection
 allow system rild:unix_stream_socket connectto;
+
+# connect to vpn tunnel
+allow system mtp:unix_stream_socket { connectto };
diff --git a/tee.te b/tee.te
new file mode 100644
index 0000000..ce4e2b6
--- /dev/null
+++ b/tee.te
@@ -0,0 +1,13 @@
+##
+# trusted execution environment (tee) daemon
+#
+type tee, domain;
+type tee_exec, exec_type, file_type;
+type tee_device, dev_type;
+type tee_data_file, file_type, data_file_type;
+
+init_daemon_domain(tee)
+allow tee self:capability { dac_override };
+allow tee tee_device:chr_file rw_file_perms;
+allow tee tee_data_file:dir { getattr write add_name };
+allow tee tee_data_file:file create_file_perms;