xref: /aosp_15_r20/system/sepolicy/tools/check_seapp.c (revision e4a36f4174b17bbab9dc043f4a65dc8d87377290)
1*e4a36f41SAndroid Build Coastguard Worker #include <stdio.h>
2*e4a36f41SAndroid Build Coastguard Worker #include <stdarg.h>
3*e4a36f41SAndroid Build Coastguard Worker #include <ctype.h>
4*e4a36f41SAndroid Build Coastguard Worker #include <stdio.h>
5*e4a36f41SAndroid Build Coastguard Worker #include <stdlib.h>
6*e4a36f41SAndroid Build Coastguard Worker #include <unistd.h>
7*e4a36f41SAndroid Build Coastguard Worker #include <string.h>
8*e4a36f41SAndroid Build Coastguard Worker #include <errno.h>
9*e4a36f41SAndroid Build Coastguard Worker #include <stdint.h>
10*e4a36f41SAndroid Build Coastguard Worker #include <search.h>
11*e4a36f41SAndroid Build Coastguard Worker #include <stdbool.h>
12*e4a36f41SAndroid Build Coastguard Worker #include <sepol/sepol.h>
13*e4a36f41SAndroid Build Coastguard Worker #include <sepol/policydb/policydb.h>
14*e4a36f41SAndroid Build Coastguard Worker #include <pcre2.h>
15*e4a36f41SAndroid Build Coastguard Worker 
16*e4a36f41SAndroid Build Coastguard Worker #define TABLE_SIZE 1024
17*e4a36f41SAndroid Build Coastguard Worker #define KVP_NUM_OF_RULES (sizeof(rules) / sizeof(key_map))
18*e4a36f41SAndroid Build Coastguard Worker #define log_set_verbose() do { logging_verbose = 1; log_info("Enabling verbose\n"); } while(0)
19*e4a36f41SAndroid Build Coastguard Worker #define log_error(fmt, ...) log_msg(stderr, "Error: ", fmt, ##__VA_ARGS__)
20*e4a36f41SAndroid Build Coastguard Worker #define log_warn(fmt, ...) log_msg(stderr, "Warning: ", fmt, ##__VA_ARGS__)
21*e4a36f41SAndroid Build Coastguard Worker #define log_info(fmt, ...) if (logging_verbose ) { log_msg(stdout, "Info: ", fmt, ##__VA_ARGS__); }
22*e4a36f41SAndroid Build Coastguard Worker 
23*e4a36f41SAndroid Build Coastguard Worker #define APP_DATA_REQUIRED_ATTRIB "app_data_file_type"
24*e4a36f41SAndroid Build Coastguard Worker #define COREDOMAIN "coredomain"
25*e4a36f41SAndroid Build Coastguard Worker 
26*e4a36f41SAndroid Build Coastguard Worker /**
27*e4a36f41SAndroid Build Coastguard Worker  * Initializes an empty, static list.
28*e4a36f41SAndroid Build Coastguard Worker  */
29*e4a36f41SAndroid Build Coastguard Worker #define list_init(free_fn) { .head = NULL, .tail = NULL, .freefn = (free_fn) }
30*e4a36f41SAndroid Build Coastguard Worker 
31*e4a36f41SAndroid Build Coastguard Worker /**
32*e4a36f41SAndroid Build Coastguard Worker  * given an item in the list, finds the offset for the container
33*e4a36f41SAndroid Build Coastguard Worker  * it was stored in.
34*e4a36f41SAndroid Build Coastguard Worker  *
35*e4a36f41SAndroid Build Coastguard Worker  * @element The element from the list
36*e4a36f41SAndroid Build Coastguard Worker  * @type The container type ie what you allocated that has the list_element structure in it.
37*e4a36f41SAndroid Build Coastguard Worker  * @name The name of the field that is the list_element
38*e4a36f41SAndroid Build Coastguard Worker  *
39*e4a36f41SAndroid Build Coastguard Worker  */
40*e4a36f41SAndroid Build Coastguard Worker #define list_entry(element, type, name) \
41*e4a36f41SAndroid Build Coastguard Worker 		(type *)(((uint8_t *)(element)) - (uint8_t *)&(((type *)NULL)->name))
42*e4a36f41SAndroid Build Coastguard Worker 
43*e4a36f41SAndroid Build Coastguard Worker /**
44*e4a36f41SAndroid Build Coastguard Worker  * Iterates over the list, do not free elements from the list when using this.
45*e4a36f41SAndroid Build Coastguard Worker  * @list The list head to walk
46*e4a36f41SAndroid Build Coastguard Worker  * @var The variable name for the cursor
47*e4a36f41SAndroid Build Coastguard Worker  */
48*e4a36f41SAndroid Build Coastguard Worker #define list_for_each(list, var) \
49*e4a36f41SAndroid Build Coastguard Worker 	for(var = (list)->head; var != NULL; var = var->next) /*NOLINT*/
50*e4a36f41SAndroid Build Coastguard Worker 
51*e4a36f41SAndroid Build Coastguard Worker 
52*e4a36f41SAndroid Build Coastguard Worker typedef struct hash_entry hash_entry;
53*e4a36f41SAndroid Build Coastguard Worker typedef enum key_dir key_dir;
54*e4a36f41SAndroid Build Coastguard Worker typedef enum data_type data_type;
55*e4a36f41SAndroid Build Coastguard Worker typedef enum rule_map_switch rule_map_switch;
56*e4a36f41SAndroid Build Coastguard Worker typedef enum map_match map_match;
57*e4a36f41SAndroid Build Coastguard Worker typedef struct key_map key_map;
58*e4a36f41SAndroid Build Coastguard Worker typedef struct kvp kvp;
59*e4a36f41SAndroid Build Coastguard Worker typedef struct rule_map rule_map;
60*e4a36f41SAndroid Build Coastguard Worker typedef struct policy_info policy_info;
61*e4a36f41SAndroid Build Coastguard Worker typedef struct list_element list_element;
62*e4a36f41SAndroid Build Coastguard Worker typedef struct list list;
63*e4a36f41SAndroid Build Coastguard Worker typedef struct key_map_regex key_map_regex;
64*e4a36f41SAndroid Build Coastguard Worker typedef struct file_info file_info;
65*e4a36f41SAndroid Build Coastguard Worker typedef struct coredomain_violation_entry coredomain_violation_entry;
66*e4a36f41SAndroid Build Coastguard Worker 
67*e4a36f41SAndroid Build Coastguard Worker enum map_match {
68*e4a36f41SAndroid Build Coastguard Worker 	map_no_matches,
69*e4a36f41SAndroid Build Coastguard Worker 	map_input_matched,
70*e4a36f41SAndroid Build Coastguard Worker 	map_matched
71*e4a36f41SAndroid Build Coastguard Worker };
72*e4a36f41SAndroid Build Coastguard Worker 
73*e4a36f41SAndroid Build Coastguard Worker const char *map_match_str[] = {
74*e4a36f41SAndroid Build Coastguard Worker 	"do not match",
75*e4a36f41SAndroid Build Coastguard Worker 	"match on all inputs",
76*e4a36f41SAndroid Build Coastguard Worker 	"match on everything"
77*e4a36f41SAndroid Build Coastguard Worker };
78*e4a36f41SAndroid Build Coastguard Worker 
79*e4a36f41SAndroid Build Coastguard Worker /**
80*e4a36f41SAndroid Build Coastguard Worker  * Whether or not the "key" from a key vaue pair is considered an
81*e4a36f41SAndroid Build Coastguard Worker  * input or an output.
82*e4a36f41SAndroid Build Coastguard Worker  */
83*e4a36f41SAndroid Build Coastguard Worker enum key_dir {
84*e4a36f41SAndroid Build Coastguard Worker 	dir_in, dir_out
85*e4a36f41SAndroid Build Coastguard Worker };
86*e4a36f41SAndroid Build Coastguard Worker 
87*e4a36f41SAndroid Build Coastguard Worker struct list_element {
88*e4a36f41SAndroid Build Coastguard Worker 	list_element *next;
89*e4a36f41SAndroid Build Coastguard Worker };
90*e4a36f41SAndroid Build Coastguard Worker 
91*e4a36f41SAndroid Build Coastguard Worker struct list {
92*e4a36f41SAndroid Build Coastguard Worker 	list_element *head;
93*e4a36f41SAndroid Build Coastguard Worker 	list_element *tail;
94*e4a36f41SAndroid Build Coastguard Worker 	void (*freefn)(list_element *e);
95*e4a36f41SAndroid Build Coastguard Worker };
96*e4a36f41SAndroid Build Coastguard Worker 
97*e4a36f41SAndroid Build Coastguard Worker struct key_map_regex {
98*e4a36f41SAndroid Build Coastguard Worker 	pcre2_code *compiled;
99*e4a36f41SAndroid Build Coastguard Worker 	pcre2_match_data *match_data;
100*e4a36f41SAndroid Build Coastguard Worker };
101*e4a36f41SAndroid Build Coastguard Worker 
102*e4a36f41SAndroid Build Coastguard Worker /**
103*e4a36f41SAndroid Build Coastguard Worker  * The workhorse of the logic. This struct maps key value pairs to
104*e4a36f41SAndroid Build Coastguard Worker  * an associated set of meta data maintained in rule_map_new()
105*e4a36f41SAndroid Build Coastguard Worker  */
106*e4a36f41SAndroid Build Coastguard Worker struct key_map {
107*e4a36f41SAndroid Build Coastguard Worker 	char *name;
108*e4a36f41SAndroid Build Coastguard Worker 	key_dir dir;
109*e4a36f41SAndroid Build Coastguard Worker 	char *data;
110*e4a36f41SAndroid Build Coastguard Worker 	key_map_regex regex;
111*e4a36f41SAndroid Build Coastguard Worker 	bool (*fn_validate)(char *value, const char *filename, int lineno, char **errmsg);
112*e4a36f41SAndroid Build Coastguard Worker };
113*e4a36f41SAndroid Build Coastguard Worker 
114*e4a36f41SAndroid Build Coastguard Worker /**
115*e4a36f41SAndroid Build Coastguard Worker  * Key value pair struct, this represents the raw kvp values coming
116*e4a36f41SAndroid Build Coastguard Worker  * from the rules files.
117*e4a36f41SAndroid Build Coastguard Worker  */
118*e4a36f41SAndroid Build Coastguard Worker struct kvp {
119*e4a36f41SAndroid Build Coastguard Worker 	char *key;
120*e4a36f41SAndroid Build Coastguard Worker 	char *value;
121*e4a36f41SAndroid Build Coastguard Worker };
122*e4a36f41SAndroid Build Coastguard Worker 
123*e4a36f41SAndroid Build Coastguard Worker /**
124*e4a36f41SAndroid Build Coastguard Worker  * Rules are made up of meta data and an associated set of kvp stored in a
125*e4a36f41SAndroid Build Coastguard Worker  * key_map array.
126*e4a36f41SAndroid Build Coastguard Worker  */
127*e4a36f41SAndroid Build Coastguard Worker struct rule_map {
128*e4a36f41SAndroid Build Coastguard Worker 	bool is_never_allow;
129*e4a36f41SAndroid Build Coastguard Worker 	list violations;
130*e4a36f41SAndroid Build Coastguard Worker 	list_element listify;
131*e4a36f41SAndroid Build Coastguard Worker 	char *key; /** key value before hashing */
132*e4a36f41SAndroid Build Coastguard Worker 	size_t length; /** length of the key map */
133*e4a36f41SAndroid Build Coastguard Worker 	int lineno; /** Line number rule was encounter on */
134*e4a36f41SAndroid Build Coastguard Worker 	char *filename; /** File it was found in */
135*e4a36f41SAndroid Build Coastguard Worker 	key_map m[]; /** key value mapping */
136*e4a36f41SAndroid Build Coastguard Worker };
137*e4a36f41SAndroid Build Coastguard Worker 
138*e4a36f41SAndroid Build Coastguard Worker struct hash_entry {
139*e4a36f41SAndroid Build Coastguard Worker 	list_element listify;
140*e4a36f41SAndroid Build Coastguard Worker 	rule_map *r; /** The rule map to store at that location */
141*e4a36f41SAndroid Build Coastguard Worker };
142*e4a36f41SAndroid Build Coastguard Worker 
143*e4a36f41SAndroid Build Coastguard Worker /**
144*e4a36f41SAndroid Build Coastguard Worker  * Data associated for a policy file
145*e4a36f41SAndroid Build Coastguard Worker  */
146*e4a36f41SAndroid Build Coastguard Worker struct policy_info {
147*e4a36f41SAndroid Build Coastguard Worker 
148*e4a36f41SAndroid Build Coastguard Worker 	char *policy_file_name; /** policy file path name */
149*e4a36f41SAndroid Build Coastguard Worker 	FILE *policy_file;      /** file handle to the policy file */
150*e4a36f41SAndroid Build Coastguard Worker 	sepol_policydb_t *db;
151*e4a36f41SAndroid Build Coastguard Worker 	sepol_policy_file_t *pf;
152*e4a36f41SAndroid Build Coastguard Worker 	sepol_handle_t *handle;
153*e4a36f41SAndroid Build Coastguard Worker 	sepol_context_t *con;
154*e4a36f41SAndroid Build Coastguard Worker 	bool vendor;
155*e4a36f41SAndroid Build Coastguard Worker };
156*e4a36f41SAndroid Build Coastguard Worker 
157*e4a36f41SAndroid Build Coastguard Worker struct file_info {
158*e4a36f41SAndroid Build Coastguard Worker 	FILE *file; /** file itself */
159*e4a36f41SAndroid Build Coastguard Worker 	const char *name; /** name of file. do not free, these are not alloc'd */
160*e4a36f41SAndroid Build Coastguard Worker 	list_element listify;
161*e4a36f41SAndroid Build Coastguard Worker };
162*e4a36f41SAndroid Build Coastguard Worker 
163*e4a36f41SAndroid Build Coastguard Worker struct coredomain_violation_entry {
164*e4a36f41SAndroid Build Coastguard Worker 	list_element listify;
165*e4a36f41SAndroid Build Coastguard Worker 	char *domain;
166*e4a36f41SAndroid Build Coastguard Worker 	char *filename;
167*e4a36f41SAndroid Build Coastguard Worker 	int lineno;
168*e4a36f41SAndroid Build Coastguard Worker };
169*e4a36f41SAndroid Build Coastguard Worker 
170*e4a36f41SAndroid Build Coastguard Worker static void coredomain_violation_list_freefn(list_element *e);
171*e4a36f41SAndroid Build Coastguard Worker static void input_file_list_freefn(list_element *e);
172*e4a36f41SAndroid Build Coastguard Worker static void line_order_list_freefn(list_element *e);
173*e4a36f41SAndroid Build Coastguard Worker static void rule_map_free(rule_map *rm, bool is_in_htable);
174*e4a36f41SAndroid Build Coastguard Worker 
175*e4a36f41SAndroid Build Coastguard Worker /** Set to !0 to enable verbose logging */
176*e4a36f41SAndroid Build Coastguard Worker static int logging_verbose = 0;
177*e4a36f41SAndroid Build Coastguard Worker 
178*e4a36f41SAndroid Build Coastguard Worker /** file handle to the output file */
179*e4a36f41SAndroid Build Coastguard Worker static file_info out_file;
180*e4a36f41SAndroid Build Coastguard Worker 
181*e4a36f41SAndroid Build Coastguard Worker static list input_file_list = list_init(input_file_list_freefn);
182*e4a36f41SAndroid Build Coastguard Worker 
183*e4a36f41SAndroid Build Coastguard Worker static list coredomain_violation_list = list_init(coredomain_violation_list_freefn);
184*e4a36f41SAndroid Build Coastguard Worker 
185*e4a36f41SAndroid Build Coastguard Worker static policy_info pol = {
186*e4a36f41SAndroid Build Coastguard Worker 	.policy_file_name = NULL,
187*e4a36f41SAndroid Build Coastguard Worker 	.policy_file = NULL,
188*e4a36f41SAndroid Build Coastguard Worker 	.db = NULL,
189*e4a36f41SAndroid Build Coastguard Worker 	.pf = NULL,
190*e4a36f41SAndroid Build Coastguard Worker 	.handle = NULL,
191*e4a36f41SAndroid Build Coastguard Worker 	.con = NULL,
192*e4a36f41SAndroid Build Coastguard Worker 	.vendor = false
193*e4a36f41SAndroid Build Coastguard Worker };
194*e4a36f41SAndroid Build Coastguard Worker 
195*e4a36f41SAndroid Build Coastguard Worker /**
196*e4a36f41SAndroid Build Coastguard Worker  * Head pointer to a linked list of
197*e4a36f41SAndroid Build Coastguard Worker  * rule map table entries (hash_entry), used for
198*e4a36f41SAndroid Build Coastguard Worker  * preserving the order of entries
199*e4a36f41SAndroid Build Coastguard Worker  * based on "first encounter"
200*e4a36f41SAndroid Build Coastguard Worker  */
201*e4a36f41SAndroid Build Coastguard Worker static list line_order_list = list_init(line_order_list_freefn);
202*e4a36f41SAndroid Build Coastguard Worker 
203*e4a36f41SAndroid Build Coastguard Worker /*
204*e4a36f41SAndroid Build Coastguard Worker  * List of hash_entrys for never allow rules.
205*e4a36f41SAndroid Build Coastguard Worker  */
206*e4a36f41SAndroid Build Coastguard Worker static list nallow_list = list_init(line_order_list_freefn);
207*e4a36f41SAndroid Build Coastguard Worker 
208*e4a36f41SAndroid Build Coastguard Worker /* validation call backs */
209*e4a36f41SAndroid Build Coastguard Worker static bool validate_bool(char *value, const char *filename, int lineno, char **errmsg);
210*e4a36f41SAndroid Build Coastguard Worker static bool validate_levelFrom(char *value, const char *filename, int lineno, char **errmsg);
211*e4a36f41SAndroid Build Coastguard Worker static bool validate_domain(char *value, const char *filename, int lineno, char **errmsg);
212*e4a36f41SAndroid Build Coastguard Worker static bool validate_type(char *value, const char *filename, int lineno, char **errmsg);
213*e4a36f41SAndroid Build Coastguard Worker static bool validate_selinux_level(char *value, const char *filename, int lineno, char **errmsg);
214*e4a36f41SAndroid Build Coastguard Worker static bool validate_uint(char *value, const char *filename, int lineno, char **errmsg);
215*e4a36f41SAndroid Build Coastguard Worker 
216*e4a36f41SAndroid Build Coastguard Worker /**
217*e4a36f41SAndroid Build Coastguard Worker  * The heart of the mapping process, this must be updated if a new key value pair is added
218*e4a36f41SAndroid Build Coastguard Worker  * to a rule.
219*e4a36f41SAndroid Build Coastguard Worker  */
220*e4a36f41SAndroid Build Coastguard Worker key_map rules[] = {
221*e4a36f41SAndroid Build Coastguard Worker                 /*Inputs*/
222*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isSystemServer", .dir = dir_in, .fn_validate = validate_bool },
223*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isEphemeralApp",  .dir = dir_in, .fn_validate = validate_bool },
224*e4a36f41SAndroid Build Coastguard Worker                 { .name = "user",           .dir = dir_in,                              },
225*e4a36f41SAndroid Build Coastguard Worker                 { .name = "seinfo",         .dir = dir_in,                              },
226*e4a36f41SAndroid Build Coastguard Worker                 { .name = "name",           .dir = dir_in,                              },
227*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isPrivApp",      .dir = dir_in, .fn_validate = validate_bool },
228*e4a36f41SAndroid Build Coastguard Worker                 { .name = "minTargetSdkVersion", .dir = dir_in, .fn_validate = validate_uint },
229*e4a36f41SAndroid Build Coastguard Worker                 { .name = "fromRunAs",       .dir = dir_in, .fn_validate = validate_bool },
230*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isIsolatedComputeApp", .dir = dir_in, .fn_validate = validate_bool },
231*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isSdkSandboxAudit", .dir = dir_in, .fn_validate = validate_bool },
232*e4a36f41SAndroid Build Coastguard Worker                 { .name = "isSdkSandboxNext", .dir = dir_in, .fn_validate = validate_bool },
233*e4a36f41SAndroid Build Coastguard Worker                 /*Outputs*/
234*e4a36f41SAndroid Build Coastguard Worker                 { .name = "domain",         .dir = dir_out, .fn_validate = validate_domain  },
235*e4a36f41SAndroid Build Coastguard Worker                 { .name = "type",           .dir = dir_out, .fn_validate = validate_type  },
236*e4a36f41SAndroid Build Coastguard Worker                 { .name = "levelFrom",      .dir = dir_out, .fn_validate = validate_levelFrom     },
237*e4a36f41SAndroid Build Coastguard Worker                 { .name = "level",          .dir = dir_out, .fn_validate = validate_selinux_level },
238*e4a36f41SAndroid Build Coastguard Worker };
239*e4a36f41SAndroid Build Coastguard Worker 
240*e4a36f41SAndroid Build Coastguard Worker /**
241*e4a36f41SAndroid Build Coastguard Worker  * Appends to the end of the list.
242*e4a36f41SAndroid Build Coastguard Worker  * @list The list to append to
243*e4a36f41SAndroid Build Coastguard Worker  * @e the element to append
244*e4a36f41SAndroid Build Coastguard Worker  */
list_append(list * list,list_element * e)245*e4a36f41SAndroid Build Coastguard Worker void list_append(list *list, list_element *e) {
246*e4a36f41SAndroid Build Coastguard Worker 
247*e4a36f41SAndroid Build Coastguard Worker 	memset(e, 0, sizeof(*e));
248*e4a36f41SAndroid Build Coastguard Worker 
249*e4a36f41SAndroid Build Coastguard Worker 	if (list->head == NULL ) {
250*e4a36f41SAndroid Build Coastguard Worker 		list->head = list->tail = e;
251*e4a36f41SAndroid Build Coastguard Worker 		return;
252*e4a36f41SAndroid Build Coastguard Worker 	}
253*e4a36f41SAndroid Build Coastguard Worker 
254*e4a36f41SAndroid Build Coastguard Worker 	list->tail->next = e;
255*e4a36f41SAndroid Build Coastguard Worker 	list->tail = e;
256*e4a36f41SAndroid Build Coastguard Worker 	return;
257*e4a36f41SAndroid Build Coastguard Worker }
258*e4a36f41SAndroid Build Coastguard Worker 
259*e4a36f41SAndroid Build Coastguard Worker /**
260*e4a36f41SAndroid Build Coastguard Worker  * Free's all the elements in the specified list.
261*e4a36f41SAndroid Build Coastguard Worker  * @list The list to free
262*e4a36f41SAndroid Build Coastguard Worker  */
list_free(list * list)263*e4a36f41SAndroid Build Coastguard Worker static void list_free(list *list) {
264*e4a36f41SAndroid Build Coastguard Worker 
265*e4a36f41SAndroid Build Coastguard Worker 	list_element *tmp;
266*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor = list->head;
267*e4a36f41SAndroid Build Coastguard Worker 
268*e4a36f41SAndroid Build Coastguard Worker 	while (cursor) {
269*e4a36f41SAndroid Build Coastguard Worker 		tmp = cursor;
270*e4a36f41SAndroid Build Coastguard Worker 		cursor = cursor->next;
271*e4a36f41SAndroid Build Coastguard Worker 		if (list->freefn) {
272*e4a36f41SAndroid Build Coastguard Worker 			list->freefn(tmp);
273*e4a36f41SAndroid Build Coastguard Worker 		}
274*e4a36f41SAndroid Build Coastguard Worker 	}
275*e4a36f41SAndroid Build Coastguard Worker }
276*e4a36f41SAndroid Build Coastguard Worker 
277*e4a36f41SAndroid Build Coastguard Worker /*
278*e4a36f41SAndroid Build Coastguard Worker  * called when the lists are freed
279*e4a36f41SAndroid Build Coastguard Worker  */
line_order_list_freefn(list_element * e)280*e4a36f41SAndroid Build Coastguard Worker static void line_order_list_freefn(list_element *e) {
281*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *h = list_entry(e, typeof(*h), listify);
282*e4a36f41SAndroid Build Coastguard Worker 	rule_map_free(h->r, true);
283*e4a36f41SAndroid Build Coastguard Worker 	free(h);
284*e4a36f41SAndroid Build Coastguard Worker }
285*e4a36f41SAndroid Build Coastguard Worker 
input_file_list_freefn(list_element * e)286*e4a36f41SAndroid Build Coastguard Worker static void input_file_list_freefn(list_element *e) {
287*e4a36f41SAndroid Build Coastguard Worker 	file_info *f = list_entry(e, typeof(*f), listify);
288*e4a36f41SAndroid Build Coastguard Worker 
289*e4a36f41SAndroid Build Coastguard Worker 	if (f->file) {
290*e4a36f41SAndroid Build Coastguard Worker 		fclose(f->file);
291*e4a36f41SAndroid Build Coastguard Worker 	}
292*e4a36f41SAndroid Build Coastguard Worker 	free(f);
293*e4a36f41SAndroid Build Coastguard Worker }
294*e4a36f41SAndroid Build Coastguard Worker 
coredomain_violation_list_freefn(list_element * e)295*e4a36f41SAndroid Build Coastguard Worker static void coredomain_violation_list_freefn(list_element *e) {
296*e4a36f41SAndroid Build Coastguard Worker 	coredomain_violation_entry *c = list_entry(e, typeof(*c), listify);
297*e4a36f41SAndroid Build Coastguard Worker 
298*e4a36f41SAndroid Build Coastguard Worker 	free(c->domain);
299*e4a36f41SAndroid Build Coastguard Worker 	free(c->filename);
300*e4a36f41SAndroid Build Coastguard Worker 	free(c);
301*e4a36f41SAndroid Build Coastguard Worker }
302*e4a36f41SAndroid Build Coastguard Worker 
303*e4a36f41SAndroid Build Coastguard Worker /**
304*e4a36f41SAndroid Build Coastguard Worker  * Send a logging message to a file
305*e4a36f41SAndroid Build Coastguard Worker  * @param out
306*e4a36f41SAndroid Build Coastguard Worker  * 	Output file to send message too
307*e4a36f41SAndroid Build Coastguard Worker  * @param prefix
308*e4a36f41SAndroid Build Coastguard Worker  * 	A special prefix to write to the file, such as "Error:"
309*e4a36f41SAndroid Build Coastguard Worker  * @param fmt
310*e4a36f41SAndroid Build Coastguard Worker  * 	The printf style formatter to use, such as "%d"
311*e4a36f41SAndroid Build Coastguard Worker  */
312*e4a36f41SAndroid Build Coastguard Worker static void __attribute__ ((format(printf, 3, 4)))
log_msg(FILE * out,const char * prefix,const char * fmt,...)313*e4a36f41SAndroid Build Coastguard Worker log_msg(FILE *out, const char *prefix, const char *fmt, ...) {
314*e4a36f41SAndroid Build Coastguard Worker 
315*e4a36f41SAndroid Build Coastguard Worker 	fprintf(out, "%s", prefix);
316*e4a36f41SAndroid Build Coastguard Worker 	va_list args;
317*e4a36f41SAndroid Build Coastguard Worker 	va_start(args, fmt);
318*e4a36f41SAndroid Build Coastguard Worker 	vfprintf(out, fmt, args);
319*e4a36f41SAndroid Build Coastguard Worker 	va_end(args);
320*e4a36f41SAndroid Build Coastguard Worker }
321*e4a36f41SAndroid Build Coastguard Worker 
322*e4a36f41SAndroid Build Coastguard Worker /**
323*e4a36f41SAndroid Build Coastguard Worker  * Look up a type in the policy.
324*e4a36f41SAndroid Build Coastguard Worker  * @param db
325*e4a36f41SAndroid Build Coastguard Worker  * 	The policy db to search
326*e4a36f41SAndroid Build Coastguard Worker  * @param type
327*e4a36f41SAndroid Build Coastguard Worker  * 	The type to search for
328*e4a36f41SAndroid Build Coastguard Worker  * @param flavor
329*e4a36f41SAndroid Build Coastguard Worker  * 	The expected flavor of type
330*e4a36f41SAndroid Build Coastguard Worker  * @return
331*e4a36f41SAndroid Build Coastguard Worker  * 	Pointer to the type's datum if it exists in the policy with the expected
332*e4a36f41SAndroid Build Coastguard Worker  * 	flavor, NULL otherwise.
333*e4a36f41SAndroid Build Coastguard Worker  * @warning
334*e4a36f41SAndroid Build Coastguard Worker  * 	This function should not be called if libsepol is not linked statically
335*e4a36f41SAndroid Build Coastguard Worker  * 	to this executable and LINK_SEPOL_STATIC is not defined.
336*e4a36f41SAndroid Build Coastguard Worker  */
find_type(sepol_policydb_t * db,char * type,uint32_t flavor)337*e4a36f41SAndroid Build Coastguard Worker static type_datum_t *find_type(sepol_policydb_t *db, char *type, uint32_t flavor) {
338*e4a36f41SAndroid Build Coastguard Worker 
339*e4a36f41SAndroid Build Coastguard Worker 	policydb_t *d = &db->p;
340*e4a36f41SAndroid Build Coastguard Worker 	hashtab_datum_t dat = hashtab_search(d->p_types.table, type);
341*e4a36f41SAndroid Build Coastguard Worker         if (!dat) {
342*e4a36f41SAndroid Build Coastguard Worker             return NULL;
343*e4a36f41SAndroid Build Coastguard Worker         }
344*e4a36f41SAndroid Build Coastguard Worker         type_datum_t *type_dat = (type_datum_t *) dat;
345*e4a36f41SAndroid Build Coastguard Worker         if (type_dat->flavor != flavor) {
346*e4a36f41SAndroid Build Coastguard Worker             return NULL;
347*e4a36f41SAndroid Build Coastguard Worker         }
348*e4a36f41SAndroid Build Coastguard Worker         return type_dat;
349*e4a36f41SAndroid Build Coastguard Worker }
350*e4a36f41SAndroid Build Coastguard Worker 
type_has_attribute(sepol_policydb_t * db,type_datum_t * type_dat,type_datum_t * attrib_dat)351*e4a36f41SAndroid Build Coastguard Worker static bool type_has_attribute(sepol_policydb_t *db, type_datum_t *type_dat,
352*e4a36f41SAndroid Build Coastguard Worker                                type_datum_t *attrib_dat) {
353*e4a36f41SAndroid Build Coastguard Worker     policydb_t *d = &db->p;
354*e4a36f41SAndroid Build Coastguard Worker     ebitmap_t *attr_bits = &d->type_attr_map[type_dat->s.value - 1];
355*e4a36f41SAndroid Build Coastguard Worker     return ebitmap_get_bit(attr_bits, attrib_dat->s.value - 1) != 0;
356*e4a36f41SAndroid Build Coastguard Worker }
357*e4a36f41SAndroid Build Coastguard Worker 
match_regex(key_map * assert,const key_map * check)358*e4a36f41SAndroid Build Coastguard Worker static bool match_regex(key_map *assert, const key_map *check) {
359*e4a36f41SAndroid Build Coastguard Worker 
360*e4a36f41SAndroid Build Coastguard Worker 	char *tomatch = check->data;
361*e4a36f41SAndroid Build Coastguard Worker 
362*e4a36f41SAndroid Build Coastguard Worker 	int ret = pcre2_match(assert->regex.compiled, (PCRE2_SPTR) tomatch,
363*e4a36f41SAndroid Build Coastguard Worker 				PCRE2_ZERO_TERMINATED, 0, 0,
364*e4a36f41SAndroid Build Coastguard Worker 				assert->regex.match_data, NULL);
365*e4a36f41SAndroid Build Coastguard Worker 
366*e4a36f41SAndroid Build Coastguard Worker 	/* ret > 0 from pcre2_match means matched */
367*e4a36f41SAndroid Build Coastguard Worker 	return ret > 0;
368*e4a36f41SAndroid Build Coastguard Worker }
369*e4a36f41SAndroid Build Coastguard Worker 
compile_regex(key_map * km,int * errcode,PCRE2_SIZE * erroff)370*e4a36f41SAndroid Build Coastguard Worker static bool compile_regex(key_map *km, int *errcode, PCRE2_SIZE *erroff) {
371*e4a36f41SAndroid Build Coastguard Worker 
372*e4a36f41SAndroid Build Coastguard Worker 	size_t size;
373*e4a36f41SAndroid Build Coastguard Worker 	char *anchored;
374*e4a36f41SAndroid Build Coastguard Worker 
375*e4a36f41SAndroid Build Coastguard Worker 	/*
376*e4a36f41SAndroid Build Coastguard Worker 	 * Explicitly anchor all regex's
377*e4a36f41SAndroid Build Coastguard Worker 	 * The size is the length of the string to anchor (km->data), the anchor
378*e4a36f41SAndroid Build Coastguard Worker 	 * characters ^ and $ and the null byte. Hence strlen(km->data) + 3
379*e4a36f41SAndroid Build Coastguard Worker 	 */
380*e4a36f41SAndroid Build Coastguard Worker 	size = strlen(km->data) + 3;
381*e4a36f41SAndroid Build Coastguard Worker 	anchored = alloca(size);
382*e4a36f41SAndroid Build Coastguard Worker 	sprintf(anchored, "^%s$", km->data);
383*e4a36f41SAndroid Build Coastguard Worker 
384*e4a36f41SAndroid Build Coastguard Worker 	km->regex.compiled = pcre2_compile((PCRE2_SPTR) anchored,
385*e4a36f41SAndroid Build Coastguard Worker 						PCRE2_ZERO_TERMINATED,
386*e4a36f41SAndroid Build Coastguard Worker 						PCRE2_DOTALL,
387*e4a36f41SAndroid Build Coastguard Worker 						errcode, erroff,
388*e4a36f41SAndroid Build Coastguard Worker 						NULL);
389*e4a36f41SAndroid Build Coastguard Worker 	if (!km->regex.compiled) {
390*e4a36f41SAndroid Build Coastguard Worker 		return false;
391*e4a36f41SAndroid Build Coastguard Worker 	}
392*e4a36f41SAndroid Build Coastguard Worker 
393*e4a36f41SAndroid Build Coastguard Worker 	km->regex.match_data = pcre2_match_data_create_from_pattern(
394*e4a36f41SAndroid Build Coastguard Worker 			km->regex.compiled, NULL);
395*e4a36f41SAndroid Build Coastguard Worker 	if (!km->regex.match_data) {
396*e4a36f41SAndroid Build Coastguard Worker 		pcre2_code_free(km->regex.compiled);
397*e4a36f41SAndroid Build Coastguard Worker 		return false;
398*e4a36f41SAndroid Build Coastguard Worker 	}
399*e4a36f41SAndroid Build Coastguard Worker 	return true;
400*e4a36f41SAndroid Build Coastguard Worker }
401*e4a36f41SAndroid Build Coastguard Worker 
validate_bool(char * value,const char * filename,int lineno,char ** errmsg)402*e4a36f41SAndroid Build Coastguard Worker static bool validate_bool(
403*e4a36f41SAndroid Build Coastguard Worker 		char *value,
404*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) const char *filename,
405*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) int lineno,
406*e4a36f41SAndroid Build Coastguard Worker 		char **errmsg) {
407*e4a36f41SAndroid Build Coastguard Worker 	if (!strcmp("true", value) || !strcmp("false", value)) {
408*e4a36f41SAndroid Build Coastguard Worker 		return true;
409*e4a36f41SAndroid Build Coastguard Worker 	}
410*e4a36f41SAndroid Build Coastguard Worker 
411*e4a36f41SAndroid Build Coastguard Worker 	*errmsg = "Expecting \"true\" or \"false\"";
412*e4a36f41SAndroid Build Coastguard Worker 	return false;
413*e4a36f41SAndroid Build Coastguard Worker }
414*e4a36f41SAndroid Build Coastguard Worker 
validate_levelFrom(char * value,const char * filename,int lineno,char ** errmsg)415*e4a36f41SAndroid Build Coastguard Worker static bool validate_levelFrom(
416*e4a36f41SAndroid Build Coastguard Worker 		char *value,
417*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) const char *filename,
418*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) int lineno,
419*e4a36f41SAndroid Build Coastguard Worker 		char **errmsg) {
420*e4a36f41SAndroid Build Coastguard Worker 	if (strcasecmp(value, "none") && strcasecmp(value, "all") &&
421*e4a36f41SAndroid Build Coastguard Worker 		strcasecmp(value, "app") && strcasecmp(value, "user")) {
422*e4a36f41SAndroid Build Coastguard Worker 		*errmsg = "Expecting one of: \"none\", \"all\", \"app\" or \"user\"";
423*e4a36f41SAndroid Build Coastguard Worker 		return false;
424*e4a36f41SAndroid Build Coastguard Worker 	}
425*e4a36f41SAndroid Build Coastguard Worker 	return true;
426*e4a36f41SAndroid Build Coastguard Worker }
427*e4a36f41SAndroid Build Coastguard Worker 
validate_domain(char * value,const char * filename,int lineno,char ** errmsg)428*e4a36f41SAndroid Build Coastguard Worker static bool validate_domain(char *value, const char *filename, int lineno, char **errmsg) {
429*e4a36f41SAndroid Build Coastguard Worker 
430*e4a36f41SAndroid Build Coastguard Worker #if defined(LINK_SEPOL_STATIC)
431*e4a36f41SAndroid Build Coastguard Worker 	/*
432*e4a36f41SAndroid Build Coastguard Worker 	 * No policy file present means we cannot check
433*e4a36f41SAndroid Build Coastguard Worker 	 * SE Linux types
434*e4a36f41SAndroid Build Coastguard Worker 	 */
435*e4a36f41SAndroid Build Coastguard Worker 	if (!pol.policy_file) {
436*e4a36f41SAndroid Build Coastguard Worker 		return true;
437*e4a36f41SAndroid Build Coastguard Worker 	}
438*e4a36f41SAndroid Build Coastguard Worker 
439*e4a36f41SAndroid Build Coastguard Worker 	type_datum_t *type_dat = find_type(pol.db, value, TYPE_TYPE);
440*e4a36f41SAndroid Build Coastguard Worker 	if (!type_dat) {
441*e4a36f41SAndroid Build Coastguard Worker 		*errmsg = "Expecting a valid SELinux type";
442*e4a36f41SAndroid Build Coastguard Worker 		return false;
443*e4a36f41SAndroid Build Coastguard Worker 	}
444*e4a36f41SAndroid Build Coastguard Worker 
445*e4a36f41SAndroid Build Coastguard Worker 	if (pol.vendor) {
446*e4a36f41SAndroid Build Coastguard Worker 		type_datum_t *attrib_dat = find_type(pol.db, COREDOMAIN, TYPE_ATTRIB);
447*e4a36f41SAndroid Build Coastguard Worker 		if (!attrib_dat) {
448*e4a36f41SAndroid Build Coastguard Worker 			*errmsg = "The attribute " COREDOMAIN " is not defined in the policy";
449*e4a36f41SAndroid Build Coastguard Worker 			return false;
450*e4a36f41SAndroid Build Coastguard Worker 		}
451*e4a36f41SAndroid Build Coastguard Worker 
452*e4a36f41SAndroid Build Coastguard Worker 		if (type_has_attribute(pol.db, type_dat, attrib_dat)) {
453*e4a36f41SAndroid Build Coastguard Worker 			coredomain_violation_entry *entry = (coredomain_violation_entry *)malloc(sizeof(*entry));
454*e4a36f41SAndroid Build Coastguard Worker 			entry->domain = strdup(value);
455*e4a36f41SAndroid Build Coastguard Worker 			entry->filename = strdup(filename);
456*e4a36f41SAndroid Build Coastguard Worker 			entry->lineno = lineno;
457*e4a36f41SAndroid Build Coastguard Worker 			list_append(&coredomain_violation_list, &entry->listify);
458*e4a36f41SAndroid Build Coastguard Worker 		}
459*e4a36f41SAndroid Build Coastguard Worker 	}
460*e4a36f41SAndroid Build Coastguard Worker #endif
461*e4a36f41SAndroid Build Coastguard Worker 
462*e4a36f41SAndroid Build Coastguard Worker 	return true;
463*e4a36f41SAndroid Build Coastguard Worker }
464*e4a36f41SAndroid Build Coastguard Worker 
validate_type(char * value,const char * filename,int lineno,char ** errmsg)465*e4a36f41SAndroid Build Coastguard Worker static bool validate_type(
466*e4a36f41SAndroid Build Coastguard Worker 		char *value,
467*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) const char *filename,
468*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) int lineno,
469*e4a36f41SAndroid Build Coastguard Worker 		char **errmsg) {
470*e4a36f41SAndroid Build Coastguard Worker #if defined(LINK_SEPOL_STATIC)
471*e4a36f41SAndroid Build Coastguard Worker 	/*
472*e4a36f41SAndroid Build Coastguard Worker 	 * No policy file present means we cannot check
473*e4a36f41SAndroid Build Coastguard Worker 	 * SE Linux types
474*e4a36f41SAndroid Build Coastguard Worker 	 */
475*e4a36f41SAndroid Build Coastguard Worker 	if (!pol.policy_file) {
476*e4a36f41SAndroid Build Coastguard Worker 		return true;
477*e4a36f41SAndroid Build Coastguard Worker 	}
478*e4a36f41SAndroid Build Coastguard Worker 
479*e4a36f41SAndroid Build Coastguard Worker         type_datum_t *type_dat = find_type(pol.db, value, TYPE_TYPE);
480*e4a36f41SAndroid Build Coastguard Worker 	if (!type_dat) {
481*e4a36f41SAndroid Build Coastguard Worker 		*errmsg = "Expecting a valid SELinux type";
482*e4a36f41SAndroid Build Coastguard Worker 		return false;
483*e4a36f41SAndroid Build Coastguard Worker 	}
484*e4a36f41SAndroid Build Coastguard Worker 
485*e4a36f41SAndroid Build Coastguard Worker         type_datum_t *attrib_dat = find_type(pol.db, APP_DATA_REQUIRED_ATTRIB,
486*e4a36f41SAndroid Build Coastguard Worker                                               TYPE_ATTRIB);
487*e4a36f41SAndroid Build Coastguard Worker 	if (!attrib_dat) {
488*e4a36f41SAndroid Build Coastguard Worker             /* If the policy doesn't contain the attribute, we can't check it */
489*e4a36f41SAndroid Build Coastguard Worker             return true;
490*e4a36f41SAndroid Build Coastguard Worker         }
491*e4a36f41SAndroid Build Coastguard Worker 
492*e4a36f41SAndroid Build Coastguard Worker         if (!type_has_attribute(pol.db, type_dat, attrib_dat)) {
493*e4a36f41SAndroid Build Coastguard Worker             *errmsg = "Missing required attribute " APP_DATA_REQUIRED_ATTRIB;
494*e4a36f41SAndroid Build Coastguard Worker             return false;
495*e4a36f41SAndroid Build Coastguard Worker         }
496*e4a36f41SAndroid Build Coastguard Worker 
497*e4a36f41SAndroid Build Coastguard Worker #endif
498*e4a36f41SAndroid Build Coastguard Worker 
499*e4a36f41SAndroid Build Coastguard Worker 	return true;
500*e4a36f41SAndroid Build Coastguard Worker }
501*e4a36f41SAndroid Build Coastguard Worker 
validate_selinux_level(char * value,const char * filename,int lineno,char ** errmsg)502*e4a36f41SAndroid Build Coastguard Worker static bool validate_selinux_level(
503*e4a36f41SAndroid Build Coastguard Worker 		char *value,
504*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) const char *filename,
505*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) int lineno,
506*e4a36f41SAndroid Build Coastguard Worker 		char **errmsg) {
507*e4a36f41SAndroid Build Coastguard Worker 	/*
508*e4a36f41SAndroid Build Coastguard Worker 	 * No policy file present means we cannot check
509*e4a36f41SAndroid Build Coastguard Worker 	 * SE Linux MLS
510*e4a36f41SAndroid Build Coastguard Worker 	 */
511*e4a36f41SAndroid Build Coastguard Worker 	if (!pol.policy_file) {
512*e4a36f41SAndroid Build Coastguard Worker 		return true;
513*e4a36f41SAndroid Build Coastguard Worker 	}
514*e4a36f41SAndroid Build Coastguard Worker 
515*e4a36f41SAndroid Build Coastguard Worker 	int ret = sepol_mls_check(pol.handle, pol.db, value);
516*e4a36f41SAndroid Build Coastguard Worker 	if (ret < 0) {
517*e4a36f41SAndroid Build Coastguard Worker 		*errmsg = "Expecting a valid SELinux MLS value";
518*e4a36f41SAndroid Build Coastguard Worker 		return false;
519*e4a36f41SAndroid Build Coastguard Worker 	}
520*e4a36f41SAndroid Build Coastguard Worker 
521*e4a36f41SAndroid Build Coastguard Worker 	return true;
522*e4a36f41SAndroid Build Coastguard Worker }
523*e4a36f41SAndroid Build Coastguard Worker 
validate_uint(char * value,const char * filename,int lineno,char ** errmsg)524*e4a36f41SAndroid Build Coastguard Worker static bool validate_uint(
525*e4a36f41SAndroid Build Coastguard Worker 		char *value,
526*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) const char *filename,
527*e4a36f41SAndroid Build Coastguard Worker 		__attribute__ ((unused)) int lineno,
528*e4a36f41SAndroid Build Coastguard Worker 		char **errmsg) {
529*e4a36f41SAndroid Build Coastguard Worker 	char *endptr;
530*e4a36f41SAndroid Build Coastguard Worker 	long longvalue;
531*e4a36f41SAndroid Build Coastguard Worker 	longvalue = strtol(value, &endptr, 10);
532*e4a36f41SAndroid Build Coastguard Worker 	if (('\0' != *endptr) || (longvalue < 0) || (longvalue > INT32_MAX)) {
533*e4a36f41SAndroid Build Coastguard Worker 		*errmsg = "Expecting a valid unsigned integer";
534*e4a36f41SAndroid Build Coastguard Worker 		return false;
535*e4a36f41SAndroid Build Coastguard Worker 	}
536*e4a36f41SAndroid Build Coastguard Worker 
537*e4a36f41SAndroid Build Coastguard Worker 	return true;
538*e4a36f41SAndroid Build Coastguard Worker }
539*e4a36f41SAndroid Build Coastguard Worker 
540*e4a36f41SAndroid Build Coastguard Worker /**
541*e4a36f41SAndroid Build Coastguard Worker  * Validates a key_map against a set of enforcement rules, this
542*e4a36f41SAndroid Build Coastguard Worker  * function exits the application on a type that cannot be properly
543*e4a36f41SAndroid Build Coastguard Worker  * checked
544*e4a36f41SAndroid Build Coastguard Worker  *
545*e4a36f41SAndroid Build Coastguard Worker  * @param m
546*e4a36f41SAndroid Build Coastguard Worker  * 	The key map to check
547*e4a36f41SAndroid Build Coastguard Worker  * @param lineno
548*e4a36f41SAndroid Build Coastguard Worker  * 	The line number in the source file for the corresponding key map
549*e4a36f41SAndroid Build Coastguard Worker  * @return
550*e4a36f41SAndroid Build Coastguard Worker  * 	true if valid, false if invalid
551*e4a36f41SAndroid Build Coastguard Worker  */
key_map_validate(key_map * m,const char * filename,int lineno,bool is_neverallow)552*e4a36f41SAndroid Build Coastguard Worker static bool key_map_validate(key_map *m, const char *filename, int lineno,
553*e4a36f41SAndroid Build Coastguard Worker 		bool is_neverallow) {
554*e4a36f41SAndroid Build Coastguard Worker 
555*e4a36f41SAndroid Build Coastguard Worker 	PCRE2_SIZE erroff;
556*e4a36f41SAndroid Build Coastguard Worker 	int errcode;
557*e4a36f41SAndroid Build Coastguard Worker 	bool rc = true;
558*e4a36f41SAndroid Build Coastguard Worker 	char *key = m->name;
559*e4a36f41SAndroid Build Coastguard Worker 	char *value = m->data;
560*e4a36f41SAndroid Build Coastguard Worker 	char *errmsg = NULL;
561*e4a36f41SAndroid Build Coastguard Worker 	char errstr[256];
562*e4a36f41SAndroid Build Coastguard Worker 
563*e4a36f41SAndroid Build Coastguard Worker 	log_info("Validating %s=%s\n", key, value);
564*e4a36f41SAndroid Build Coastguard Worker 
565*e4a36f41SAndroid Build Coastguard Worker 	/*
566*e4a36f41SAndroid Build Coastguard Worker 	 * Neverallows are completely skipped from validity checking so you can match
567*e4a36f41SAndroid Build Coastguard Worker 	 * un-unspecified inputs.
568*e4a36f41SAndroid Build Coastguard Worker 	 */
569*e4a36f41SAndroid Build Coastguard Worker 	if (is_neverallow) {
570*e4a36f41SAndroid Build Coastguard Worker 		if (!m->regex.compiled) {
571*e4a36f41SAndroid Build Coastguard Worker 			rc = compile_regex(m, &errcode, &erroff);
572*e4a36f41SAndroid Build Coastguard Worker 			if (!rc) {
573*e4a36f41SAndroid Build Coastguard Worker 				pcre2_get_error_message(errcode,
574*e4a36f41SAndroid Build Coastguard Worker 							(PCRE2_UCHAR*) errstr,
575*e4a36f41SAndroid Build Coastguard Worker 							sizeof(errstr));
576*e4a36f41SAndroid Build Coastguard Worker 				log_error("Invalid regex on line %d : %s PCRE error: %s at offset %lu",
577*e4a36f41SAndroid Build Coastguard Worker 						lineno, value, errstr, erroff);
578*e4a36f41SAndroid Build Coastguard Worker 			}
579*e4a36f41SAndroid Build Coastguard Worker 		}
580*e4a36f41SAndroid Build Coastguard Worker 		goto out;
581*e4a36f41SAndroid Build Coastguard Worker 	}
582*e4a36f41SAndroid Build Coastguard Worker 
583*e4a36f41SAndroid Build Coastguard Worker 	/* If the key has a validation routine, call it */
584*e4a36f41SAndroid Build Coastguard Worker 	if (m->fn_validate) {
585*e4a36f41SAndroid Build Coastguard Worker 		rc = m->fn_validate(value, filename, lineno, &errmsg);
586*e4a36f41SAndroid Build Coastguard Worker 
587*e4a36f41SAndroid Build Coastguard Worker 		if (!rc) {
588*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not validate key \"%s\" for value \"%s\" on line: %d in file: \"%s\": %s\n", key, value,
589*e4a36f41SAndroid Build Coastguard Worker 			lineno, filename, errmsg);
590*e4a36f41SAndroid Build Coastguard Worker 		}
591*e4a36f41SAndroid Build Coastguard Worker 	}
592*e4a36f41SAndroid Build Coastguard Worker 
593*e4a36f41SAndroid Build Coastguard Worker out:
594*e4a36f41SAndroid Build Coastguard Worker 	log_info("Key map validate returning: %d\n", rc);
595*e4a36f41SAndroid Build Coastguard Worker 	return rc;
596*e4a36f41SAndroid Build Coastguard Worker }
597*e4a36f41SAndroid Build Coastguard Worker 
598*e4a36f41SAndroid Build Coastguard Worker /**
599*e4a36f41SAndroid Build Coastguard Worker  * Prints a rule map back to a file
600*e4a36f41SAndroid Build Coastguard Worker  * @param fp
601*e4a36f41SAndroid Build Coastguard Worker  * 	The file handle to print too
602*e4a36f41SAndroid Build Coastguard Worker  * @param r
603*e4a36f41SAndroid Build Coastguard Worker  * 	The rule map to print
604*e4a36f41SAndroid Build Coastguard Worker  */
rule_map_print(FILE * fp,rule_map * r)605*e4a36f41SAndroid Build Coastguard Worker static void rule_map_print(FILE *fp, rule_map *r) {
606*e4a36f41SAndroid Build Coastguard Worker 
607*e4a36f41SAndroid Build Coastguard Worker 	size_t i;
608*e4a36f41SAndroid Build Coastguard Worker 	key_map *m;
609*e4a36f41SAndroid Build Coastguard Worker 
610*e4a36f41SAndroid Build Coastguard Worker 	for (i = 0; i < r->length; i++) {
611*e4a36f41SAndroid Build Coastguard Worker 		m = &(r->m[i]);
612*e4a36f41SAndroid Build Coastguard Worker 		if (i < r->length - 1)
613*e4a36f41SAndroid Build Coastguard Worker 			fprintf(fp, "%s=%s ", m->name, m->data);
614*e4a36f41SAndroid Build Coastguard Worker 		else
615*e4a36f41SAndroid Build Coastguard Worker 			fprintf(fp, "%s=%s", m->name, m->data);
616*e4a36f41SAndroid Build Coastguard Worker 	}
617*e4a36f41SAndroid Build Coastguard Worker }
618*e4a36f41SAndroid Build Coastguard Worker 
619*e4a36f41SAndroid Build Coastguard Worker /**
620*e4a36f41SAndroid Build Coastguard Worker  * Compare two rule maps for equality
621*e4a36f41SAndroid Build Coastguard Worker  * @param rmA
622*e4a36f41SAndroid Build Coastguard Worker  * 	a rule map to check
623*e4a36f41SAndroid Build Coastguard Worker  * @param rmB
624*e4a36f41SAndroid Build Coastguard Worker  * 	a rule map to check
625*e4a36f41SAndroid Build Coastguard Worker  * @return
626*e4a36f41SAndroid Build Coastguard Worker  *  a map_match enum indicating the result
627*e4a36f41SAndroid Build Coastguard Worker  */
rule_map_cmp(rule_map * rmA,rule_map * rmB)628*e4a36f41SAndroid Build Coastguard Worker static map_match rule_map_cmp(rule_map *rmA, rule_map *rmB) {
629*e4a36f41SAndroid Build Coastguard Worker 
630*e4a36f41SAndroid Build Coastguard Worker 	size_t i;
631*e4a36f41SAndroid Build Coastguard Worker 	size_t j;
632*e4a36f41SAndroid Build Coastguard Worker 	int inputs_found = 0;
633*e4a36f41SAndroid Build Coastguard Worker 	int num_of_matched_inputs = 0;
634*e4a36f41SAndroid Build Coastguard Worker 	int input_mode = 0;
635*e4a36f41SAndroid Build Coastguard Worker 	size_t matches = 0;
636*e4a36f41SAndroid Build Coastguard Worker 	key_map *mA;
637*e4a36f41SAndroid Build Coastguard Worker 	key_map *mB;
638*e4a36f41SAndroid Build Coastguard Worker 
639*e4a36f41SAndroid Build Coastguard Worker 	for (i = 0; i < rmA->length; i++) {
640*e4a36f41SAndroid Build Coastguard Worker 		mA = &(rmA->m[i]);
641*e4a36f41SAndroid Build Coastguard Worker 
642*e4a36f41SAndroid Build Coastguard Worker 		for (j = 0; j < rmB->length; j++) {
643*e4a36f41SAndroid Build Coastguard Worker 			mB = &(rmB->m[j]);
644*e4a36f41SAndroid Build Coastguard Worker 			input_mode = 0;
645*e4a36f41SAndroid Build Coastguard Worker 
646*e4a36f41SAndroid Build Coastguard Worker 			if (strcmp(mA->name, mB->name))
647*e4a36f41SAndroid Build Coastguard Worker 				continue;
648*e4a36f41SAndroid Build Coastguard Worker 
649*e4a36f41SAndroid Build Coastguard Worker 			if (strcmp(mA->data, mB->data))
650*e4a36f41SAndroid Build Coastguard Worker 				continue;
651*e4a36f41SAndroid Build Coastguard Worker 
652*e4a36f41SAndroid Build Coastguard Worker 			if (mB->dir != mA->dir)
653*e4a36f41SAndroid Build Coastguard Worker 				continue;
654*e4a36f41SAndroid Build Coastguard Worker 			else if (mB->dir == dir_in) {
655*e4a36f41SAndroid Build Coastguard Worker 				input_mode = 1;
656*e4a36f41SAndroid Build Coastguard Worker 				inputs_found++;
657*e4a36f41SAndroid Build Coastguard Worker 			}
658*e4a36f41SAndroid Build Coastguard Worker 
659*e4a36f41SAndroid Build Coastguard Worker 			if (input_mode) {
660*e4a36f41SAndroid Build Coastguard Worker 				log_info("Matched input lines: name=%s data=%s\n", mA->name, mA->data);
661*e4a36f41SAndroid Build Coastguard Worker 				num_of_matched_inputs++;
662*e4a36f41SAndroid Build Coastguard Worker 			}
663*e4a36f41SAndroid Build Coastguard Worker 
664*e4a36f41SAndroid Build Coastguard Worker 			/* Match found, move on */
665*e4a36f41SAndroid Build Coastguard Worker 			log_info("Matched lines: name=%s data=%s", mA->name, mA->data);
666*e4a36f41SAndroid Build Coastguard Worker 			matches++;
667*e4a36f41SAndroid Build Coastguard Worker 			break;
668*e4a36f41SAndroid Build Coastguard Worker 		}
669*e4a36f41SAndroid Build Coastguard Worker 	}
670*e4a36f41SAndroid Build Coastguard Worker 
671*e4a36f41SAndroid Build Coastguard Worker 	/* If they all matched*/
672*e4a36f41SAndroid Build Coastguard Worker 	if (matches == rmA->length) {
673*e4a36f41SAndroid Build Coastguard Worker 		log_info("Rule map cmp MATCH\n");
674*e4a36f41SAndroid Build Coastguard Worker 		return map_matched;
675*e4a36f41SAndroid Build Coastguard Worker 	}
676*e4a36f41SAndroid Build Coastguard Worker 
677*e4a36f41SAndroid Build Coastguard Worker 	/* They didn't all match but the input's did */
678*e4a36f41SAndroid Build Coastguard Worker 	else if (num_of_matched_inputs == inputs_found) {
679*e4a36f41SAndroid Build Coastguard Worker 		log_info("Rule map cmp INPUT MATCH\n");
680*e4a36f41SAndroid Build Coastguard Worker 		return map_input_matched;
681*e4a36f41SAndroid Build Coastguard Worker 	}
682*e4a36f41SAndroid Build Coastguard Worker 
683*e4a36f41SAndroid Build Coastguard Worker 	/* They didn't all match, and the inputs didn't match, ie it didn't
684*e4a36f41SAndroid Build Coastguard Worker 	 * match */
685*e4a36f41SAndroid Build Coastguard Worker 	else {
686*e4a36f41SAndroid Build Coastguard Worker 		log_info("Rule map cmp NO MATCH\n");
687*e4a36f41SAndroid Build Coastguard Worker 		return map_no_matches;
688*e4a36f41SAndroid Build Coastguard Worker 	}
689*e4a36f41SAndroid Build Coastguard Worker }
690*e4a36f41SAndroid Build Coastguard Worker 
691*e4a36f41SAndroid Build Coastguard Worker /**
692*e4a36f41SAndroid Build Coastguard Worker  * Frees a rule map
693*e4a36f41SAndroid Build Coastguard Worker  * @param rm
694*e4a36f41SAndroid Build Coastguard Worker  * 	rule map to be freed.
695*e4a36f41SAndroid Build Coastguard Worker  * @is_in_htable
696*e4a36f41SAndroid Build Coastguard Worker  * 	True if the rule map has been added to the hash table, false
697*e4a36f41SAndroid Build Coastguard Worker  * 	otherwise.
698*e4a36f41SAndroid Build Coastguard Worker  */
rule_map_free(rule_map * rm,bool is_in_htable)699*e4a36f41SAndroid Build Coastguard Worker static void rule_map_free(rule_map *rm, bool is_in_htable) {
700*e4a36f41SAndroid Build Coastguard Worker 
701*e4a36f41SAndroid Build Coastguard Worker 	size_t i;
702*e4a36f41SAndroid Build Coastguard Worker 	size_t len = rm->length;
703*e4a36f41SAndroid Build Coastguard Worker 	for (i = 0; i < len; i++) {
704*e4a36f41SAndroid Build Coastguard Worker 		key_map *m = &(rm->m[i]);
705*e4a36f41SAndroid Build Coastguard Worker 		free(m->data);
706*e4a36f41SAndroid Build Coastguard Worker 
707*e4a36f41SAndroid Build Coastguard Worker 		if (m->regex.compiled) {
708*e4a36f41SAndroid Build Coastguard Worker 			pcre2_code_free(m->regex.compiled);
709*e4a36f41SAndroid Build Coastguard Worker 		}
710*e4a36f41SAndroid Build Coastguard Worker 
711*e4a36f41SAndroid Build Coastguard Worker 		if (m->regex.match_data) {
712*e4a36f41SAndroid Build Coastguard Worker 			pcre2_match_data_free(m->regex.match_data);
713*e4a36f41SAndroid Build Coastguard Worker 		}
714*e4a36f41SAndroid Build Coastguard Worker 	}
715*e4a36f41SAndroid Build Coastguard Worker 
716*e4a36f41SAndroid Build Coastguard Worker 	/*
717*e4a36f41SAndroid Build Coastguard Worker 	 * hdestroy() frees comparsion keys for non glibc
718*e4a36f41SAndroid Build Coastguard Worker 	 * on GLIBC we always free on NON-GLIBC we free if
719*e4a36f41SAndroid Build Coastguard Worker 	 * it is not in the htable.
720*e4a36f41SAndroid Build Coastguard Worker 	 */
721*e4a36f41SAndroid Build Coastguard Worker 	if (rm->key) {
722*e4a36f41SAndroid Build Coastguard Worker #ifdef __GLIBC__
723*e4a36f41SAndroid Build Coastguard Worker 		/* silence unused warning */
724*e4a36f41SAndroid Build Coastguard Worker 		(void)is_in_htable;
725*e4a36f41SAndroid Build Coastguard Worker 		free(rm->key);
726*e4a36f41SAndroid Build Coastguard Worker #else
727*e4a36f41SAndroid Build Coastguard Worker 		if (!is_in_htable) {
728*e4a36f41SAndroid Build Coastguard Worker 			free(rm->key);
729*e4a36f41SAndroid Build Coastguard Worker 		}
730*e4a36f41SAndroid Build Coastguard Worker #endif
731*e4a36f41SAndroid Build Coastguard Worker 	}
732*e4a36f41SAndroid Build Coastguard Worker 
733*e4a36f41SAndroid Build Coastguard Worker 	free(rm->filename);
734*e4a36f41SAndroid Build Coastguard Worker 	free(rm);
735*e4a36f41SAndroid Build Coastguard Worker }
736*e4a36f41SAndroid Build Coastguard Worker 
free_kvp(kvp * k)737*e4a36f41SAndroid Build Coastguard Worker static void free_kvp(kvp *k) {
738*e4a36f41SAndroid Build Coastguard Worker 	free(k->key);
739*e4a36f41SAndroid Build Coastguard Worker 	free(k->value);
740*e4a36f41SAndroid Build Coastguard Worker }
741*e4a36f41SAndroid Build Coastguard Worker 
742*e4a36f41SAndroid Build Coastguard Worker /**
743*e4a36f41SAndroid Build Coastguard Worker  * Checks a rule_map for any variation of KVP's that shouldn't be allowed.
744*e4a36f41SAndroid Build Coastguard Worker  * It builds an assertion failure list for each rule map.
745*e4a36f41SAndroid Build Coastguard Worker  * Note that this function logs all errors.
746*e4a36f41SAndroid Build Coastguard Worker  *
747*e4a36f41SAndroid Build Coastguard Worker  * Current Checks:
748*e4a36f41SAndroid Build Coastguard Worker  * 1. That a specified name entry should have a specified seinfo entry as well.
749*e4a36f41SAndroid Build Coastguard Worker  * 2. That no rule violates a neverallow
750*e4a36f41SAndroid Build Coastguard Worker  * @param rm
751*e4a36f41SAndroid Build Coastguard Worker  *  The rule map to check for validity.
752*e4a36f41SAndroid Build Coastguard Worker  */
rule_map_validate(rule_map * rm)753*e4a36f41SAndroid Build Coastguard Worker static void rule_map_validate(rule_map *rm) {
754*e4a36f41SAndroid Build Coastguard Worker 
755*e4a36f41SAndroid Build Coastguard Worker 	size_t i, j;
756*e4a36f41SAndroid Build Coastguard Worker 	const key_map *rule;
757*e4a36f41SAndroid Build Coastguard Worker 	key_map *nrule;
758*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *e;
759*e4a36f41SAndroid Build Coastguard Worker 	rule_map *assert;
760*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor;
761*e4a36f41SAndroid Build Coastguard Worker 
762*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&nallow_list, cursor) {
763*e4a36f41SAndroid Build Coastguard Worker 		e = list_entry(cursor, typeof(*e), listify);
764*e4a36f41SAndroid Build Coastguard Worker 		assert = e->r;
765*e4a36f41SAndroid Build Coastguard Worker 
766*e4a36f41SAndroid Build Coastguard Worker 		size_t cnt = 0;
767*e4a36f41SAndroid Build Coastguard Worker 
768*e4a36f41SAndroid Build Coastguard Worker 		for (j = 0; j < assert->length; j++) {
769*e4a36f41SAndroid Build Coastguard Worker 			nrule = &(assert->m[j]);
770*e4a36f41SAndroid Build Coastguard Worker 
771*e4a36f41SAndroid Build Coastguard Worker 			// mark that nrule->name is for a null check
772*e4a36f41SAndroid Build Coastguard Worker 			bool is_null_check = !strcmp(nrule->data, "\"\"");
773*e4a36f41SAndroid Build Coastguard Worker 
774*e4a36f41SAndroid Build Coastguard Worker 			for (i = 0; i < rm->length; i++) {
775*e4a36f41SAndroid Build Coastguard Worker 				rule = &(rm->m[i]);
776*e4a36f41SAndroid Build Coastguard Worker 
777*e4a36f41SAndroid Build Coastguard Worker 				if (!strcmp(rule->name, nrule->name)) {
778*e4a36f41SAndroid Build Coastguard Worker 
779*e4a36f41SAndroid Build Coastguard Worker 					/* the name was found, (data cannot be false) then it was specified */
780*e4a36f41SAndroid Build Coastguard Worker 					is_null_check = false;
781*e4a36f41SAndroid Build Coastguard Worker 
782*e4a36f41SAndroid Build Coastguard Worker 					if (match_regex(nrule, rule)) {
783*e4a36f41SAndroid Build Coastguard Worker 						cnt++;
784*e4a36f41SAndroid Build Coastguard Worker 					}
785*e4a36f41SAndroid Build Coastguard Worker 				}
786*e4a36f41SAndroid Build Coastguard Worker 			}
787*e4a36f41SAndroid Build Coastguard Worker 
788*e4a36f41SAndroid Build Coastguard Worker 			/*
789*e4a36f41SAndroid Build Coastguard Worker 			 * the nrule was marked in a null check and we never found a match on nrule, thus
790*e4a36f41SAndroid Build Coastguard Worker 			 * it matched and we update the cnt
791*e4a36f41SAndroid Build Coastguard Worker 			 */
792*e4a36f41SAndroid Build Coastguard Worker 			if (is_null_check) {
793*e4a36f41SAndroid Build Coastguard Worker 				cnt++;
794*e4a36f41SAndroid Build Coastguard Worker 			}
795*e4a36f41SAndroid Build Coastguard Worker 		}
796*e4a36f41SAndroid Build Coastguard Worker 		if (cnt == assert->length) {
797*e4a36f41SAndroid Build Coastguard Worker 			list_append(&rm->violations, &assert->listify);
798*e4a36f41SAndroid Build Coastguard Worker 		}
799*e4a36f41SAndroid Build Coastguard Worker 	}
800*e4a36f41SAndroid Build Coastguard Worker }
801*e4a36f41SAndroid Build Coastguard Worker 
802*e4a36f41SAndroid Build Coastguard Worker /**
803*e4a36f41SAndroid Build Coastguard Worker  * Given a set of key value pairs, this will construct a new rule map.
804*e4a36f41SAndroid Build Coastguard Worker  * On error this function calls exit.
805*e4a36f41SAndroid Build Coastguard Worker  * @param keys
806*e4a36f41SAndroid Build Coastguard Worker  * 	Keys from a rule line to map
807*e4a36f41SAndroid Build Coastguard Worker  * @param num_of_keys
808*e4a36f41SAndroid Build Coastguard Worker  * 	The length of the keys array
809*e4a36f41SAndroid Build Coastguard Worker  * @param lineno
810*e4a36f41SAndroid Build Coastguard Worker  * 	The line number the keys were extracted from
811*e4a36f41SAndroid Build Coastguard Worker  * @return
812*e4a36f41SAndroid Build Coastguard Worker  * 	A rule map pointer.
813*e4a36f41SAndroid Build Coastguard Worker  */
rule_map_new(kvp keys[],size_t num_of_keys,int lineno,const char * filename,bool is_never_allow)814*e4a36f41SAndroid Build Coastguard Worker static rule_map *rule_map_new(kvp keys[], size_t num_of_keys, int lineno,
815*e4a36f41SAndroid Build Coastguard Worker 		const char *filename, bool is_never_allow) {
816*e4a36f41SAndroid Build Coastguard Worker 
817*e4a36f41SAndroid Build Coastguard Worker 	size_t i = 0, j = 0;
818*e4a36f41SAndroid Build Coastguard Worker 	rule_map *new_map = NULL;
819*e4a36f41SAndroid Build Coastguard Worker 	kvp *k = NULL;
820*e4a36f41SAndroid Build Coastguard Worker 	key_map *r = NULL, *x = NULL;
821*e4a36f41SAndroid Build Coastguard Worker 	bool seen[KVP_NUM_OF_RULES];
822*e4a36f41SAndroid Build Coastguard Worker 
823*e4a36f41SAndroid Build Coastguard Worker 	for (i = 0; i < KVP_NUM_OF_RULES; i++)
824*e4a36f41SAndroid Build Coastguard Worker 		seen[i] = false;
825*e4a36f41SAndroid Build Coastguard Worker 
826*e4a36f41SAndroid Build Coastguard Worker 	new_map = calloc(1, (num_of_keys * sizeof(key_map)) + sizeof(rule_map));
827*e4a36f41SAndroid Build Coastguard Worker 	if (!new_map)
828*e4a36f41SAndroid Build Coastguard Worker 		goto oom;
829*e4a36f41SAndroid Build Coastguard Worker 
830*e4a36f41SAndroid Build Coastguard Worker 	new_map->is_never_allow = is_never_allow;
831*e4a36f41SAndroid Build Coastguard Worker 	new_map->length = num_of_keys;
832*e4a36f41SAndroid Build Coastguard Worker 	new_map->lineno = lineno;
833*e4a36f41SAndroid Build Coastguard Worker 	new_map->filename = strdup(filename);
834*e4a36f41SAndroid Build Coastguard Worker 	if (!new_map->filename) {
835*e4a36f41SAndroid Build Coastguard Worker 		goto oom;
836*e4a36f41SAndroid Build Coastguard Worker 	}
837*e4a36f41SAndroid Build Coastguard Worker 
838*e4a36f41SAndroid Build Coastguard Worker 	/* For all the keys in a rule line*/
839*e4a36f41SAndroid Build Coastguard Worker 	for (i = 0; i < num_of_keys; i++) {
840*e4a36f41SAndroid Build Coastguard Worker 		k = &(keys[i]);
841*e4a36f41SAndroid Build Coastguard Worker 		r = &(new_map->m[i]);
842*e4a36f41SAndroid Build Coastguard Worker 
843*e4a36f41SAndroid Build Coastguard Worker 		for (j = 0; j < KVP_NUM_OF_RULES; j++) {
844*e4a36f41SAndroid Build Coastguard Worker 			x = &(rules[j]);
845*e4a36f41SAndroid Build Coastguard Worker 
846*e4a36f41SAndroid Build Coastguard Worker 			/* Only assign key name to map name */
847*e4a36f41SAndroid Build Coastguard Worker 			if (strcasecmp(k->key, x->name)) {
848*e4a36f41SAndroid Build Coastguard Worker 				if (j == KVP_NUM_OF_RULES - 1) {
849*e4a36f41SAndroid Build Coastguard Worker 					log_error("No match for key: %s\n", k->key);
850*e4a36f41SAndroid Build Coastguard Worker 					goto err;
851*e4a36f41SAndroid Build Coastguard Worker 				}
852*e4a36f41SAndroid Build Coastguard Worker 				continue;
853*e4a36f41SAndroid Build Coastguard Worker 			}
854*e4a36f41SAndroid Build Coastguard Worker 
855*e4a36f41SAndroid Build Coastguard Worker 			if (seen[j]) {
856*e4a36f41SAndroid Build Coastguard Worker 					log_error("Duplicated key: %s\n", k->key);
857*e4a36f41SAndroid Build Coastguard Worker 					goto err;
858*e4a36f41SAndroid Build Coastguard Worker 			}
859*e4a36f41SAndroid Build Coastguard Worker 			seen[j] = true;
860*e4a36f41SAndroid Build Coastguard Worker 
861*e4a36f41SAndroid Build Coastguard Worker 			memcpy(r, x, sizeof(key_map));
862*e4a36f41SAndroid Build Coastguard Worker 
863*e4a36f41SAndroid Build Coastguard Worker 			/* Assign rule map value to one from file */
864*e4a36f41SAndroid Build Coastguard Worker 			r->data = strdup(k->value);
865*e4a36f41SAndroid Build Coastguard Worker 			if (!r->data)
866*e4a36f41SAndroid Build Coastguard Worker 				goto oom;
867*e4a36f41SAndroid Build Coastguard Worker 
868*e4a36f41SAndroid Build Coastguard Worker 			/* Enforce type check*/
869*e4a36f41SAndroid Build Coastguard Worker 			log_info("Validating keys!\n");
870*e4a36f41SAndroid Build Coastguard Worker 			if (!key_map_validate(r, filename, lineno, new_map->is_never_allow)) {
871*e4a36f41SAndroid Build Coastguard Worker 				log_error("Could not validate\n");
872*e4a36f41SAndroid Build Coastguard Worker 				goto err;
873*e4a36f41SAndroid Build Coastguard Worker 			}
874*e4a36f41SAndroid Build Coastguard Worker 
875*e4a36f41SAndroid Build Coastguard Worker 			/*
876*e4a36f41SAndroid Build Coastguard Worker 			 * Only build key off of inputs with the exception of neverallows.
877*e4a36f41SAndroid Build Coastguard Worker 			 * Neverallows are keyed off of all key value pairs,
878*e4a36f41SAndroid Build Coastguard Worker 			 */
879*e4a36f41SAndroid Build Coastguard Worker 			if (r->dir == dir_in || new_map->is_never_allow) {
880*e4a36f41SAndroid Build Coastguard Worker 				char *tmp;
881*e4a36f41SAndroid Build Coastguard Worker 				int key_len = strlen(k->key);
882*e4a36f41SAndroid Build Coastguard Worker 				int val_len = strlen(k->value);
883*e4a36f41SAndroid Build Coastguard Worker 				int l = (new_map->key) ? strlen(new_map->key) : 0;
884*e4a36f41SAndroid Build Coastguard Worker 				l = l + key_len + val_len;
885*e4a36f41SAndroid Build Coastguard Worker 				l += 1;
886*e4a36f41SAndroid Build Coastguard Worker 
887*e4a36f41SAndroid Build Coastguard Worker 				tmp = realloc(new_map->key, l);
888*e4a36f41SAndroid Build Coastguard Worker 				if (!tmp)
889*e4a36f41SAndroid Build Coastguard Worker 					goto oom;
890*e4a36f41SAndroid Build Coastguard Worker 
891*e4a36f41SAndroid Build Coastguard Worker 				if (!new_map->key)
892*e4a36f41SAndroid Build Coastguard Worker 					memset(tmp, 0, l);
893*e4a36f41SAndroid Build Coastguard Worker 
894*e4a36f41SAndroid Build Coastguard Worker 				new_map->key = tmp;
895*e4a36f41SAndroid Build Coastguard Worker 
896*e4a36f41SAndroid Build Coastguard Worker 				strncat(new_map->key, k->key, key_len);
897*e4a36f41SAndroid Build Coastguard Worker 				strncat(new_map->key, k->value, val_len);
898*e4a36f41SAndroid Build Coastguard Worker 			}
899*e4a36f41SAndroid Build Coastguard Worker 			break;
900*e4a36f41SAndroid Build Coastguard Worker 		}
901*e4a36f41SAndroid Build Coastguard Worker 		free_kvp(k);
902*e4a36f41SAndroid Build Coastguard Worker 	}
903*e4a36f41SAndroid Build Coastguard Worker 
904*e4a36f41SAndroid Build Coastguard Worker 	if (new_map->key == NULL) {
905*e4a36f41SAndroid Build Coastguard Worker 		log_error("Strange, no keys found, input file corrupt perhaps?\n");
906*e4a36f41SAndroid Build Coastguard Worker 		goto err;
907*e4a36f41SAndroid Build Coastguard Worker 	}
908*e4a36f41SAndroid Build Coastguard Worker 
909*e4a36f41SAndroid Build Coastguard Worker 	return new_map;
910*e4a36f41SAndroid Build Coastguard Worker 
911*e4a36f41SAndroid Build Coastguard Worker oom:
912*e4a36f41SAndroid Build Coastguard Worker 	log_error("Out of memory!\n");
913*e4a36f41SAndroid Build Coastguard Worker err:
914*e4a36f41SAndroid Build Coastguard Worker 	if (new_map) {
915*e4a36f41SAndroid Build Coastguard Worker 		rule_map_free(new_map, false);
916*e4a36f41SAndroid Build Coastguard Worker 		for (; i < num_of_keys; i++) {
917*e4a36f41SAndroid Build Coastguard Worker 			k = &(keys[i]);
918*e4a36f41SAndroid Build Coastguard Worker 			free_kvp(k);
919*e4a36f41SAndroid Build Coastguard Worker 		}
920*e4a36f41SAndroid Build Coastguard Worker 	}
921*e4a36f41SAndroid Build Coastguard Worker 	return NULL;
922*e4a36f41SAndroid Build Coastguard Worker }
923*e4a36f41SAndroid Build Coastguard Worker 
924*e4a36f41SAndroid Build Coastguard Worker /**
925*e4a36f41SAndroid Build Coastguard Worker  * Print the usage of the program
926*e4a36f41SAndroid Build Coastguard Worker  */
usage()927*e4a36f41SAndroid Build Coastguard Worker static void usage() {
928*e4a36f41SAndroid Build Coastguard Worker 	printf(
929*e4a36f41SAndroid Build Coastguard Worker 	        "checkseapp [options] <input file>\n"
930*e4a36f41SAndroid Build Coastguard Worker 		        "Processes an seapp_contexts file specified by argument <input file> (default stdin) "
931*e4a36f41SAndroid Build Coastguard Worker 		        "and allows later declarations to override previous ones on a match.\n"
932*e4a36f41SAndroid Build Coastguard Worker 		        "Options:\n"
933*e4a36f41SAndroid Build Coastguard Worker 		        "-h - print this help message\n"
934*e4a36f41SAndroid Build Coastguard Worker 		        "-v - enable verbose debugging informations\n"
935*e4a36f41SAndroid Build Coastguard Worker 		        "-p policy file - specify policy file for strict checking of output selectors against the policy\n"
936*e4a36f41SAndroid Build Coastguard Worker 		        "-o output file - specify output file or - for stdout. No argument runs in silent mode and outputs nothing\n");
937*e4a36f41SAndroid Build Coastguard Worker }
938*e4a36f41SAndroid Build Coastguard Worker 
init()939*e4a36f41SAndroid Build Coastguard Worker static void init() {
940*e4a36f41SAndroid Build Coastguard Worker 
941*e4a36f41SAndroid Build Coastguard Worker 	bool has_out_file;
942*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor;
943*e4a36f41SAndroid Build Coastguard Worker 	file_info *tmp;
944*e4a36f41SAndroid Build Coastguard Worker 
945*e4a36f41SAndroid Build Coastguard Worker 	/* input files if the list is empty, use stdin */
946*e4a36f41SAndroid Build Coastguard Worker 	if (!input_file_list.head) {
947*e4a36f41SAndroid Build Coastguard Worker 		log_info("Using stdin for input\n");
948*e4a36f41SAndroid Build Coastguard Worker 		tmp = malloc(sizeof(*tmp));
949*e4a36f41SAndroid Build Coastguard Worker 		if (!tmp) {
950*e4a36f41SAndroid Build Coastguard Worker 			log_error("oom");
951*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
952*e4a36f41SAndroid Build Coastguard Worker 		}
953*e4a36f41SAndroid Build Coastguard Worker 		tmp->name = "stdin";
954*e4a36f41SAndroid Build Coastguard Worker 		tmp->file = stdin;
955*e4a36f41SAndroid Build Coastguard Worker 		list_append(&input_file_list, &(tmp->listify));
956*e4a36f41SAndroid Build Coastguard Worker 	}
957*e4a36f41SAndroid Build Coastguard Worker 	else {
958*e4a36f41SAndroid Build Coastguard Worker 		list_for_each(&input_file_list, cursor) {
959*e4a36f41SAndroid Build Coastguard Worker 			tmp = list_entry(cursor, typeof(*tmp), listify);
960*e4a36f41SAndroid Build Coastguard Worker 
961*e4a36f41SAndroid Build Coastguard Worker 			log_info("Opening input file: \"%s\"\n", tmp->name);
962*e4a36f41SAndroid Build Coastguard Worker 			tmp->file = fopen(tmp->name, "r");
963*e4a36f41SAndroid Build Coastguard Worker 			if (!tmp->file) {
964*e4a36f41SAndroid Build Coastguard Worker 				log_error("Could not open file: %s error: %s\n", tmp->name,
965*e4a36f41SAndroid Build Coastguard Worker 						strerror(errno));
966*e4a36f41SAndroid Build Coastguard Worker 				exit(EXIT_FAILURE);
967*e4a36f41SAndroid Build Coastguard Worker 			}
968*e4a36f41SAndroid Build Coastguard Worker 		}
969*e4a36f41SAndroid Build Coastguard Worker 	}
970*e4a36f41SAndroid Build Coastguard Worker 
971*e4a36f41SAndroid Build Coastguard Worker 	has_out_file = out_file.name != NULL;
972*e4a36f41SAndroid Build Coastguard Worker 
973*e4a36f41SAndroid Build Coastguard Worker 	/* If output file is -, then use stdout, else open the path */
974*e4a36f41SAndroid Build Coastguard Worker 	if (has_out_file && !strcmp(out_file.name, "-")) {
975*e4a36f41SAndroid Build Coastguard Worker 		out_file.file = stdout;
976*e4a36f41SAndroid Build Coastguard Worker 		out_file.name = "stdout";
977*e4a36f41SAndroid Build Coastguard Worker 	}
978*e4a36f41SAndroid Build Coastguard Worker 	else if (has_out_file) {
979*e4a36f41SAndroid Build Coastguard Worker 		out_file.file = fopen(out_file.name, "w+");
980*e4a36f41SAndroid Build Coastguard Worker 	}
981*e4a36f41SAndroid Build Coastguard Worker 
982*e4a36f41SAndroid Build Coastguard Worker 	if (has_out_file && !out_file.file) {
983*e4a36f41SAndroid Build Coastguard Worker 		log_error("Could not open file: \"%s\" error: \"%s\"\n", out_file.name,
984*e4a36f41SAndroid Build Coastguard Worker 				strerror(errno));
985*e4a36f41SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
986*e4a36f41SAndroid Build Coastguard Worker 	}
987*e4a36f41SAndroid Build Coastguard Worker 
988*e4a36f41SAndroid Build Coastguard Worker 	if (pol.policy_file_name) {
989*e4a36f41SAndroid Build Coastguard Worker 		log_info("Opening policy file: %s\n", pol.policy_file_name);
990*e4a36f41SAndroid Build Coastguard Worker 		pol.policy_file = fopen(pol.policy_file_name, "rb");
991*e4a36f41SAndroid Build Coastguard Worker 		if (!pol.policy_file) {
992*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not open file: %s error: %s\n",
993*e4a36f41SAndroid Build Coastguard Worker 					pol.policy_file_name, strerror(errno));
994*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
995*e4a36f41SAndroid Build Coastguard Worker 		}
996*e4a36f41SAndroid Build Coastguard Worker 
997*e4a36f41SAndroid Build Coastguard Worker 		pol.handle = sepol_handle_create();
998*e4a36f41SAndroid Build Coastguard Worker 		if (!pol.handle) {
999*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not create sepolicy handle: %s\n",
1000*e4a36f41SAndroid Build Coastguard Worker 					strerror(errno));
1001*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1002*e4a36f41SAndroid Build Coastguard Worker 		}
1003*e4a36f41SAndroid Build Coastguard Worker 
1004*e4a36f41SAndroid Build Coastguard Worker 		if (sepol_policy_file_create(&pol.pf) < 0) {
1005*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not create sepolicy file: %s!\n",
1006*e4a36f41SAndroid Build Coastguard Worker 					strerror(errno));
1007*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1008*e4a36f41SAndroid Build Coastguard Worker 		}
1009*e4a36f41SAndroid Build Coastguard Worker 
1010*e4a36f41SAndroid Build Coastguard Worker 		sepol_policy_file_set_fp(pol.pf, pol.policy_file);
1011*e4a36f41SAndroid Build Coastguard Worker 		sepol_policy_file_set_handle(pol.pf, pol.handle);
1012*e4a36f41SAndroid Build Coastguard Worker 
1013*e4a36f41SAndroid Build Coastguard Worker 		if (sepol_policydb_create(&pol.db) < 0) {
1014*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not create sepolicy db: %s!\n",
1015*e4a36f41SAndroid Build Coastguard Worker 					strerror(errno));
1016*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1017*e4a36f41SAndroid Build Coastguard Worker 		}
1018*e4a36f41SAndroid Build Coastguard Worker 
1019*e4a36f41SAndroid Build Coastguard Worker 		if (sepol_policydb_read(pol.db, pol.pf) < 0) {
1020*e4a36f41SAndroid Build Coastguard Worker 			log_error("Could not load policy file to db: invalid input file!\n");
1021*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1022*e4a36f41SAndroid Build Coastguard Worker 		}
1023*e4a36f41SAndroid Build Coastguard Worker 	}
1024*e4a36f41SAndroid Build Coastguard Worker 
1025*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&input_file_list, cursor) {
1026*e4a36f41SAndroid Build Coastguard Worker 		tmp = list_entry(cursor, typeof(*tmp), listify);
1027*e4a36f41SAndroid Build Coastguard Worker 		log_info("Input file set to: \"%s\"\n", tmp->name);
1028*e4a36f41SAndroid Build Coastguard Worker 	}
1029*e4a36f41SAndroid Build Coastguard Worker 
1030*e4a36f41SAndroid Build Coastguard Worker 	log_info("Policy file set to: \"%s\"\n",
1031*e4a36f41SAndroid Build Coastguard Worker 			(pol.policy_file_name == NULL) ? "None" : pol.policy_file_name);
1032*e4a36f41SAndroid Build Coastguard Worker 	log_info("Output file set to: \"%s\"\n", out_file.name);
1033*e4a36f41SAndroid Build Coastguard Worker 
1034*e4a36f41SAndroid Build Coastguard Worker #if !defined(LINK_SEPOL_STATIC)
1035*e4a36f41SAndroid Build Coastguard Worker 	log_warn("LINK_SEPOL_STATIC is not defined\n""Not checking types!");
1036*e4a36f41SAndroid Build Coastguard Worker #endif
1037*e4a36f41SAndroid Build Coastguard Worker 
1038*e4a36f41SAndroid Build Coastguard Worker }
1039*e4a36f41SAndroid Build Coastguard Worker 
1040*e4a36f41SAndroid Build Coastguard Worker /**
1041*e4a36f41SAndroid Build Coastguard Worker  * Handle parsing and setting the global flags for the command line
1042*e4a36f41SAndroid Build Coastguard Worker  * options. This function calls exit on failure.
1043*e4a36f41SAndroid Build Coastguard Worker  * @param argc
1044*e4a36f41SAndroid Build Coastguard Worker  * 	argument count
1045*e4a36f41SAndroid Build Coastguard Worker  * @param argv
1046*e4a36f41SAndroid Build Coastguard Worker  * 	argument list
1047*e4a36f41SAndroid Build Coastguard Worker  */
handle_options(int argc,char * argv[])1048*e4a36f41SAndroid Build Coastguard Worker static void handle_options(int argc, char *argv[]) {
1049*e4a36f41SAndroid Build Coastguard Worker 
1050*e4a36f41SAndroid Build Coastguard Worker 	int c;
1051*e4a36f41SAndroid Build Coastguard Worker 	file_info *input_file;
1052*e4a36f41SAndroid Build Coastguard Worker 
1053*e4a36f41SAndroid Build Coastguard Worker 	while ((c = getopt(argc, argv, "ho:p:vc")) != -1) {
1054*e4a36f41SAndroid Build Coastguard Worker 		switch (c) {
1055*e4a36f41SAndroid Build Coastguard Worker 		case 'h':
1056*e4a36f41SAndroid Build Coastguard Worker 			usage();
1057*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_SUCCESS);
1058*e4a36f41SAndroid Build Coastguard Worker 		case 'o':
1059*e4a36f41SAndroid Build Coastguard Worker 			out_file.name = optarg;
1060*e4a36f41SAndroid Build Coastguard Worker 			break;
1061*e4a36f41SAndroid Build Coastguard Worker 		case 'p':
1062*e4a36f41SAndroid Build Coastguard Worker 			pol.policy_file_name = optarg;
1063*e4a36f41SAndroid Build Coastguard Worker 			break;
1064*e4a36f41SAndroid Build Coastguard Worker 		case 'v':
1065*e4a36f41SAndroid Build Coastguard Worker 			log_set_verbose();
1066*e4a36f41SAndroid Build Coastguard Worker 			break;
1067*e4a36f41SAndroid Build Coastguard Worker 		case 'c':
1068*e4a36f41SAndroid Build Coastguard Worker 			pol.vendor = true;
1069*e4a36f41SAndroid Build Coastguard Worker 			break;
1070*e4a36f41SAndroid Build Coastguard Worker 		case '?':
1071*e4a36f41SAndroid Build Coastguard Worker 			if (optopt == 'o' || optopt == 'p')
1072*e4a36f41SAndroid Build Coastguard Worker 				log_error("Option -%c requires an argument.\n", optopt);
1073*e4a36f41SAndroid Build Coastguard Worker 			else if (isprint (optopt))
1074*e4a36f41SAndroid Build Coastguard Worker 				log_error("Unknown option `-%c'.\n", optopt);
1075*e4a36f41SAndroid Build Coastguard Worker 			else {
1076*e4a36f41SAndroid Build Coastguard Worker 				log_error(
1077*e4a36f41SAndroid Build Coastguard Worker 						"Unknown option character `\\x%x'.\n",
1078*e4a36f41SAndroid Build Coastguard Worker 						optopt);
1079*e4a36f41SAndroid Build Coastguard Worker 			}
1080*e4a36f41SAndroid Build Coastguard Worker 		default:
1081*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1082*e4a36f41SAndroid Build Coastguard Worker 		}
1083*e4a36f41SAndroid Build Coastguard Worker 	}
1084*e4a36f41SAndroid Build Coastguard Worker 
1085*e4a36f41SAndroid Build Coastguard Worker 	for (c = optind; c < argc; c++) {
1086*e4a36f41SAndroid Build Coastguard Worker 
1087*e4a36f41SAndroid Build Coastguard Worker 		input_file = calloc(1, sizeof(*input_file));
1088*e4a36f41SAndroid Build Coastguard Worker 		if (!input_file) {
1089*e4a36f41SAndroid Build Coastguard Worker 			log_error("oom");
1090*e4a36f41SAndroid Build Coastguard Worker 			exit(EXIT_FAILURE);
1091*e4a36f41SAndroid Build Coastguard Worker 		}
1092*e4a36f41SAndroid Build Coastguard Worker 		input_file->name = argv[c];
1093*e4a36f41SAndroid Build Coastguard Worker 		list_append(&input_file_list, &input_file->listify);
1094*e4a36f41SAndroid Build Coastguard Worker 	}
1095*e4a36f41SAndroid Build Coastguard Worker }
1096*e4a36f41SAndroid Build Coastguard Worker 
1097*e4a36f41SAndroid Build Coastguard Worker /**
1098*e4a36f41SAndroid Build Coastguard Worker  * Adds a rule to the hash table and to the ordered list if needed.
1099*e4a36f41SAndroid Build Coastguard Worker  * @param rm
1100*e4a36f41SAndroid Build Coastguard Worker  * 	The rule map to add.
1101*e4a36f41SAndroid Build Coastguard Worker  */
rule_add(rule_map * rm)1102*e4a36f41SAndroid Build Coastguard Worker static void rule_add(rule_map *rm) {
1103*e4a36f41SAndroid Build Coastguard Worker 
1104*e4a36f41SAndroid Build Coastguard Worker 	map_match cmp;
1105*e4a36f41SAndroid Build Coastguard Worker 	ENTRY e;
1106*e4a36f41SAndroid Build Coastguard Worker 	ENTRY *f;
1107*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *entry;
1108*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *tmp;
1109*e4a36f41SAndroid Build Coastguard Worker 	list *list_to_addto;
1110*e4a36f41SAndroid Build Coastguard Worker 
1111*e4a36f41SAndroid Build Coastguard Worker 	e.key = rm->key;
1112*e4a36f41SAndroid Build Coastguard Worker 	e.data = NULL;
1113*e4a36f41SAndroid Build Coastguard Worker 
1114*e4a36f41SAndroid Build Coastguard Worker 	log_info("Searching for key: %s\n", e.key);
1115*e4a36f41SAndroid Build Coastguard Worker 	/* Check to see if it has already been added*/
1116*e4a36f41SAndroid Build Coastguard Worker 	f = hsearch(e, FIND);
1117*e4a36f41SAndroid Build Coastguard Worker 
1118*e4a36f41SAndroid Build Coastguard Worker 	/*
1119*e4a36f41SAndroid Build Coastguard Worker 	 * Since your only hashing on a partial key, the inputs we need to handle
1120*e4a36f41SAndroid Build Coastguard Worker 	 * when you want to override the outputs for a given input set, as well as
1121*e4a36f41SAndroid Build Coastguard Worker 	 * checking for duplicate entries.
1122*e4a36f41SAndroid Build Coastguard Worker 	 */
1123*e4a36f41SAndroid Build Coastguard Worker 	if (f) {
1124*e4a36f41SAndroid Build Coastguard Worker 		log_info("Existing entry found!\n");
1125*e4a36f41SAndroid Build Coastguard Worker 		tmp = (hash_entry *)f->data;
1126*e4a36f41SAndroid Build Coastguard Worker 		cmp = rule_map_cmp(rm, tmp->r);
1127*e4a36f41SAndroid Build Coastguard Worker 		log_error("Duplicate line detected in file: %s\n"
1128*e4a36f41SAndroid Build Coastguard Worker 			  "Lines %d and %d %s!\n",
1129*e4a36f41SAndroid Build Coastguard Worker 			  rm->filename, tmp->r->lineno, rm->lineno,
1130*e4a36f41SAndroid Build Coastguard Worker 			  map_match_str[cmp]);
1131*e4a36f41SAndroid Build Coastguard Worker 		rule_map_free(rm, false);
1132*e4a36f41SAndroid Build Coastguard Worker 		goto err;
1133*e4a36f41SAndroid Build Coastguard Worker 	}
1134*e4a36f41SAndroid Build Coastguard Worker 	/* It wasn't found, just add the rule map to the table */
1135*e4a36f41SAndroid Build Coastguard Worker 	else {
1136*e4a36f41SAndroid Build Coastguard Worker 
1137*e4a36f41SAndroid Build Coastguard Worker 		entry = malloc(sizeof(hash_entry));
1138*e4a36f41SAndroid Build Coastguard Worker 		if (!entry)
1139*e4a36f41SAndroid Build Coastguard Worker 			goto oom;
1140*e4a36f41SAndroid Build Coastguard Worker 
1141*e4a36f41SAndroid Build Coastguard Worker 		entry->r = rm;
1142*e4a36f41SAndroid Build Coastguard Worker 		e.data = entry;
1143*e4a36f41SAndroid Build Coastguard Worker 
1144*e4a36f41SAndroid Build Coastguard Worker 		f = hsearch(e, ENTER);
1145*e4a36f41SAndroid Build Coastguard Worker 		if (f == NULL) {
1146*e4a36f41SAndroid Build Coastguard Worker 			goto oom;
1147*e4a36f41SAndroid Build Coastguard Worker 		}
1148*e4a36f41SAndroid Build Coastguard Worker 
1149*e4a36f41SAndroid Build Coastguard Worker 		/* new entries must be added to the ordered list */
1150*e4a36f41SAndroid Build Coastguard Worker 		entry->r = rm;
1151*e4a36f41SAndroid Build Coastguard Worker 		list_to_addto = rm->is_never_allow ? &nallow_list : &line_order_list;
1152*e4a36f41SAndroid Build Coastguard Worker 		list_append(list_to_addto, &entry->listify);
1153*e4a36f41SAndroid Build Coastguard Worker 	}
1154*e4a36f41SAndroid Build Coastguard Worker 
1155*e4a36f41SAndroid Build Coastguard Worker 	return;
1156*e4a36f41SAndroid Build Coastguard Worker oom:
1157*e4a36f41SAndroid Build Coastguard Worker 	if (e.key)
1158*e4a36f41SAndroid Build Coastguard Worker 		free(e.key);
1159*e4a36f41SAndroid Build Coastguard Worker 	if (entry)
1160*e4a36f41SAndroid Build Coastguard Worker 		free(entry);
1161*e4a36f41SAndroid Build Coastguard Worker 	if (rm)
1162*e4a36f41SAndroid Build Coastguard Worker 		free(rm);
1163*e4a36f41SAndroid Build Coastguard Worker 	log_error("Out of memory in function: %s\n", __FUNCTION__);
1164*e4a36f41SAndroid Build Coastguard Worker err:
1165*e4a36f41SAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
1166*e4a36f41SAndroid Build Coastguard Worker }
1167*e4a36f41SAndroid Build Coastguard Worker 
parse_file(file_info * in_file)1168*e4a36f41SAndroid Build Coastguard Worker static void parse_file(file_info *in_file) {
1169*e4a36f41SAndroid Build Coastguard Worker 
1170*e4a36f41SAndroid Build Coastguard Worker 	char *p;
1171*e4a36f41SAndroid Build Coastguard Worker 	size_t len;
1172*e4a36f41SAndroid Build Coastguard Worker 	char *token;
1173*e4a36f41SAndroid Build Coastguard Worker 	char *saveptr;
1174*e4a36f41SAndroid Build Coastguard Worker 	bool is_never_allow;
1175*e4a36f41SAndroid Build Coastguard Worker 	bool found_whitespace;
1176*e4a36f41SAndroid Build Coastguard Worker 
1177*e4a36f41SAndroid Build Coastguard Worker 	size_t lineno = 0;
1178*e4a36f41SAndroid Build Coastguard Worker 	char *name = NULL;
1179*e4a36f41SAndroid Build Coastguard Worker 	char *value = NULL;
1180*e4a36f41SAndroid Build Coastguard Worker 	size_t token_cnt = 0;
1181*e4a36f41SAndroid Build Coastguard Worker 
1182*e4a36f41SAndroid Build Coastguard Worker 	char line_buf[BUFSIZ];
1183*e4a36f41SAndroid Build Coastguard Worker 	kvp keys[KVP_NUM_OF_RULES];
1184*e4a36f41SAndroid Build Coastguard Worker 
1185*e4a36f41SAndroid Build Coastguard Worker 	while (fgets(line_buf, sizeof(line_buf) - 1, in_file->file)) {
1186*e4a36f41SAndroid Build Coastguard Worker 		lineno++;
1187*e4a36f41SAndroid Build Coastguard Worker 		is_never_allow = false;
1188*e4a36f41SAndroid Build Coastguard Worker 		found_whitespace = false;
1189*e4a36f41SAndroid Build Coastguard Worker 		log_info("Got line %zu\n", lineno);
1190*e4a36f41SAndroid Build Coastguard Worker 		len = strlen(line_buf);
1191*e4a36f41SAndroid Build Coastguard Worker 		if (line_buf[len - 1] == '\n')
1192*e4a36f41SAndroid Build Coastguard Worker 			line_buf[len - 1] = '\0';
1193*e4a36f41SAndroid Build Coastguard Worker 		p = line_buf;
1194*e4a36f41SAndroid Build Coastguard Worker 
1195*e4a36f41SAndroid Build Coastguard Worker 		/* neverallow lines must start with neverallow (ie ^neverallow) */
1196*e4a36f41SAndroid Build Coastguard Worker 		if (!strncasecmp(p, "neverallow", strlen("neverallow"))) {
1197*e4a36f41SAndroid Build Coastguard Worker 			p += strlen("neverallow");
1198*e4a36f41SAndroid Build Coastguard Worker 			is_never_allow = true;
1199*e4a36f41SAndroid Build Coastguard Worker 		}
1200*e4a36f41SAndroid Build Coastguard Worker 
1201*e4a36f41SAndroid Build Coastguard Worker 		/* strip trailing whitespace skip comments */
1202*e4a36f41SAndroid Build Coastguard Worker 		while (isspace(*p)) {
1203*e4a36f41SAndroid Build Coastguard Worker 			p++;
1204*e4a36f41SAndroid Build Coastguard Worker 			found_whitespace = true;
1205*e4a36f41SAndroid Build Coastguard Worker 		}
1206*e4a36f41SAndroid Build Coastguard Worker 		if (*p == '#' || *p == '\0')
1207*e4a36f41SAndroid Build Coastguard Worker 			continue;
1208*e4a36f41SAndroid Build Coastguard Worker 
1209*e4a36f41SAndroid Build Coastguard Worker 		token = strtok_r(p, " \t", &saveptr);
1210*e4a36f41SAndroid Build Coastguard Worker 		if (!token)
1211*e4a36f41SAndroid Build Coastguard Worker 			goto err;
1212*e4a36f41SAndroid Build Coastguard Worker 
1213*e4a36f41SAndroid Build Coastguard Worker 		token_cnt = 0;
1214*e4a36f41SAndroid Build Coastguard Worker 		memset(keys, 0, sizeof(kvp) * KVP_NUM_OF_RULES);
1215*e4a36f41SAndroid Build Coastguard Worker 		while (1) {
1216*e4a36f41SAndroid Build Coastguard Worker 
1217*e4a36f41SAndroid Build Coastguard Worker 			name = token;
1218*e4a36f41SAndroid Build Coastguard Worker 			value = strchr(name, '=');
1219*e4a36f41SAndroid Build Coastguard Worker 			if (!value)
1220*e4a36f41SAndroid Build Coastguard Worker 				goto err;
1221*e4a36f41SAndroid Build Coastguard Worker 			*value++ = 0;
1222*e4a36f41SAndroid Build Coastguard Worker 
1223*e4a36f41SAndroid Build Coastguard Worker 			keys[token_cnt].key = strdup(name);
1224*e4a36f41SAndroid Build Coastguard Worker 			if (!keys[token_cnt].key)
1225*e4a36f41SAndroid Build Coastguard Worker 				goto oom;
1226*e4a36f41SAndroid Build Coastguard Worker 
1227*e4a36f41SAndroid Build Coastguard Worker 			keys[token_cnt].value = strdup(value);
1228*e4a36f41SAndroid Build Coastguard Worker 			if (!keys[token_cnt].value)
1229*e4a36f41SAndroid Build Coastguard Worker 				goto oom;
1230*e4a36f41SAndroid Build Coastguard Worker 
1231*e4a36f41SAndroid Build Coastguard Worker 			token_cnt++;
1232*e4a36f41SAndroid Build Coastguard Worker 
1233*e4a36f41SAndroid Build Coastguard Worker 			token = strtok_r(NULL, " \t", &saveptr);
1234*e4a36f41SAndroid Build Coastguard Worker 			if (!token)
1235*e4a36f41SAndroid Build Coastguard Worker 				break;
1236*e4a36f41SAndroid Build Coastguard Worker 
1237*e4a36f41SAndroid Build Coastguard Worker 			if (token_cnt == KVP_NUM_OF_RULES)
1238*e4a36f41SAndroid Build Coastguard Worker 				goto oob;
1239*e4a36f41SAndroid Build Coastguard Worker 
1240*e4a36f41SAndroid Build Coastguard Worker 		} /*End token parsing */
1241*e4a36f41SAndroid Build Coastguard Worker 
1242*e4a36f41SAndroid Build Coastguard Worker 		rule_map *r = rule_map_new(keys, token_cnt, lineno, in_file->name, is_never_allow);
1243*e4a36f41SAndroid Build Coastguard Worker 		if (!r)
1244*e4a36f41SAndroid Build Coastguard Worker 			goto err;
1245*e4a36f41SAndroid Build Coastguard Worker 		rule_add(r);
1246*e4a36f41SAndroid Build Coastguard Worker 
1247*e4a36f41SAndroid Build Coastguard Worker 	} /* End file parsing */
1248*e4a36f41SAndroid Build Coastguard Worker 	return;
1249*e4a36f41SAndroid Build Coastguard Worker 
1250*e4a36f41SAndroid Build Coastguard Worker err:
1251*e4a36f41SAndroid Build Coastguard Worker 	log_error("Reading file: \"%s\" line: %zu name: \"%s\" value: \"%s\"\n",
1252*e4a36f41SAndroid Build Coastguard Worker 		in_file->name, lineno, name, value);
1253*e4a36f41SAndroid Build Coastguard Worker 	if (found_whitespace && name && !strcasecmp(name, "neverallow")) {
1254*e4a36f41SAndroid Build Coastguard Worker 		log_error("perhaps whitespace before neverallow\n");
1255*e4a36f41SAndroid Build Coastguard Worker 	}
1256*e4a36f41SAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
1257*e4a36f41SAndroid Build Coastguard Worker oom:
1258*e4a36f41SAndroid Build Coastguard Worker 	log_error("In function %s:  Out of memory\n", __FUNCTION__);
1259*e4a36f41SAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
1260*e4a36f41SAndroid Build Coastguard Worker oob:
1261*e4a36f41SAndroid Build Coastguard Worker 	log_error("Reading file: \"%s\" line: %zu reason: the size of key pairs exceeds the MAX(%zu)\n",
1262*e4a36f41SAndroid Build Coastguard Worker 		in_file->name, lineno, KVP_NUM_OF_RULES);
1263*e4a36f41SAndroid Build Coastguard Worker 	exit(EXIT_FAILURE);
1264*e4a36f41SAndroid Build Coastguard Worker }
1265*e4a36f41SAndroid Build Coastguard Worker 
1266*e4a36f41SAndroid Build Coastguard Worker /**
1267*e4a36f41SAndroid Build Coastguard Worker  * Parses the seapp_contexts file and neverallow file
1268*e4a36f41SAndroid Build Coastguard Worker  * and adds them to the hash table and ordered list entries
1269*e4a36f41SAndroid Build Coastguard Worker  * when it encounters them.
1270*e4a36f41SAndroid Build Coastguard Worker  * Calls exit on failure.
1271*e4a36f41SAndroid Build Coastguard Worker  */
parse()1272*e4a36f41SAndroid Build Coastguard Worker static void parse() {
1273*e4a36f41SAndroid Build Coastguard Worker 
1274*e4a36f41SAndroid Build Coastguard Worker 	file_info *current;
1275*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor;
1276*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&input_file_list, cursor) {
1277*e4a36f41SAndroid Build Coastguard Worker 		current = list_entry(cursor, typeof(*current), listify);
1278*e4a36f41SAndroid Build Coastguard Worker 		parse_file(current);
1279*e4a36f41SAndroid Build Coastguard Worker 	}
1280*e4a36f41SAndroid Build Coastguard Worker }
1281*e4a36f41SAndroid Build Coastguard Worker 
validate()1282*e4a36f41SAndroid Build Coastguard Worker static void validate() {
1283*e4a36f41SAndroid Build Coastguard Worker 
1284*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor, *v;
1285*e4a36f41SAndroid Build Coastguard Worker 	bool found_issues = false;
1286*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *e;
1287*e4a36f41SAndroid Build Coastguard Worker 	rule_map *r;
1288*e4a36f41SAndroid Build Coastguard Worker 	coredomain_violation_entry *c;
1289*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&line_order_list, cursor) {
1290*e4a36f41SAndroid Build Coastguard Worker 		e = list_entry(cursor, typeof(*e), listify);
1291*e4a36f41SAndroid Build Coastguard Worker 		rule_map_validate(e->r);
1292*e4a36f41SAndroid Build Coastguard Worker 	}
1293*e4a36f41SAndroid Build Coastguard Worker 
1294*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&line_order_list, cursor) {
1295*e4a36f41SAndroid Build Coastguard Worker 		e = list_entry(cursor, typeof(*e), listify);
1296*e4a36f41SAndroid Build Coastguard Worker 		r = e->r;
1297*e4a36f41SAndroid Build Coastguard Worker 		list_for_each(&r->violations, v) {
1298*e4a36f41SAndroid Build Coastguard Worker 			found_issues = true;
1299*e4a36f41SAndroid Build Coastguard Worker 			log_error("Rule in File \"%s\" on line %d: \"", e->r->filename, e->r->lineno);
1300*e4a36f41SAndroid Build Coastguard Worker 			rule_map_print(stderr, e->r);
1301*e4a36f41SAndroid Build Coastguard Worker 			r = list_entry(v, rule_map, listify);
1302*e4a36f41SAndroid Build Coastguard Worker 			fprintf(stderr, "\" violates neverallow in File \"%s\" on line %d: \"", r->filename, r->lineno);
1303*e4a36f41SAndroid Build Coastguard Worker 			rule_map_print(stderr, r);
1304*e4a36f41SAndroid Build Coastguard Worker 			fprintf(stderr, "\"\n");
1305*e4a36f41SAndroid Build Coastguard Worker 		}
1306*e4a36f41SAndroid Build Coastguard Worker 	}
1307*e4a36f41SAndroid Build Coastguard Worker 
1308*e4a36f41SAndroid Build Coastguard Worker 	bool coredomain_violation = false;
1309*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&coredomain_violation_list, cursor) {
1310*e4a36f41SAndroid Build Coastguard Worker 		c = list_entry(cursor, typeof(*c), listify);
1311*e4a36f41SAndroid Build Coastguard Worker 		fprintf(stderr, "Forbidden attribute " COREDOMAIN " assigned to domain \"%s\" in "
1312*e4a36f41SAndroid Build Coastguard Worker 		        "File \"%s\" on line %d\n", c->domain, c->filename, c->lineno);
1313*e4a36f41SAndroid Build Coastguard Worker 		coredomain_violation = true;
1314*e4a36f41SAndroid Build Coastguard Worker 	}
1315*e4a36f41SAndroid Build Coastguard Worker 
1316*e4a36f41SAndroid Build Coastguard Worker 	if (coredomain_violation) {
1317*e4a36f41SAndroid Build Coastguard Worker 		fprintf(stderr, "********************************************************************************\n");
1318*e4a36f41SAndroid Build Coastguard Worker 		fprintf(stderr, "You tried to assign coredomain with vendor seapp_contexts, which is not allowed.\n"
1319*e4a36f41SAndroid Build Coastguard Worker 		        "Either move offending entries to system, system_ext, or product seapp_contexts,\n"
1320*e4a36f41SAndroid Build Coastguard Worker 		        "or remove 'coredomain' attribute from the domains.\n"
1321*e4a36f41SAndroid Build Coastguard Worker 		        "See an example of how to fix this:\n"
1322*e4a36f41SAndroid Build Coastguard Worker 		        "https://android-review.googlesource.com/2671075\n");
1323*e4a36f41SAndroid Build Coastguard Worker 		fprintf(stderr, "********************************************************************************\n");
1324*e4a36f41SAndroid Build Coastguard Worker 		found_issues = true;
1325*e4a36f41SAndroid Build Coastguard Worker 	}
1326*e4a36f41SAndroid Build Coastguard Worker 
1327*e4a36f41SAndroid Build Coastguard Worker 	if (found_issues) {
1328*e4a36f41SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
1329*e4a36f41SAndroid Build Coastguard Worker 	}
1330*e4a36f41SAndroid Build Coastguard Worker }
1331*e4a36f41SAndroid Build Coastguard Worker 
1332*e4a36f41SAndroid Build Coastguard Worker /**
1333*e4a36f41SAndroid Build Coastguard Worker  * Should be called after parsing to cause the printing of the rule_maps
1334*e4a36f41SAndroid Build Coastguard Worker  * stored in the ordered list, head first, which preserves the "first encountered"
1335*e4a36f41SAndroid Build Coastguard Worker  * ordering.
1336*e4a36f41SAndroid Build Coastguard Worker  */
output()1337*e4a36f41SAndroid Build Coastguard Worker static void output() {
1338*e4a36f41SAndroid Build Coastguard Worker 
1339*e4a36f41SAndroid Build Coastguard Worker 	hash_entry *e;
1340*e4a36f41SAndroid Build Coastguard Worker 	list_element *cursor;
1341*e4a36f41SAndroid Build Coastguard Worker 
1342*e4a36f41SAndroid Build Coastguard Worker 	if (!out_file.file) {
1343*e4a36f41SAndroid Build Coastguard Worker 		log_info("No output file, not outputting.\n");
1344*e4a36f41SAndroid Build Coastguard Worker 		return;
1345*e4a36f41SAndroid Build Coastguard Worker 	}
1346*e4a36f41SAndroid Build Coastguard Worker 
1347*e4a36f41SAndroid Build Coastguard Worker 	list_for_each(&line_order_list, cursor) {
1348*e4a36f41SAndroid Build Coastguard Worker 		e = list_entry(cursor, hash_entry, listify);
1349*e4a36f41SAndroid Build Coastguard Worker 		rule_map_print(out_file.file, e->r);
1350*e4a36f41SAndroid Build Coastguard Worker 		fprintf(out_file.file, "\n");
1351*e4a36f41SAndroid Build Coastguard Worker 	}
1352*e4a36f41SAndroid Build Coastguard Worker }
1353*e4a36f41SAndroid Build Coastguard Worker 
1354*e4a36f41SAndroid Build Coastguard Worker /**
1355*e4a36f41SAndroid Build Coastguard Worker  * This function is registered to the at exit handler and should clean up
1356*e4a36f41SAndroid Build Coastguard Worker  * the programs dynamic resources, such as memory and fd's.
1357*e4a36f41SAndroid Build Coastguard Worker  */
cleanup()1358*e4a36f41SAndroid Build Coastguard Worker static void cleanup() {
1359*e4a36f41SAndroid Build Coastguard Worker 
1360*e4a36f41SAndroid Build Coastguard Worker 	/* Only close this when it was opened by me and not the crt */
1361*e4a36f41SAndroid Build Coastguard Worker 	if (out_file.name && strcmp(out_file.name, "stdout") && out_file.file) {
1362*e4a36f41SAndroid Build Coastguard Worker 		log_info("Closing file: %s\n", out_file.name);
1363*e4a36f41SAndroid Build Coastguard Worker 		fclose(out_file.file);
1364*e4a36f41SAndroid Build Coastguard Worker 	}
1365*e4a36f41SAndroid Build Coastguard Worker 
1366*e4a36f41SAndroid Build Coastguard Worker 	if (pol.policy_file) {
1367*e4a36f41SAndroid Build Coastguard Worker 
1368*e4a36f41SAndroid Build Coastguard Worker 		log_info("Closing file: %s\n", pol.policy_file_name);
1369*e4a36f41SAndroid Build Coastguard Worker 		fclose(pol.policy_file);
1370*e4a36f41SAndroid Build Coastguard Worker 
1371*e4a36f41SAndroid Build Coastguard Worker 		if (pol.db)
1372*e4a36f41SAndroid Build Coastguard Worker 			sepol_policydb_free(pol.db);
1373*e4a36f41SAndroid Build Coastguard Worker 
1374*e4a36f41SAndroid Build Coastguard Worker 		if (pol.pf)
1375*e4a36f41SAndroid Build Coastguard Worker 			sepol_policy_file_free(pol.pf);
1376*e4a36f41SAndroid Build Coastguard Worker 
1377*e4a36f41SAndroid Build Coastguard Worker 		if (pol.handle)
1378*e4a36f41SAndroid Build Coastguard Worker 			sepol_handle_destroy(pol.handle);
1379*e4a36f41SAndroid Build Coastguard Worker 	}
1380*e4a36f41SAndroid Build Coastguard Worker 
1381*e4a36f41SAndroid Build Coastguard Worker 	log_info("Freeing lists\n");
1382*e4a36f41SAndroid Build Coastguard Worker 	list_free(&input_file_list);
1383*e4a36f41SAndroid Build Coastguard Worker 	list_free(&line_order_list);
1384*e4a36f41SAndroid Build Coastguard Worker 	list_free(&nallow_list);
1385*e4a36f41SAndroid Build Coastguard Worker 	list_free(&coredomain_violation_list);
1386*e4a36f41SAndroid Build Coastguard Worker 	hdestroy();
1387*e4a36f41SAndroid Build Coastguard Worker }
1388*e4a36f41SAndroid Build Coastguard Worker 
main(int argc,char * argv[])1389*e4a36f41SAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
1390*e4a36f41SAndroid Build Coastguard Worker 	if (!hcreate(TABLE_SIZE)) {
1391*e4a36f41SAndroid Build Coastguard Worker 		log_error("Could not create hash table: %s\n", strerror(errno));
1392*e4a36f41SAndroid Build Coastguard Worker 		exit(EXIT_FAILURE);
1393*e4a36f41SAndroid Build Coastguard Worker 	}
1394*e4a36f41SAndroid Build Coastguard Worker 	atexit(cleanup);
1395*e4a36f41SAndroid Build Coastguard Worker 	handle_options(argc, argv);
1396*e4a36f41SAndroid Build Coastguard Worker 	init();
1397*e4a36f41SAndroid Build Coastguard Worker 	log_info("Starting to parse\n");
1398*e4a36f41SAndroid Build Coastguard Worker 	parse();
1399*e4a36f41SAndroid Build Coastguard Worker 	log_info("Parsing completed, generating output\n");
1400*e4a36f41SAndroid Build Coastguard Worker 	validate();
1401*e4a36f41SAndroid Build Coastguard Worker 	output();
1402*e4a36f41SAndroid Build Coastguard Worker 	log_info("Success, generated output\n");
1403*e4a36f41SAndroid Build Coastguard Worker 	exit(EXIT_SUCCESS);
1404*e4a36f41SAndroid Build Coastguard Worker }
1405