Ensure vendor seapp contexts can't use coredomain

Bug: 280547417
Test: build
Change-Id: Iadff17523767f91f073c6569400e17f1da55fbdc
diff --git a/tools/check_seapp.c b/tools/check_seapp.c
index 0d7a4d1..862ecce 100644
--- a/tools/check_seapp.c
+++ b/tools/check_seapp.c
@@ -21,6 +21,7 @@
 #define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
 
 #define APP_DATA_REQUIRED_ATTRIB "app_data_file_type"
+#define COREDOMAIN "coredomain"
 
 /**
  * Initializes an empty, static list.
@@ -61,6 +62,7 @@
 typedef struct list list;
 typedef struct key_map_regex key_map_regex;
 typedef struct file_info file_info;
+typedef struct coredomain_violation_entry coredomain_violation_entry;
 
 enum map_match {
 	map_no_matches,
@@ -106,7 +108,7 @@
 	key_dir dir;
 	char *data;
 	key_map_regex regex;
-	bool (*fn_validate)(char *value, char **errmsg);
+	bool (*fn_validate)(char *value, const char *filename, int lineno, char **errmsg);
 };
 
 /**
@@ -149,6 +151,7 @@
 	sepol_policy_file_t *pf;
 	sepol_handle_t *handle;
 	sepol_context_t *con;
+	bool vendor;
 };
 
 struct file_info {
@@ -157,6 +160,14 @@
 	list_element listify;
 };
 
+struct coredomain_violation_entry {
+	list_element listify;
+	char *domain;
+	char *filename;
+	int lineno;
+};
+
+static void coredomain_violation_list_freefn(list_element *e);
 static void input_file_list_freefn(list_element *e);
 static void line_order_list_freefn(list_element *e);
 static void rule_map_free(rule_map *rm, bool is_in_htable);
@@ -169,13 +180,16 @@
 
 static list input_file_list = list_init(input_file_list_freefn);
 
+static list coredomain_violation_list = list_init(coredomain_violation_list_freefn);
+
 static policy_info pol = {
 	.policy_file_name = NULL,
 	.policy_file = NULL,
 	.db = NULL,
 	.pf = NULL,
 	.handle = NULL,
-	.con = NULL
+	.con = NULL,
+	.vendor = false
 };
 
 /**
@@ -192,12 +206,12 @@
 static list nallow_list = list_init(line_order_list_freefn);
 
 /* validation call backs */
-static bool validate_bool(char *value, char **errmsg);
-static bool validate_levelFrom(char *value, char **errmsg);
-static bool validate_domain(char *value, char **errmsg);
-static bool validate_type(char *value, char **errmsg);
-static bool validate_selinux_level(char *value, char **errmsg);
-static bool validate_uint(char *value, char **errmsg);
+static bool validate_bool(char *value, const char *filename, int lineno, char **errmsg);
+static bool validate_levelFrom(char *value, const char *filename, int lineno, char **errmsg);
+static bool validate_domain(char *value, const char *filename, int lineno, char **errmsg);
+static bool validate_type(char *value, const char *filename, int lineno, char **errmsg);
+static bool validate_selinux_level(char *value, const char *filename, int lineno, char **errmsg);
+static bool validate_uint(char *value, const char *filename, int lineno, char **errmsg);
 
 /**
  * The heart of the mapping process, this must be updated if a new key value pair is added
@@ -278,6 +292,14 @@
 	free(f);
 }
 
+static void coredomain_violation_list_freefn(list_element *e) {
+	coredomain_violation_entry *c = list_entry(e, typeof(*c), listify);
+
+	free(c->domain);
+	free(c->filename);
+	free(c);
+}
+
 /**
  * Send a logging message to a file
  * @param out
@@ -377,8 +399,11 @@
 	return true;
 }
 
-static bool validate_bool(char *value, char **errmsg) {
-
+static bool validate_bool(
+		char *value,
+		__attribute__ ((unused)) const char *filename,
+		__attribute__ ((unused)) int lineno,
+		char **errmsg) {
 	if (!strcmp("true", value) || !strcmp("false", value)) {
 		return true;
 	}
@@ -387,8 +412,11 @@
 	return false;
 }
 
-static bool validate_levelFrom(char *value, char **errmsg) {
-
+static bool validate_levelFrom(
+		char *value,
+		__attribute__ ((unused)) const char *filename,
+		__attribute__ ((unused)) int lineno,
+		char **errmsg) {
 	if (strcasecmp(value, "none") && strcasecmp(value, "all") &&
 		strcasecmp(value, "app") && strcasecmp(value, "user")) {
 		*errmsg = "Expecting one of: \"none\", \"all\", \"app\" or \"user\"";
@@ -397,7 +425,7 @@
 	return true;
 }
 
-static bool validate_domain(char *value, char **errmsg) {
+static bool validate_domain(char *value, const char *filename, int lineno, char **errmsg) {
 
 #if defined(LINK_SEPOL_STATIC)
 	/*
@@ -408,17 +436,37 @@
 		return true;
 	}
 
-	if (!find_type(pol.db, value, TYPE_TYPE)) {
+	type_datum_t *type_dat = find_type(pol.db, value, TYPE_TYPE);
+	if (!type_dat) {
 		*errmsg = "Expecting a valid SELinux type";
 		return false;
 	}
+
+	if (pol.vendor) {
+		type_datum_t *attrib_dat = find_type(pol.db, COREDOMAIN, TYPE_ATTRIB);
+		if (!attrib_dat) {
+			*errmsg = "The attribute " COREDOMAIN " is not defined in the policy";
+			return false;
+		}
+
+		if (type_has_attribute(pol.db, type_dat, attrib_dat)) {
+			coredomain_violation_entry *entry = (coredomain_violation_entry *)malloc(sizeof(*entry));
+			entry->domain = strdup(value);
+			entry->filename = strdup(filename);
+			entry->lineno = lineno;
+			list_append(&coredomain_violation_list, &entry->listify);
+		}
+	}
 #endif
 
 	return true;
 }
 
-static bool validate_type(char *value, char **errmsg) {
-
+static bool validate_type(
+		char *value,
+		__attribute__ ((unused)) const char *filename,
+		__attribute__ ((unused)) int lineno,
+		char **errmsg) {
 #if defined(LINK_SEPOL_STATIC)
 	/*
 	 * No policy file present means we cannot check
@@ -451,8 +499,11 @@
 	return true;
 }
 
-static bool validate_selinux_level(char *value, char **errmsg) {
-
+static bool validate_selinux_level(
+		char *value,
+		__attribute__ ((unused)) const char *filename,
+		__attribute__ ((unused)) int lineno,
+		char **errmsg) {
 	/*
 	 * No policy file present means we cannot check
 	 * SE Linux MLS
@@ -470,8 +521,11 @@
 	return true;
 }
 
-static bool validate_uint(char *value, char **errmsg) {
-
+static bool validate_uint(
+		char *value,
+		__attribute__ ((unused)) const char *filename,
+		__attribute__ ((unused)) int lineno,
+		char **errmsg) {
 	char *endptr;
 	long longvalue;
 	longvalue = strtol(value, &endptr, 10);
@@ -528,7 +582,7 @@
 
 	/* If the key has a validation routine, call it */
 	if (m->fn_validate) {
-		rc = m->fn_validate(value, &errmsg);
+		rc = m->fn_validate(value, filename, lineno, &errmsg);
 
 		if (!rc) {
 			log_error("Could not validate key \"%s\" for value \"%s\" on line: %d in file: \"%s\": %s\n", key, value,
@@ -996,7 +1050,7 @@
 	int c;
 	file_info *input_file;
 
-	while ((c = getopt(argc, argv, "ho:p:v")) != -1) {
+	while ((c = getopt(argc, argv, "ho:p:vc")) != -1) {
 		switch (c) {
 		case 'h':
 			usage();
@@ -1010,6 +1064,9 @@
 		case 'v':
 			log_set_verbose();
 			break;
+		case 'c':
+			pol.vendor = true;
+			break;
 		case '?':
 			if (optopt == 'o' || optopt == 'p')
 				log_error("Option -%c requires an argument.\n", optopt);
@@ -1228,6 +1285,7 @@
 	bool found_issues = false;
 	hash_entry *e;
 	rule_map *r;
+	coredomain_violation_entry *c;
 	list_for_each(&line_order_list, cursor) {
 		e = list_entry(cursor, typeof(*e), listify);
 		rule_map_validate(e->r);
@@ -1247,6 +1305,12 @@
 		}
 	}
 
+	list_for_each(&coredomain_violation_list, cursor) {
+		c = list_entry(cursor, typeof(*c), listify);
+		fprintf(stderr, "Forbidden attribute " COREDOMAIN " assigned to domain \"%s\" in "
+                        "File \"%s\" on line %d\n", c->domain, c->filename, c->lineno);
+	}
+
 	if (found_issues) {
 		exit(EXIT_FAILURE);
 	}
@@ -1305,6 +1369,7 @@
 	list_free(&input_file_list);
 	list_free(&line_order_list);
 	list_free(&nallow_list);
+	list_free(&coredomain_violation_list);
 	hdestroy();
 }