1 #include <stdarg.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <inttypes.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 
9 #include <arpa/inet.h>
10 #include <netinet/in.h>
11 #ifndef IPPROTO_DCCP
12 #define IPPROTO_DCCP 33
13 #endif
14 #ifndef IPPROTO_SCTP
15 #define IPPROTO_SCTP 132
16 #endif
17 
18 #include <sepol/policydb/avtab.h>
19 #include <sepol/policydb/conditional.h>
20 #include <sepol/policydb/flask.h>
21 #include <sepol/policydb/hashtab.h>
22 #include <sepol/policydb/polcaps.h>
23 #include <sepol/policydb/policydb.h>
24 #include <sepol/policydb/services.h>
25 #include <sepol/policydb/util.h>
26 
27 #include "kernel_to_common.h"
28 
29 
cond_expr_to_str(struct policydb * pdb,struct cond_expr * expr)30 static char *cond_expr_to_str(struct policydb *pdb, struct cond_expr *expr)
31 {
32 	struct cond_expr *curr;
33 	struct strs *stack;
34 	char *new_val;
35 	char *str = NULL;
36 	int rc;
37 
38 	rc = strs_stack_init(&stack);
39 	if (rc != 0) {
40 		goto exit;
41 	}
42 
43 	for (curr = expr; curr != NULL; curr = curr->next) {
44 		if (curr->expr_type == COND_BOOL) {
45 			char *val1 = pdb->p_bool_val_to_name[curr->bool - 1];
46 			new_val = create_str("%s", 1, val1);
47 		} else {
48 			const char *op;
49 			uint32_t num_params;
50 			char *val1 = NULL;
51 			char *val2 = NULL;
52 
53 			switch(curr->expr_type) {
54 			case COND_NOT:	op = "!";  num_params = 1; break;
55 			case COND_OR:	op = "||"; num_params = 2; break;
56 			case COND_AND:	op = "&&"; num_params = 2; break;
57 			case COND_XOR:	op = "^";  num_params = 2; break;
58 			case COND_EQ:	op = "=="; num_params = 2; break;
59 			case COND_NEQ:	op = "!="; num_params = 2; break;
60 			default:
61 				sepol_log_err("Unknown conditional operator: %i", curr->expr_type);
62 				goto exit;
63 			}
64 
65 			if (num_params == 2) {
66 				val2 = strs_stack_pop(stack);
67 				if (!val2) {
68 					sepol_log_err("Invalid conditional expression");
69 					goto exit;
70 				}
71 			}
72 			val1 = strs_stack_pop(stack);
73 			if (!val1) {
74 				sepol_log_err("Invalid conditional expression");
75 				free(val2);
76 				goto exit;
77 			}
78 			if (num_params == 2) {
79 				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
80 				free(val2);
81 			} else {
82 				new_val = create_str("%s %s", 2, op, val1);
83 			}
84 			free(val1);
85 		}
86 		if (!new_val) {
87 			sepol_log_err("Invalid conditional expression");
88 			goto exit;
89 		}
90 		rc = strs_stack_push(stack, new_val);
91 		if (rc != 0) {
92 			sepol_log_err("Out of memory");
93 			goto exit;
94 		}
95 	}
96 
97 	new_val = strs_stack_pop(stack);
98 	if (!new_val || !strs_stack_empty(stack)) {
99 		sepol_log_err("Invalid conditional expression");
100 		goto exit;
101 	}
102 
103 	str = new_val;
104 
105 	strs_stack_destroy(&stack);
106 	return str;
107 
108 exit:
109 	if (stack) {
110 		while ((new_val = strs_stack_pop(stack)) != NULL) {
111 			free(new_val);
112 		}
113 		strs_stack_destroy(&stack);
114 	}
115 
116 	return NULL;
117 }
118 
constraint_expr_to_str(struct policydb * pdb,struct constraint_expr * expr,int * use_mls)119 static char *constraint_expr_to_str(struct policydb *pdb, struct constraint_expr *expr, int *use_mls)
120 {
121 	struct constraint_expr *curr;
122 	struct strs *stack = NULL;
123 	char *new_val = NULL;
124 	const char *op;
125 	char *str = NULL;
126 	int rc;
127 
128 	*use_mls = 0;
129 
130 	rc = strs_stack_init(&stack);
131 	if (rc != 0) {
132 		goto exit;
133 	}
134 
135 	for (curr = expr; curr; curr = curr->next) {
136 		if (curr->expr_type == CEXPR_ATTR || curr->expr_type == CEXPR_NAMES) {
137 			const char *attr1 = NULL;
138 			const char *attr2 = NULL;
139 
140 			switch (curr->op) {
141 			case CEXPR_EQ:      op = "==";     break;
142 			case CEXPR_NEQ:     op = "!=";    break;
143 			case CEXPR_DOM:     op = "dom";    break;
144 			case CEXPR_DOMBY:   op = "domby";  break;
145 			case CEXPR_INCOMP:  op = "incomp"; break;
146 			default:
147 				sepol_log_err("Unknown constraint operator: %i", curr->op);
148 				goto exit;
149 			}
150 
151 			switch (curr->attr) {
152 			case CEXPR_USER:                 attr1 ="u1"; attr2 ="u2"; break;
153 			case CEXPR_USER | CEXPR_TARGET:  attr1 ="u2"; attr2 ="";   break;
154 			case CEXPR_USER | CEXPR_XTARGET: attr1 ="u3"; attr2 ="";   break;
155 			case CEXPR_ROLE:                 attr1 ="r1"; attr2 ="r2"; break;
156 			case CEXPR_ROLE | CEXPR_TARGET:  attr1 ="r2"; attr2 ="";   break;
157 			case CEXPR_ROLE | CEXPR_XTARGET: attr1 ="r3"; attr2 ="";   break;
158 			case CEXPR_TYPE:                 attr1 ="t1"; attr2 ="t2"; break;
159 			case CEXPR_TYPE | CEXPR_TARGET:  attr1 ="t2"; attr2 ="";   break;
160 			case CEXPR_TYPE | CEXPR_XTARGET: attr1 ="t3"; attr2 ="";   break;
161 			case CEXPR_L1L2:                 attr1 ="l1"; attr2 ="l2"; break;
162 			case CEXPR_L1H2:                 attr1 ="l1"; attr2 ="h2"; break;
163 			case CEXPR_H1L2:                 attr1 ="h1"; attr2 ="l2"; break;
164 			case CEXPR_H1H2:                 attr1 ="h1"; attr2 ="h2"; break;
165 			case CEXPR_L1H1:                 attr1 ="l1"; attr2 ="h1"; break;
166 			case CEXPR_L2H2:                 attr1 ="l2"; attr2 ="h2"; break;
167 			default:
168 				sepol_log_err("Unknown constraint attribute: %i", curr->attr);
169 				goto exit;
170 			}
171 
172 			if (curr->attr >= CEXPR_XTARGET) {
173 				*use_mls = 1;
174 			}
175 
176 			if (curr->expr_type == CEXPR_ATTR) {
177 				new_val = create_str("%s %s %s", 3, attr1, op, attr2);
178 			} else {
179 				char *names = NULL;
180 				if (curr->attr & CEXPR_TYPE) {
181 					struct type_set *ts = curr->type_names;
182 					names = ebitmap_to_str(&ts->types, pdb->p_type_val_to_name, 1);
183 				} else if (curr->attr & CEXPR_USER) {
184 					names = ebitmap_to_str(&curr->names, pdb->p_user_val_to_name, 1);
185 				} else if (curr->attr & CEXPR_ROLE) {
186 					names = ebitmap_to_str(&curr->names, pdb->p_role_val_to_name, 1);
187 				}
188 				if (!names) {
189 					goto exit;
190 				}
191 				new_val = create_str("%s %s %s", 3, attr1, op, names);
192 				free(names);
193 			}
194 		} else {
195 			uint32_t num_params;
196 			char *val1 = NULL;
197 			char *val2 = NULL;
198 
199 			switch (curr->expr_type) {
200 			case CEXPR_NOT: op = "not"; num_params = 1; break;
201 			case CEXPR_AND: op = "and"; num_params = 2; break;
202 			case CEXPR_OR:  op = "or";  num_params = 2; break;
203 			default:
204 				sepol_log_err("Unknown constraint expression type: %i", curr->expr_type);
205 				goto exit;
206 			}
207 
208 			if (num_params == 2) {
209 				val2 = strs_stack_pop(stack);
210 				if (!val2) {
211 					sepol_log_err("Invalid constraint expression");
212 					goto exit;
213 				}
214 			}
215 			val1 = strs_stack_pop(stack);
216 			if (!val1) {
217 				sepol_log_err("Invalid constraint expression");
218 				goto exit;
219 			}
220 
221 			if (num_params == 2) {
222 				new_val = create_str("(%s %s %s)", 3, val1, op, val2);
223 				free(val2);
224 			} else {
225 				new_val = create_str("%s (%s)", 2, op, val1);
226 			}
227 			free(val1);
228 		}
229 		if (!new_val) {
230 			goto exit;
231 		}
232 		rc = strs_stack_push(stack, new_val);
233 		if (rc != 0) {
234 			sepol_log_err("Out of memory");
235 			goto exit;
236 		}
237 	}
238 
239 	new_val = strs_stack_pop(stack);
240 	if (!new_val || !strs_stack_empty(stack)) {
241 		sepol_log_err("Invalid constraint expression");
242 		goto exit;
243 	}
244 
245 	str = new_val;
246 
247 	strs_stack_destroy(&stack);
248 
249 	return str;
250 
251 exit:
252 	if (stack) {
253 		while ((new_val = strs_stack_pop(stack)) != NULL) {
254 			free(new_val);
255 		}
256 		strs_stack_destroy(&stack);
257 	}
258 
259 	return NULL;
260 }
261 
class_constraint_rules_to_strs(struct policydb * pdb,char * classkey,class_datum_t * class,struct constraint_node * constraint_rules,struct strs * mls_list,struct strs * non_mls_list)262 static int class_constraint_rules_to_strs(struct policydb *pdb, char *classkey,
263 					  class_datum_t *class,
264 					  struct constraint_node *constraint_rules,
265 					  struct strs *mls_list,
266 					  struct strs *non_mls_list)
267 {
268 	struct constraint_node *curr;
269 	struct strs *strs;
270 	const char *format_str, *flavor;
271 	char *perms, *expr;
272 	int is_mls;
273 	int rc = 0;
274 
275 	for (curr = constraint_rules; curr != NULL; curr = curr->next) {
276 		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
277 		if (!expr) {
278 			rc = -1;
279 			goto exit;
280 		}
281 
282 		perms = sepol_av_to_string(pdb, class->s.value, curr->permissions);
283 		if (strchr(perms, ' ')) {
284 			format_str = "%s %s { %s } %s;";
285 		} else {
286 			format_str = "%s %s %s %s";
287 		}
288 		if (is_mls) {
289 			flavor = "mlsconstrain";
290 			strs = mls_list;
291 		} else {
292 			flavor = "constrain";
293 			strs = non_mls_list;
294 		}
295 
296 		rc = strs_create_and_add(strs, format_str, 4,
297 					 flavor, classkey, perms+1, expr);
298 		free(expr);
299 		if (rc != 0) {
300 			goto exit;
301 		}
302 	}
303 
304 	return 0;
305 exit:
306 	sepol_log_err("Error gathering constraint rules\n");
307 	return rc;
308 }
309 
class_validatetrans_rules_to_strs(struct policydb * pdb,char * classkey,struct constraint_node * validatetrans_rules,struct strs * mls_list,struct strs * non_mls_list)310 static int class_validatetrans_rules_to_strs(struct policydb *pdb, char *classkey,
311 					     struct constraint_node *validatetrans_rules,
312 					     struct strs *mls_list,
313 					     struct strs *non_mls_list)
314 {
315 	struct constraint_node *curr;
316 	struct strs *strs;
317 	const char *flavor;
318 	char *expr;
319 	int is_mls;
320 	int rc = 0;
321 
322 	for (curr = validatetrans_rules; curr != NULL; curr = curr->next) {
323 		expr = constraint_expr_to_str(pdb, curr->expr, &is_mls);
324 		if (!expr) {
325 			rc = -1;
326 			goto exit;
327 		}
328 
329 		if (is_mls) {
330 			flavor = "mlsvalidatetrans";
331 			strs = mls_list;
332 		} else {
333 			flavor = "validatetrans";
334 			strs = non_mls_list;
335 		}
336 
337 		rc = strs_create_and_add(strs, "%s %s %s;", 3, flavor, classkey, expr);
338 		free(expr);
339 		if (rc != 0) {
340 			goto exit;
341 		}
342 	}
343 
344 exit:
345 	return rc;
346 }
347 
constraint_rules_to_strs(struct policydb * pdb,struct strs * mls_strs,struct strs * non_mls_strs)348 static int constraint_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
349 {
350 	class_datum_t *class;
351 	char *name;
352 	unsigned i;
353 	int rc = 0;
354 
355 	for (i=0; i < pdb->p_classes.nprim; i++) {
356 		class = pdb->class_val_to_struct[i];
357 		if (class->constraints) {
358 			name = pdb->p_class_val_to_name[i];
359 			rc = class_constraint_rules_to_strs(pdb, name, class, class->constraints, mls_strs, non_mls_strs);
360 			if (rc != 0) {
361 				goto exit;
362 			}
363 		}
364 	}
365 
366 	strs_sort(mls_strs);
367 	strs_sort(non_mls_strs);
368 
369 exit:
370 	return rc;
371 }
372 
validatetrans_rules_to_strs(struct policydb * pdb,struct strs * mls_strs,struct strs * non_mls_strs)373 static int validatetrans_rules_to_strs(struct policydb *pdb, struct strs *mls_strs, struct strs *non_mls_strs)
374 {
375 	class_datum_t *class;
376 	char *name;
377 	unsigned i;
378 	int rc = 0;
379 
380 	for (i=0; i < pdb->p_classes.nprim; i++) {
381 		class = pdb->class_val_to_struct[i];
382 		if (class->validatetrans) {
383 			name = pdb->p_class_val_to_name[i];
384 			rc = class_validatetrans_rules_to_strs(pdb, name, class->validatetrans, mls_strs, non_mls_strs);
385 			if (rc != 0) {
386 				goto exit;
387 			}
388 		}
389 	}
390 
391 	strs_sort(mls_strs);
392 	strs_sort(non_mls_strs);
393 
394 exit:
395 	return rc;
396 }
397 
write_handle_unknown_to_conf(FILE * out,struct policydb * pdb)398 static int write_handle_unknown_to_conf(FILE *out, struct policydb *pdb)
399 {
400 	const char *action;
401 
402 	switch (pdb->handle_unknown) {
403 	case SEPOL_DENY_UNKNOWN:
404 		action = "deny";
405 		break;
406 	case SEPOL_REJECT_UNKNOWN:
407 		action = "reject";
408 		break;
409 	case SEPOL_ALLOW_UNKNOWN:
410 		action = "allow";
411 		break;
412 	default:
413 		sepol_log_err("Unknown value for handle-unknown: %i", pdb->handle_unknown);
414 		return -1;
415 	}
416 
417 	sepol_printf(out, "# handle_unknown %s\n", action);
418 
419 	return 0;
420 }
421 
write_class_decl_rules_to_conf(FILE * out,struct policydb * pdb)422 static int write_class_decl_rules_to_conf(FILE *out, struct policydb *pdb)
423 {
424 	char *name;
425 	unsigned i;
426 
427 	for (i=0; i < pdb->p_classes.nprim; i++) {
428 		name = pdb->p_class_val_to_name[i];
429 		sepol_printf(out, "class %s\n", name);
430 	}
431 
432 	return 0;
433 }
434 
write_sids_to_conf(FILE * out,const char * const * sid_to_str,unsigned num_sids,struct ocontext * isids)435 static int write_sids_to_conf(FILE *out, const char *const *sid_to_str,
436 			      unsigned num_sids, struct ocontext *isids)
437 {
438 	struct ocontext *isid;
439 	struct strs *strs;
440 	char *sid;
441 	char unknown[18];
442 	unsigned i;
443 	int rc;
444 
445 	rc = strs_init(&strs, num_sids+1);
446 	if (rc != 0) {
447 		goto exit;
448 	}
449 
450 	for (isid = isids; isid != NULL; isid = isid->next) {
451 		i = isid->sid[0];
452 		if (i < num_sids) {
453 			sid = (char *)sid_to_str[i];
454 		} else {
455 			snprintf(unknown, sizeof(unknown), "%s%u", "UNKNOWN", i);
456 			sid = strdup(unknown);
457 			if (!sid) {
458 				rc = -1;
459 				goto exit;
460 			}
461 		}
462 		rc = strs_add_at_index(strs, sid, i);
463 		if (rc != 0) {
464 			goto exit;
465 		}
466 	}
467 
468 	for (i=0; i<strs_num_items(strs); i++) {
469 		sid = strs_read_at_index(strs, i);
470 		if (!sid) {
471 			continue;
472 		}
473 		sepol_printf(out, "sid %s\n", sid);
474 	}
475 
476 exit:
477 	for (i=num_sids; i<strs_num_items(strs); i++) {
478 		sid = strs_read_at_index(strs, i);
479 		free(sid);
480 	}
481 	strs_destroy(&strs);
482 	if (rc != 0) {
483 		sepol_log_err("Error writing sid rules to policy.conf\n");
484 	}
485 
486 	return rc;
487 }
488 
write_sid_decl_rules_to_conf(FILE * out,struct policydb * pdb)489 static int write_sid_decl_rules_to_conf(FILE *out, struct policydb *pdb)
490 {
491 	int rc = 0;
492 
493 	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
494 		rc = write_sids_to_conf(out, selinux_sid_to_str, SELINUX_SID_SZ,
495 					pdb->ocontexts[0]);
496 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
497 		rc = write_sids_to_conf(out, xen_sid_to_str, XEN_SID_SZ,
498 					pdb->ocontexts[0]);
499 	} else {
500 		sepol_log_err("Unknown target platform: %i", pdb->target_platform);
501 		rc = -1;
502 	}
503 
504 	return rc;
505 }
class_or_common_perms_to_str(symtab_t * permtab)506 static char *class_or_common_perms_to_str(symtab_t *permtab)
507 {
508 	struct strs *strs;
509 	char *perms = NULL;
510 	int rc = 0;
511 
512 	rc = strs_init(&strs, permtab->nprim);
513 	if (rc != 0) {
514 		goto exit;
515 	}
516 
517 	rc = hashtab_map(permtab->table, hashtab_ordered_to_strs, strs);
518 	if (rc != 0) {
519 		goto exit;
520 	}
521 
522 	if (strs_num_items(strs) > 0) {
523 		perms = strs_to_str(strs);
524 	}
525 
526 exit:
527 	strs_destroy(&strs);
528 
529 	return perms;
530 }
531 
write_class_and_common_rules_to_conf(FILE * out,struct policydb * pdb)532 static int write_class_and_common_rules_to_conf(FILE *out, struct policydb *pdb)
533 {
534 	class_datum_t *class;
535 	common_datum_t *common;
536 	int *used;
537 	char *name, *perms;
538 	unsigned i;
539 	int rc = 0;
540 
541 	/* common */
542 	used = calloc(pdb->p_commons.nprim, sizeof(*used));
543 	if (!used) {
544 		sepol_log_err("Out of memory");
545 		rc = -1;
546 		goto exit;
547 	}
548 	for (i=0; i < pdb->p_classes.nprim; i++) {
549 		class = pdb->class_val_to_struct[i];
550 		name = class->comkey;
551 		if (!name) continue;
552 		common = hashtab_search(pdb->p_commons.table, name);
553 		if (!common) {
554 			rc = -1;
555 			free(used);
556 			goto exit;
557 		}
558 		/* Only write common rule once */
559 		if (!used[common->s.value-1]) {
560 			perms = class_or_common_perms_to_str(&common->permissions);
561 			if (!perms) {
562 				rc = -1;
563 				free(used);
564 				goto exit;
565 			}
566 			sepol_printf(out, "common %s { %s }\n", name, perms);
567 			free(perms);
568 			used[common->s.value-1] = 1;
569 		}
570 	}
571 	free(used);
572 
573 	/* class */
574 	for (i=0; i < pdb->p_classes.nprim; i++) {
575 		class = pdb->class_val_to_struct[i];
576 		name = pdb->p_class_val_to_name[i];
577 		sepol_printf(out, "class %s", name);
578 		if (class->comkey) {
579 			sepol_printf(out, " inherits %s", class->comkey);
580 		}
581 		perms = class_or_common_perms_to_str(&class->permissions);
582 		if (perms) {
583 			sepol_printf(out, " { %s }", perms);
584 			free(perms);
585 		}
586 		sepol_printf(out, "\n");
587 	}
588 
589 exit:
590 	if (rc != 0) {
591 		sepol_log_err("Error writing class rules to policy.conf\n");
592 	}
593 
594 	return rc;
595 }
596 
write_default_user_to_conf(FILE * out,char * class_name,class_datum_t * class)597 static int write_default_user_to_conf(FILE *out, char *class_name, class_datum_t *class)
598 {
599 	const char *dft;
600 
601 	switch (class->default_user) {
602 	case DEFAULT_SOURCE:
603 		dft = "source";
604 		break;
605 	case DEFAULT_TARGET:
606 		dft = "target";
607 		break;
608 	default:
609 		sepol_log_err("Unknown default role value: %i", class->default_user);
610 		return -1;
611 	}
612 	sepol_printf(out, "default_user { %s } %s;\n", class_name, dft);
613 
614 	return 0;
615 }
616 
write_default_role_to_conf(FILE * out,char * class_name,class_datum_t * class)617 static int write_default_role_to_conf(FILE *out, char *class_name, class_datum_t *class)
618 {
619 	const char *dft;
620 
621 	switch (class->default_role) {
622 	case DEFAULT_SOURCE:
623 		dft = "source";
624 		break;
625 	case DEFAULT_TARGET:
626 		dft = "target";
627 		break;
628 	default:
629 		sepol_log_err("Unknown default role value: %i", class->default_role);
630 		return -1;
631 	}
632 	sepol_printf(out, "default_role { %s } %s;\n", class_name, dft);
633 
634 	return 0;
635 }
636 
write_default_type_to_conf(FILE * out,char * class_name,class_datum_t * class)637 static int write_default_type_to_conf(FILE *out, char *class_name, class_datum_t *class)
638 {
639 	const char *dft;
640 
641 	switch (class->default_type) {
642 	case DEFAULT_SOURCE:
643 		dft = "source";
644 		break;
645 	case DEFAULT_TARGET:
646 		dft = "target";
647 		break;
648 	default:
649 		sepol_log_err("Unknown default type value: %i", class->default_type);
650 		return -1;
651 	}
652 	sepol_printf(out, "default_type { %s } %s;\n", class_name, dft);
653 
654 	return 0;
655 }
656 
write_default_range_to_conf(FILE * out,char * class_name,class_datum_t * class)657 static int write_default_range_to_conf(FILE *out, char *class_name, class_datum_t *class)
658 {
659 	const char *dft;
660 
661 	switch (class->default_range) {
662 	case DEFAULT_SOURCE_LOW:
663 		dft = "source low";
664 		break;
665 	case DEFAULT_SOURCE_HIGH:
666 		dft = "source high";
667 		break;
668 	case DEFAULT_SOURCE_LOW_HIGH:
669 		dft = "source low-high";
670 		break;
671 	case DEFAULT_TARGET_LOW:
672 		dft = "target low";
673 		break;
674 	case DEFAULT_TARGET_HIGH:
675 		dft = "target high";
676 		break;
677 	case DEFAULT_TARGET_LOW_HIGH:
678 		dft = "target low-high";
679 		break;
680 	case DEFAULT_GLBLUB:
681 		dft = "glblub";
682 		break;
683 	default:
684 		sepol_log_err("Unknown default type value: %i", class->default_range);
685 		return -1;
686 	}
687 	sepol_printf(out, "default_range { %s } %s;\n", class_name, dft);
688 
689 	return 0;
690 }
691 
write_default_rules_to_conf(FILE * out,struct policydb * pdb)692 static int write_default_rules_to_conf(FILE *out, struct policydb *pdb)
693 {
694 	class_datum_t *class;
695 	unsigned i;
696 	int rc = 0;
697 
698 	/* default_user */
699 	for (i=0; i < pdb->p_classes.nprim; i++) {
700 		class = pdb->class_val_to_struct[i];
701 		if (class->default_user != 0) {
702 			rc = write_default_user_to_conf(out, pdb->p_class_val_to_name[i], class);
703 			if (rc != 0) {
704 				goto exit;
705 			}
706 		}
707 	}
708 
709 	/* default_role */
710 	for (i=0; i < pdb->p_classes.nprim; i++) {
711 		class = pdb->class_val_to_struct[i];
712 		if (class->default_role != 0) {
713 			rc = write_default_role_to_conf(out, pdb->p_class_val_to_name[i], class);
714 			if (rc != 0) {
715 				goto exit;
716 			}
717 		}
718 	}
719 
720 	/* default_type */
721 	for (i=0; i < pdb->p_classes.nprim; i++) {
722 		class = pdb->class_val_to_struct[i];
723 		if (class->default_type != 0) {
724 			rc = write_default_type_to_conf(out, pdb->p_class_val_to_name[i], class);
725 			if (rc != 0) {
726 				goto exit;
727 			}
728 		}
729 	}
730 
731 	if (!pdb->mls) {
732 		return 0;
733 	}
734 
735 	/* default_range */
736 	for (i=0; i < pdb->p_classes.nprim; i++) {
737 		class = pdb->class_val_to_struct[i];
738 		if (class->default_range != 0) {
739 			rc = write_default_range_to_conf(out, pdb->p_class_val_to_name[i], class);
740 			if (rc != 0) {
741 				goto exit;
742 			}
743 		}
744 	}
745 
746 exit:
747 	if (rc != 0) {
748 		sepol_log_err("Error writing default rules to policy.conf\n");
749 	}
750 
751 	return rc;
752 }
753 
map_sensitivity_aliases_to_strs(char * key,void * data,void * args)754 static int map_sensitivity_aliases_to_strs(char *key, void *data, void *args)
755 {
756 	level_datum_t *sens = data;
757 	struct strs *strs = args;
758 	int rc = 0;
759 
760 	if (sens->isalias) {
761 		rc = strs_add(strs, key);
762 	}
763 
764 	return rc;
765 }
766 
write_sensitivity_rules_to_conf(FILE * out,struct policydb * pdb)767 static int write_sensitivity_rules_to_conf(FILE *out, struct policydb *pdb)
768 {
769 	level_datum_t *level;
770 	struct strs *strs;
771 	char **sens_alias_map = NULL;
772 	char *name, *prev, *alias;
773 	unsigned i, j, num;
774 	int rc = 0;
775 
776 	rc = strs_init(&strs, pdb->p_levels.nprim);
777 	if (rc != 0) {
778 		goto exit;
779 	}
780 
781 	rc = hashtab_map(pdb->p_levels.table, map_sensitivity_aliases_to_strs, strs);
782 	if (rc != 0) {
783 		goto exit;
784 	}
785 
786 	num = strs_num_items(strs);
787 
788 	if (num > 0) {
789 		sens_alias_map = calloc(sizeof(*sens_alias_map), pdb->p_levels.nprim);
790 		if (!sens_alias_map) {
791 			rc = -1;
792 			goto exit;
793 		}
794 
795 		/* map aliases to sensitivities */
796 		for (i=0; i < num; i++) {
797 			name = strs_read_at_index(strs, i);
798 			level = hashtab_search(pdb->p_levels.table, name);
799 			if (!level) {
800 				rc = -1;
801 				goto exit;
802 			}
803 			j = level->level->sens - 1;
804 			if (!sens_alias_map[j]) {
805 				sens_alias_map[j] = strdup(name);
806 				if (!sens_alias_map[j]) {
807 					rc = -1;
808 					goto exit;
809 				}
810 			} else {
811 				alias = sens_alias_map[j];
812 				sens_alias_map[j] = create_str("%s %s", 2, alias, name);
813 				free(alias);
814 				if (!sens_alias_map[j]) {
815 					rc = -1;
816 					goto exit;
817 				}
818 			}
819 		}
820 	}
821 
822 	/* sensitivities */
823 	for (i=0; i < pdb->p_levels.nprim; i++) {
824 		name = pdb->p_sens_val_to_name[i];
825 		if (!name) continue;
826 		level = hashtab_search(pdb->p_levels.table, name);
827 		if (!level) {
828 			rc = -1;
829 			goto exit;
830 		}
831 		if (level->isalias) continue;
832 
833 		if (sens_alias_map && sens_alias_map[i]) {
834 			alias = sens_alias_map[i];
835 			if (strchr(alias, ' ')) {
836 				sepol_printf(out, "sensitivity %s alias { %s };\n", name, alias);
837 			} else {
838 				sepol_printf(out, "sensitivity %s alias %s;\n", name, alias);
839 			}
840 		} else {
841 			sepol_printf(out, "sensitivity %s;\n", name);
842 		}
843 	}
844 
845 	/* dominance */
846 	sepol_printf(out, "dominance { ");
847 	prev = NULL;
848 	for (i=0; i < pdb->p_levels.nprim; i++) {
849 		name = pdb->p_sens_val_to_name[i];
850 		if (!name) continue;
851 		level = hashtab_search(pdb->p_levels.table, name);
852 		if (!level) {
853 			rc = -1;
854 			goto exit;
855 		}
856 		if (level->isalias) continue;
857 
858 		if (prev) {
859 			sepol_printf(out, "%s ", prev);
860 		}
861 		prev = name;
862 	}
863 	if (prev) {
864 		sepol_printf(out, "%s", prev);
865 	}
866 	sepol_printf(out, " }\n");
867 
868 exit:
869 	if (sens_alias_map) {
870 		for (i=0; i < pdb->p_levels.nprim; i++) {
871 			free(sens_alias_map[i]);
872 		}
873 		free(sens_alias_map);
874 	}
875 
876 	strs_destroy(&strs);
877 
878 	if (rc != 0) {
879 		sepol_log_err("Error writing sensitivity rules to CIL\n");
880 	}
881 
882 	return rc;
883 }
884 
map_category_aliases_to_strs(char * key,void * data,void * args)885 static int map_category_aliases_to_strs(char *key, void *data, void *args)
886 {
887 	cat_datum_t *cat = data;
888 	struct strs *strs = args;
889 	int rc = 0;
890 
891 	if (cat->isalias) {
892 		rc = strs_add(strs, key);
893 	}
894 
895 	return rc;
896 }
897 
write_category_rules_to_conf(FILE * out,struct policydb * pdb)898 static int write_category_rules_to_conf(FILE *out, struct policydb *pdb)
899 {
900 	cat_datum_t *cat;
901 	struct strs *strs;
902 	char **cat_alias_map = NULL;
903 	char *name, *alias;
904 	unsigned i, j, num;
905 	int rc = 0;
906 
907 	rc = strs_init(&strs, pdb->p_levels.nprim);
908 	if (rc != 0) {
909 		goto exit;
910 	}
911 
912 	rc = hashtab_map(pdb->p_cats.table, map_category_aliases_to_strs, strs);
913 	if (rc != 0) {
914 		goto exit;
915 	}
916 
917 	num = strs_num_items(strs);
918 
919 	if (num > 0) {
920 		cat_alias_map = calloc(sizeof(*cat_alias_map), pdb->p_cats.nprim);
921 		if (!cat_alias_map) {
922 			rc = -1;
923 			goto exit;
924 		}
925 
926 		/* map aliases to categories */
927 		for (i=0; i < num; i++) {
928 			name = strs_read_at_index(strs, i);
929 			cat = hashtab_search(pdb->p_cats.table, name);
930 			if (!cat) {
931 				rc = -1;
932 				goto exit;
933 			}
934 			j = cat->s.value - 1;
935 			if (!cat_alias_map[j]) {
936 				cat_alias_map[j] = strdup(name);
937 				if (!cat_alias_map[j]) {
938 					rc = -1;
939 					goto exit;
940 				}
941 			} else {
942 				alias = cat_alias_map[j];
943 				cat_alias_map[j] = create_str("%s %s", 2, alias, name);
944 				free(alias);
945 				if (!cat_alias_map[j]) {
946 					rc = -1;
947 					goto exit;
948 				}
949 			}
950 		}
951 	}
952 
953 	/* categories */
954 	for (i=0; i < pdb->p_cats.nprim; i++) {
955 		name = pdb->p_cat_val_to_name[i];
956 		if (!name) continue;
957 		cat = hashtab_search(pdb->p_cats.table, name);
958 		if (!cat) {
959 			rc = -1;
960 			goto exit;
961 		}
962 		if (cat->isalias) continue;
963 
964 		if (cat_alias_map && cat_alias_map[i]) {
965 			alias = cat_alias_map[i];
966 			if (strchr(alias, ' ')) {
967 				sepol_printf(out, "category %s alias { %s };\n", name, alias);
968 			} else {
969 				sepol_printf(out, "category %s alias %s;\n", name, alias);
970 			}
971 		} else {
972 			sepol_printf(out, "category %s;\n", name);
973 		}
974 	}
975 
976 exit:
977 	if (cat_alias_map) {
978 		for (i=0; i < pdb->p_cats.nprim; i++) {
979 			free(cat_alias_map[i]);
980 		}
981 		free(cat_alias_map);
982 	}
983 
984 	strs_destroy(&strs);
985 
986 	if (rc != 0) {
987 		sepol_log_err("Error writing category rules to policy.conf\n");
988 	}
989 
990 	return rc;
991 }
992 
cats_ebitmap_len(struct ebitmap * cats,char ** val_to_name)993 static size_t cats_ebitmap_len(struct ebitmap *cats, char **val_to_name)
994 {
995 	struct ebitmap_node *node;
996 	uint32_t i, start, range;
997 	size_t len = 0;
998 
999 	range = 0;
1000 	ebitmap_for_each_positive_bit(cats, node, i) {
1001 		if (range == 0)
1002 			start = i;
1003 
1004 		range++;
1005 
1006 		if (ebitmap_get_bit(cats, i+1))
1007 			continue;
1008 
1009 		len += strlen(val_to_name[start]) + 1;
1010 		if (range > 1) {
1011 			len += strlen(val_to_name[i]) + 1;
1012 		}
1013 
1014 		range = 0;
1015 	}
1016 
1017 	return len;
1018 }
1019 
cats_ebitmap_to_str(struct ebitmap * cats,char ** val_to_name)1020 static char *cats_ebitmap_to_str(struct ebitmap *cats, char **val_to_name)
1021 {
1022 	struct ebitmap_node *node;
1023 	uint32_t i, start, range, first;
1024 	char *catsbuf, *p;
1025 	const char *fmt;
1026 	char sep;
1027 	int len, remaining;
1028 
1029 	remaining = (int)cats_ebitmap_len(cats, val_to_name);
1030 	catsbuf = malloc(remaining);
1031 	if (!catsbuf) {
1032 		goto exit;
1033 	}
1034 
1035 	p = catsbuf;
1036 
1037 	first = 1;
1038 	range = 0;
1039 	ebitmap_for_each_positive_bit(cats, node, i) {
1040 		if (range == 0)
1041 			start = i;
1042 
1043 		range++;
1044 
1045 		if (ebitmap_get_bit(cats, i+1))
1046 			continue;
1047 
1048 		if (range > 1) {
1049 			sep = (range == 2) ? ',' : '.';
1050 			fmt = first ? "%s%c%s" : ",%s%c%s";
1051 			len = snprintf(p, remaining, fmt,
1052 				       val_to_name[start], sep, val_to_name[i]);
1053 		} else {
1054 			fmt = first ? "%s" : ",%s";
1055 			len = snprintf(p, remaining, fmt, val_to_name[start]);
1056 
1057 		}
1058 		if (len < 0 || len >= remaining) {
1059 			goto exit;
1060 		}
1061 		p += len;
1062 		remaining -= len;
1063 		first = 0;
1064 		range = 0;
1065 	}
1066 
1067 	*p = '\0';
1068 
1069 	return catsbuf;
1070 
1071 exit:
1072 	free(catsbuf);
1073 	return NULL;
1074 }
1075 
write_level_rules_to_conf(FILE * out,struct policydb * pdb)1076 static int write_level_rules_to_conf(FILE *out, struct policydb *pdb)
1077 {
1078 	level_datum_t *level;
1079 	char *name, *cats;
1080 	unsigned i;
1081 	int rc = 0;
1082 
1083 	for (i=0; i < pdb->p_levels.nprim; i++) {
1084 		name = pdb->p_sens_val_to_name[i];
1085 		if (!name) continue;
1086 		level = hashtab_search(pdb->p_levels.table, name);
1087 		if (!level) {
1088 			rc = -1;
1089 			goto exit;
1090 		}
1091 		if (level->isalias) continue;
1092 
1093 		if (ebitmap_cardinality(&level->level->cat) > 0) {
1094 			cats = cats_ebitmap_to_str(&level->level->cat, pdb->p_cat_val_to_name);
1095 			sepol_printf(out, "level %s:%s;\n", name, cats);
1096 			free(cats);
1097 		} else {
1098 			sepol_printf(out, "level %s;\n", name);
1099 		}
1100 	}
1101 
1102 exit:
1103 	if (rc != 0) {
1104 		sepol_log_err("Error writing level rules to policy.conf\n");
1105 	}
1106 
1107 	return rc;
1108 }
1109 
write_mls_rules_to_conf(FILE * out,struct policydb * pdb)1110 static int write_mls_rules_to_conf(FILE *out, struct policydb *pdb)
1111 {
1112 	int rc = 0;
1113 
1114 	if (!pdb->mls) {
1115 		return 0;
1116 	}
1117 
1118 	rc = write_sensitivity_rules_to_conf(out, pdb);
1119 	if (rc != 0) {
1120 		goto exit;
1121 	}
1122 
1123 	rc = write_category_rules_to_conf(out, pdb);
1124 	if (rc != 0) {
1125 		goto exit;
1126 	}
1127 
1128 	rc = write_level_rules_to_conf(out, pdb);
1129 	if (rc != 0) {
1130 		goto exit;
1131 	}
1132 
1133 exit:
1134 	if (rc != 0) {
1135 		sepol_log_err("Error writing mls rules to policy.conf\n");
1136 	}
1137 
1138 	return rc;
1139 }
1140 
write_polcap_rules_to_conf(FILE * out,struct policydb * pdb)1141 static int write_polcap_rules_to_conf(FILE *out, struct policydb *pdb)
1142 {
1143 	struct strs *strs;
1144 	struct ebitmap_node *node;
1145 	const char *name;
1146 	uint32_t i;
1147 	int rc = 0;
1148 
1149 	rc = strs_init(&strs, 32);
1150 	if (rc != 0) {
1151 		goto exit;
1152 	}
1153 
1154 	ebitmap_for_each_positive_bit(&pdb->policycaps, node, i) {
1155 		name = sepol_polcap_getname(i);
1156 		if (name == NULL) {
1157 			sepol_log_err("Unknown policy capability id: %i", i);
1158 			rc = -1;
1159 			goto exit;
1160 		}
1161 
1162 		rc = strs_create_and_add(strs, "policycap %s;", 1, name);
1163 		if (rc != 0) {
1164 			goto exit;
1165 		}
1166 	}
1167 
1168 	strs_sort(strs);
1169 	strs_write_each(strs, out);
1170 
1171 exit:
1172 	strs_free_all(strs);
1173 	strs_destroy(&strs);
1174 
1175 	if (rc != 0) {
1176 		sepol_log_err("Error writing polcap rules to policy.conf\n");
1177 	}
1178 
1179 	return rc;
1180 }
1181 
write_type_attributes_to_conf(FILE * out,struct policydb * pdb)1182 static int write_type_attributes_to_conf(FILE *out, struct policydb *pdb)
1183 {
1184 	type_datum_t *type;
1185 	char *name;
1186 	struct strs *strs;
1187 	unsigned i, num;
1188 	int rc = 0;
1189 
1190 	rc = strs_init(&strs, pdb->p_types.nprim);
1191 	if (rc != 0) {
1192 		goto exit;
1193 	}
1194 
1195 	for (i=0; i < pdb->p_types.nprim; i++) {
1196 		type = pdb->type_val_to_struct[i];
1197 		if (type->flavor == TYPE_ATTRIB) {
1198 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1199 			if (rc != 0) {
1200 				goto exit;
1201 			}
1202 		}
1203 	}
1204 
1205 	strs_sort(strs);
1206 
1207 	num = strs_num_items(strs);
1208 	for (i = 0; i < num; i++) {
1209 		name = strs_read_at_index(strs, i);
1210 		if (!name) {
1211 			rc = -1;
1212 			goto exit;
1213 		}
1214 		sepol_printf(out, "attribute %s;\n", name);
1215 	}
1216 
1217 exit:
1218 	strs_destroy(&strs);
1219 
1220 	if (rc != 0) {
1221 		sepol_log_err("Error writing typeattribute rules to policy.conf\n");
1222 	}
1223 
1224 	return rc;
1225 }
1226 
write_role_attributes_to_conf(FILE * out,struct policydb * pdb)1227 static int write_role_attributes_to_conf(FILE *out, struct policydb *pdb)
1228 {
1229 	role_datum_t *role;
1230 	char *name;
1231 	struct strs *strs;
1232 	unsigned i, num;
1233 	int rc = 0;
1234 
1235 	rc = strs_init(&strs, pdb->p_roles.nprim);
1236 	if (rc != 0) {
1237 		goto exit;
1238 	}
1239 
1240 	for (i=0; i < pdb->p_roles.nprim; i++) {
1241 		role = pdb->role_val_to_struct[i];
1242 		if (role && role->flavor == ROLE_ATTRIB) {
1243 			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
1244 			if (rc != 0) {
1245 				goto exit;
1246 			}
1247 		}
1248 	}
1249 
1250 	strs_sort(strs);
1251 
1252 	num = strs_num_items(strs);
1253 	for (i=0; i<num; i++) {
1254 		name = strs_read_at_index(strs, i);
1255 		if (!name) {
1256 			rc = -1;
1257 			goto exit;
1258 		}
1259 		sepol_printf(out, "attribute_role %s;\n", name);
1260 	}
1261 
1262 exit:
1263 	strs_destroy(&strs);
1264 
1265 	if (rc != 0) {
1266 		sepol_log_err("Error writing roleattribute rules to policy.conf\n");
1267 	}
1268 
1269 	return rc;
1270 }
1271 
map_boolean_to_strs(char * key,void * data,void * args)1272 static int map_boolean_to_strs(char *key, void *data, void *args)
1273 {
1274 	struct strs *strs = (struct strs *)args;
1275 	struct cond_bool_datum *boolean = data;
1276 	const char *value;
1277 
1278 	value = boolean->state ? "true" : "false";
1279 
1280 	return strs_create_and_add(strs, "bool %s %s;", 2, key, value);
1281 }
1282 
write_boolean_decl_rules_to_conf(FILE * out,struct policydb * pdb)1283 static int write_boolean_decl_rules_to_conf(FILE *out, struct policydb *pdb)
1284 {
1285 	struct strs *strs;
1286 	int rc = 0;
1287 
1288 	rc = strs_init(&strs, 32);
1289 	if (rc != 0) {
1290 		goto exit;
1291 	}
1292 
1293 	rc = hashtab_map(pdb->p_bools.table, map_boolean_to_strs, strs);
1294 	if (rc != 0) {
1295 		goto exit;
1296 	}
1297 
1298 	strs_sort(strs);
1299 	strs_write_each(strs, out);
1300 
1301 exit:
1302 	strs_free_all(strs);
1303 	strs_destroy(&strs);
1304 
1305 	if (rc != 0) {
1306 		sepol_log_err("Error writing boolean declarations to policy.conf\n");
1307 	}
1308 
1309 	return rc;
1310 }
1311 
write_type_decl_rules_to_conf(FILE * out,struct policydb * pdb)1312 static int write_type_decl_rules_to_conf(FILE *out, struct policydb *pdb)
1313 {
1314 	type_datum_t *type;
1315 	struct strs *strs;
1316 	char *name;
1317 	unsigned i, num;
1318 	int rc = 0;
1319 
1320 	rc = strs_init(&strs, pdb->p_types.nprim);
1321 	if (rc != 0) {
1322 		goto exit;
1323 	}
1324 
1325 	for (i=0; i < pdb->p_types.nprim; i++) {
1326 		type = pdb->type_val_to_struct[i];
1327 		if (type->flavor == TYPE_TYPE && type->primary) {
1328 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1329 			if (rc != 0) {
1330 				goto exit;
1331 			}
1332 		}
1333 	}
1334 
1335 	strs_sort(strs);
1336 
1337 	num = strs_num_items(strs);
1338 	for (i=0; i<num; i++) {
1339 		name = strs_read_at_index(strs, i);
1340 		if (!name) {
1341 			rc = -1;
1342 			goto exit;
1343 		}
1344 		sepol_printf(out, "type %s;\n", name);
1345 	}
1346 
1347 exit:
1348 	strs_destroy(&strs);
1349 
1350 	if (rc != 0) {
1351 		sepol_log_err("Error writing type declarations to policy.con\n");
1352 	}
1353 
1354 	return rc;
1355 }
1356 
write_type_alias_rules_to_conf(FILE * out,struct policydb * pdb)1357 static int write_type_alias_rules_to_conf(FILE *out, struct policydb *pdb)
1358 {
1359 	type_datum_t *alias;
1360 	struct strs *strs;
1361 	char *name;
1362 	char *type;
1363 	unsigned i, num;
1364 	int rc = 0;
1365 
1366 	rc = strs_init(&strs, pdb->p_types.nprim);
1367 	if (rc != 0) {
1368 		goto exit;
1369 	}
1370 
1371 	for (i=0; i < pdb->p_types.nprim; i++) {
1372 		alias = pdb->type_val_to_struct[i];
1373 		if (!alias->primary) {
1374 			rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1375 			if (rc != 0) {
1376 				goto exit;
1377 			}
1378 		}
1379 	}
1380 
1381 	strs_sort(strs);
1382 
1383 	num = strs_num_items(strs);
1384 
1385 	for (i=0; i<num; i++) {
1386 		name = strs_read_at_index(strs, i);
1387 		if (!name) {
1388 			rc = -1;
1389 			goto exit;
1390 		}
1391 		alias = hashtab_search(pdb->p_types.table, name);
1392 		if (!alias) {
1393 			rc = -1;
1394 			goto exit;
1395 		}
1396 		type = pdb->p_type_val_to_name[alias->s.value - 1];
1397 		sepol_printf(out, "typealias %s %s;\n", type, name);
1398 	}
1399 
1400 exit:
1401 	strs_destroy(&strs);
1402 
1403 	if (rc != 0) {
1404 		sepol_log_err("Error writing type alias rules to policy.conf\n");
1405 	}
1406 
1407 	return rc;
1408 }
1409 
write_type_bounds_rules_to_conf(FILE * out,struct policydb * pdb)1410 static int write_type_bounds_rules_to_conf(FILE *out, struct policydb *pdb)
1411 {
1412 	type_datum_t *type;
1413 	struct strs *strs;
1414 	char *parent;
1415 	char *child;
1416 	unsigned i, num;
1417 	int rc = 0;
1418 
1419 	rc = strs_init(&strs, pdb->p_types.nprim);
1420 	if (rc != 0) {
1421 		goto exit;
1422 	}
1423 
1424 	for (i=0; i < pdb->p_types.nprim; i++) {
1425 		type = pdb->type_val_to_struct[i];
1426 		if (type->flavor == TYPE_TYPE) {
1427 			if (type->bounds > 0) {
1428 				rc = strs_add(strs, pdb->p_type_val_to_name[i]);
1429 				if (rc != 0) {
1430 					goto exit;
1431 				}
1432 			}
1433 		}
1434 	}
1435 
1436 	strs_sort(strs);
1437 
1438 	num = strs_num_items(strs);
1439 	for (i=0; i<num; i++) {
1440 		child = strs_read_at_index(strs, i);
1441 		if (!child) {
1442 			rc = -1;
1443 			goto exit;
1444 		}
1445 		type = hashtab_search(pdb->p_types.table, child);
1446 		if (!type) {
1447 			rc = -1;
1448 			goto exit;
1449 		}
1450 		parent = pdb->p_type_val_to_name[type->bounds - 1];
1451 		sepol_printf(out, "typebounds %s %s;\n", parent, child);
1452 	}
1453 
1454 exit:
1455 	strs_destroy(&strs);
1456 
1457 	if (rc != 0) {
1458 		sepol_log_err("Error writing type bounds rules to policy.conf\n");
1459 	}
1460 
1461 	return rc;
1462 }
1463 
attr_strs_to_str(struct strs * strs)1464 static char *attr_strs_to_str(struct strs *strs)
1465 {
1466 	char *str = NULL;
1467 	size_t len = 0;
1468 	char *p;
1469 	unsigned i;
1470 	int rc;
1471 
1472 	if (strs->num == 0) {
1473 		goto exit;
1474 	}
1475 
1476 	/* 2*strs->num - 1 because ", " follows all but last attr (followed by '\0') */
1477 	len = strs_len_items(strs) + 2*strs->num - 1;
1478 	str = malloc(len);
1479 	if (!str) {
1480 		sepol_log_err("Out of memory");
1481 		goto exit;
1482 	}
1483 
1484 	p = str;
1485 	for (i=0; i<strs->num; i++) {
1486 		if (!strs->list[i]) continue;
1487 		len = strlen(strs->list[i]);
1488 		rc = snprintf(p, len+1, "%s", strs->list[i]);
1489 		if (rc < 0 || rc > (int)len) {
1490 			free(str);
1491 			str = NULL;
1492 			goto exit;
1493 		}
1494 		p += len;
1495 		if (i < strs->num - 1) {
1496 			*p++ = ',';
1497 			*p++ = ' ';
1498 		}
1499 	}
1500 
1501 	*p = '\0';
1502 
1503 exit:
1504 	return str;
1505 }
1506 
attrmap_to_str(struct ebitmap * map,char ** val_to_name)1507 static char *attrmap_to_str(struct ebitmap *map, char **val_to_name)
1508 {
1509 	struct strs *strs;
1510 	char *str = NULL;
1511 	int rc;
1512 
1513 	rc = strs_init(&strs, 32);
1514 	if (rc != 0) {
1515 		goto exit;
1516 	}
1517 
1518 	rc = ebitmap_to_strs(map, strs, val_to_name);
1519 	if (rc != 0) {
1520 		goto exit;
1521 	}
1522 
1523 	strs_sort(strs);
1524 
1525 	str = attr_strs_to_str(strs);
1526 
1527 exit:
1528 	strs_destroy(&strs);
1529 
1530 	return str;
1531 }
1532 
write_type_attribute_sets_to_conf(FILE * out,struct policydb * pdb)1533 static int write_type_attribute_sets_to_conf(FILE *out, struct policydb *pdb)
1534 {
1535 	type_datum_t *type;
1536 	struct strs *strs;
1537 	ebitmap_t attrmap;
1538 	char *name, *attrs;
1539 	unsigned i;
1540 	int rc;
1541 
1542 	rc = strs_init(&strs, pdb->p_types.nprim);
1543 	if (rc != 0) {
1544 		goto exit;
1545 	}
1546 
1547 	for (i=0; i < pdb->p_types.nprim; i++) {
1548 		type = pdb->type_val_to_struct[i];
1549 		if (type->flavor != TYPE_TYPE || !type->primary) continue;
1550 		if (ebitmap_cardinality(&pdb->type_attr_map[i]) == 1) continue;
1551 
1552 		rc = ebitmap_cpy(&attrmap, &pdb->type_attr_map[i]);
1553 		if (rc != 0) {
1554 			goto exit;
1555 		}
1556 		rc = ebitmap_set_bit(&attrmap, i, 0);
1557 		if (rc != 0) {
1558 			ebitmap_destroy(&attrmap);
1559 			goto exit;
1560 		}
1561 		name = pdb->p_type_val_to_name[i];
1562 		attrs = attrmap_to_str(&attrmap, pdb->p_type_val_to_name);
1563 		ebitmap_destroy(&attrmap);
1564 		if (!attrs) {
1565 			rc = -1;
1566 			goto exit;
1567 		}
1568 
1569 		rc = strs_create_and_add(strs, "typeattribute %s %s;",
1570 					 2, name, attrs);
1571 		free(attrs);
1572 		if (rc != 0) {
1573 			goto exit;
1574 		}
1575 	}
1576 
1577 	strs_sort(strs);
1578 	strs_write_each(strs, out);
1579 
1580 exit:
1581 	strs_free_all(strs);
1582 	strs_destroy(&strs);
1583 
1584 	if (rc != 0) {
1585 		sepol_log_err("Error writing typeattributeset rules to policy.conf\n");
1586 	}
1587 
1588 	return rc;
1589 }
1590 
write_type_permissive_rules_to_conf(FILE * out,struct policydb * pdb)1591 static int write_type_permissive_rules_to_conf(FILE *out, struct policydb *pdb)
1592 {
1593 	struct strs *strs;
1594 	char *name;
1595 	struct ebitmap_node *node;
1596 	unsigned i, num;
1597 	int rc = 0;
1598 
1599 	rc = strs_init(&strs, pdb->p_types.nprim);
1600 	if (rc != 0) {
1601 		goto exit;
1602 	}
1603 
1604 	ebitmap_for_each_positive_bit(&pdb->permissive_map, node, i) {
1605 		rc = strs_add(strs, pdb->p_type_val_to_name[i-1]);
1606 		if (rc != 0) {
1607 			goto exit;
1608 		}
1609 	}
1610 
1611 	strs_sort(strs);
1612 
1613 	num = strs_num_items(strs);
1614 	for (i=0; i<num; i++) {
1615 		name = strs_read_at_index(strs, i);
1616 		if (!name) {
1617 			rc = -1;
1618 			goto exit;
1619 		}
1620 		sepol_printf(out, "permissive %s;\n", name);
1621 	}
1622 
1623 exit:
1624 	strs_destroy(&strs);
1625 
1626 	if (rc != 0) {
1627 		sepol_log_err("Error writing typepermissive rules to policy.conf\n");
1628 	}
1629 
1630 	return rc;
1631 }
1632 
avtab_node_to_str(struct policydb * pdb,avtab_key_t * key,avtab_datum_t * datum)1633 static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum)
1634 {
1635 	uint32_t data = datum->data;
1636 	type_datum_t *type;
1637 	const char *flavor, *src, *tgt, *class, *perms, *new;
1638 	char *rule = NULL;
1639 
1640 	switch (0xFFF & key->specified) {
1641 	case AVTAB_ALLOWED:
1642 		flavor = "allow";
1643 		break;
1644 	case AVTAB_AUDITALLOW:
1645 		flavor = "auditallow";
1646 		break;
1647 	case AVTAB_AUDITDENY:
1648 		flavor = "dontaudit";
1649 		data = ~data;
1650 		break;
1651 	case AVTAB_XPERMS_ALLOWED:
1652 		flavor = "allowxperm";
1653 		break;
1654 	case AVTAB_XPERMS_AUDITALLOW:
1655 		flavor = "auditallowxperm";
1656 		break;
1657 	case AVTAB_XPERMS_DONTAUDIT:
1658 		flavor = "dontauditxperm";
1659 		break;
1660 	case AVTAB_TRANSITION:
1661 		flavor = "type_transition";
1662 		break;
1663 	case AVTAB_MEMBER:
1664 		flavor = "type_member";
1665 		break;
1666 	case AVTAB_CHANGE:
1667 		flavor = "type_change";
1668 		break;
1669 	default:
1670 		sepol_log_err("Unknown avtab type: %i", key->specified);
1671 		goto exit;
1672 	}
1673 
1674 	src = pdb->p_type_val_to_name[key->source_type - 1];
1675 	tgt = pdb->p_type_val_to_name[key->target_type - 1];
1676 	if (key->source_type == key->target_type && !(key->specified & AVTAB_TYPE)) {
1677 		type = pdb->type_val_to_struct[key->source_type - 1];
1678 		if (type->flavor != TYPE_ATTRIB) {
1679 			tgt = "self";
1680 		}
1681 	}
1682 	class = pdb->p_class_val_to_name[key->target_class - 1];
1683 
1684 	if (key->specified & AVTAB_AV) {
1685 		perms = sepol_av_to_string(pdb, key->target_class, data);
1686 		if (perms == NULL) {
1687 			sepol_log_err("Failed to generate permission string");
1688 			goto exit;
1689 		}
1690 		rule = create_str("%s %s %s:%s { %s };", 5,
1691 				  flavor, src, tgt, class, perms+1);
1692 	} else if (key->specified & AVTAB_XPERMS) {
1693 		perms = sepol_extended_perms_to_string(datum->xperms);
1694 		if (perms == NULL) {
1695 			sepol_log_err("Failed to generate extended permission string");
1696 			goto exit;
1697 		}
1698 
1699 		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms);
1700 	} else {
1701 		new = pdb->p_type_val_to_name[data - 1];
1702 
1703 		rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, new);
1704 	}
1705 
1706 	if (!rule) {
1707 		goto exit;
1708 	}
1709 
1710 	return rule;
1711 
1712 exit:
1713 	return NULL;
1714 }
1715 
1716 struct map_avtab_args {
1717 	struct policydb *pdb;
1718 	uint32_t flavor;
1719 	struct strs *strs;
1720 };
1721 
map_avtab_write_helper(avtab_key_t * key,avtab_datum_t * datum,void * args)1722 static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void *args)
1723 {
1724 	struct map_avtab_args *map_args = args;
1725 	uint32_t flavor = map_args->flavor;
1726 	struct policydb *pdb = map_args->pdb;
1727 	struct strs *strs = map_args->strs;
1728 	char *rule;
1729 	int rc = 0;
1730 
1731 	if (key->specified & flavor) {
1732 		rule = avtab_node_to_str(pdb, key, datum);
1733 		if (!rule) {
1734 			rc = -1;
1735 			goto exit;
1736 		}
1737 		rc = strs_add(strs, rule);
1738 		if (rc != 0) {
1739 			free(rule);
1740 			goto exit;
1741 		}
1742 	}
1743 
1744 exit:
1745 	return rc;
1746 }
1747 
write_avtab_flavor_to_conf(FILE * out,struct policydb * pdb,uint32_t flavor,int indent)1748 static int write_avtab_flavor_to_conf(FILE *out, struct policydb *pdb, uint32_t flavor, int indent)
1749 {
1750 	struct map_avtab_args args;
1751 	struct strs *strs;
1752 	int rc = 0;
1753 
1754 	rc = strs_init(&strs, 1000);
1755 	if (rc != 0) {
1756 		goto exit;
1757 	}
1758 
1759 	args.pdb = pdb;
1760 	args.flavor = flavor;
1761 	args.strs = strs;
1762 
1763 	rc = avtab_map(&pdb->te_avtab, map_avtab_write_helper, &args);
1764 	if (rc != 0) {
1765 		goto exit;
1766 	}
1767 
1768 	strs_sort(strs);
1769 	strs_write_each_indented(strs, out, indent);
1770 
1771 exit:
1772 	strs_free_all(strs);
1773 	strs_destroy(&strs);
1774 
1775 	return rc;
1776 }
1777 
write_avtab_to_conf(FILE * out,struct policydb * pdb,int indent)1778 static int write_avtab_to_conf(FILE *out, struct policydb *pdb, int indent)
1779 {
1780 	unsigned i;
1781 	int rc = 0;
1782 
1783 	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
1784 		rc = write_avtab_flavor_to_conf(out, pdb, avtab_flavors[i], indent);
1785 		if (rc != 0) {
1786 			goto exit;
1787 		}
1788 	}
1789 
1790 exit:
1791 	if (rc != 0) {
1792 		sepol_log_err("Error writing avtab rules to policy.conf\n");
1793 	}
1794 
1795 	return rc;
1796 }
1797 
1798 struct map_filename_trans_args {
1799 	struct policydb *pdb;
1800 	struct strs *strs;
1801 };
1802 
map_filename_trans_to_str(hashtab_key_t key,void * data,void * arg)1803 static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg)
1804 {
1805 	filename_trans_t *ft = (filename_trans_t *)key;
1806 	filename_trans_datum_t *datum = data;
1807 	struct map_filename_trans_args *map_args = arg;
1808 	struct policydb *pdb = map_args->pdb;
1809 	struct strs *strs = map_args->strs;
1810 	char *src, *tgt, *class, *filename, *new;
1811 
1812 	src = pdb->p_type_val_to_name[ft->stype - 1];
1813 	tgt = pdb->p_type_val_to_name[ft->ttype - 1];
1814 	class = pdb->p_class_val_to_name[ft->tclass - 1];
1815 	filename = ft->name;
1816 	new =  pdb->p_type_val_to_name[datum->otype - 1];
1817 
1818 	return strs_create_and_add(strs, "type_transition %s %s:%s %s \"%s\";", 5,
1819 				   src, tgt, class, new, filename);
1820 }
1821 
write_filename_trans_rules_to_conf(FILE * out,struct policydb * pdb)1822 static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb)
1823 {
1824 	struct map_filename_trans_args args;
1825 	struct strs *strs;
1826 	int rc = 0;
1827 
1828 	rc = strs_init(&strs, 100);
1829 	if (rc != 0) {
1830 		goto exit;
1831 	}
1832 
1833 	args.pdb = pdb;
1834 	args.strs = strs;
1835 
1836 	rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args);
1837 	if (rc != 0) {
1838 		goto exit;
1839 	}
1840 
1841 	strs_sort(strs);
1842 	strs_write_each(strs, out);
1843 
1844 exit:
1845 	strs_free_all(strs);
1846 	strs_destroy(&strs);
1847 
1848 	if (rc != 0) {
1849 		sepol_log_err("Error writing filename typetransition rules to policy.conf\n");
1850 	}
1851 
1852 	return rc;
1853 }
1854 
level_to_str(struct policydb * pdb,struct mls_level * level)1855 static char *level_to_str(struct policydb *pdb, struct mls_level *level)
1856 {
1857 	ebitmap_t *cats = &level->cat;
1858 	char *level_str = NULL;
1859 	char *sens_str = pdb->p_sens_val_to_name[level->sens - 1];
1860 	char *cats_str;
1861 
1862 	if (ebitmap_cardinality(cats) > 0) {
1863 		cats_str = cats_ebitmap_to_str(cats, pdb->p_cat_val_to_name);
1864 		level_str = create_str("%s:%s", 2, sens_str, cats_str);
1865 		free(cats_str);
1866 	} else {
1867 		level_str = create_str("%s", 1, sens_str);
1868 	}
1869 
1870 	return level_str;
1871 }
1872 
range_to_str(struct policydb * pdb,mls_range_t * range)1873 static char *range_to_str(struct policydb *pdb, mls_range_t *range)
1874 {
1875 	char *low = NULL;
1876 	char *high = NULL;
1877 	char *range_str = NULL;
1878 
1879 	low = level_to_str(pdb, &range->level[0]);
1880 	if (!low) {
1881 		goto exit;
1882 	}
1883 
1884 	high = level_to_str(pdb, &range->level[1]);
1885 	if (!high) {
1886 		goto exit;
1887 	}
1888 
1889 	range_str = create_str("%s - %s", 2, low, high);
1890 
1891 exit:
1892 	free(low);
1893 	free(high);
1894 
1895 	return range_str;
1896 }
1897 
1898 struct map_range_trans_args {
1899 	struct policydb *pdb;
1900 	struct strs *strs;
1901 };
1902 
map_range_trans_to_str(hashtab_key_t key,void * data,void * arg)1903 static int map_range_trans_to_str(hashtab_key_t key, void *data, void *arg)
1904 {
1905 	range_trans_t *rt = (range_trans_t *)key;
1906 	mls_range_t *mls_range = data;
1907 	struct map_range_trans_args *map_args = arg;
1908 	struct policydb *pdb = map_args->pdb;
1909 	struct strs *strs = map_args->strs;
1910 	char *src, *tgt, *class, *range;
1911 	int rc;
1912 
1913 	src = pdb->p_type_val_to_name[rt->source_type - 1];
1914 	tgt = pdb->p_type_val_to_name[rt->target_type - 1];
1915 	class = pdb->p_class_val_to_name[rt->target_class - 1];
1916 	range = range_to_str(pdb, mls_range);
1917 	if (!range) {
1918 		rc = -1;
1919 		goto exit;
1920 	}
1921 
1922 	rc = strs_create_and_add(strs, "range_transition %s %s:%s %s;", 4,
1923 				 src, tgt, class, range);
1924 	free(range);
1925 	if (rc != 0) {
1926 		goto exit;
1927 	}
1928 
1929 exit:
1930 	return rc;
1931 }
1932 
write_range_trans_rules_to_conf(FILE * out,struct policydb * pdb)1933 static int write_range_trans_rules_to_conf(FILE *out, struct policydb *pdb)
1934 {
1935 	struct map_range_trans_args args;
1936 	struct strs *strs;
1937 	int rc = 0;
1938 
1939 	rc = strs_init(&strs, 100);
1940 	if (rc != 0) {
1941 		goto exit;
1942 	}
1943 
1944 	args.pdb = pdb;
1945 	args.strs = strs;
1946 
1947 	rc = hashtab_map(pdb->range_tr, map_range_trans_to_str, &args);
1948 	if (rc != 0) {
1949 		goto exit;
1950 	}
1951 
1952 	strs_sort(strs);
1953 	strs_write_each(strs, out);
1954 
1955 exit:
1956 	strs_free_all(strs);
1957 	strs_destroy(&strs);
1958 
1959 	if (rc != 0) {
1960 		sepol_log_err("Error writing range transition rules to policy.conf\n");
1961 	}
1962 
1963 	return rc;
1964 }
1965 
write_cond_av_list_to_conf(FILE * out,struct policydb * pdb,cond_av_list_t * cond_list,int indent)1966 static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_list_t *cond_list, int indent)
1967 {
1968 	cond_av_list_t *cond_av;
1969 	avtab_ptr_t node;
1970 	uint32_t flavor;
1971 	avtab_key_t *key;
1972 	avtab_datum_t *datum;
1973 	struct strs *strs;
1974 	char *rule;
1975 	unsigned i;
1976 	int rc;
1977 
1978 	for (i = 0; i < AVTAB_FLAVORS_SZ; i++) {
1979 		flavor = avtab_flavors[i];
1980 		rc = strs_init(&strs, 64);
1981 		if (rc != 0) {
1982 			goto exit;
1983 		}
1984 
1985 		for (cond_av = cond_list; cond_av != NULL; cond_av = cond_av->next) {
1986 			node = cond_av->node;
1987 			key = &node->key;
1988 			datum = &node->datum;
1989 			if (key->specified & flavor) {
1990 				rule = avtab_node_to_str(pdb, key, datum);
1991 				if (!rule) {
1992 					rc = -1;
1993 					goto exit;
1994 				}
1995 				rc = strs_add(strs, rule);
1996 				if (rc != 0) {
1997 					free(rule);
1998 					goto exit;
1999 				}
2000 			}
2001 		}
2002 
2003 		strs_sort(strs);
2004 		strs_write_each_indented(strs, out, indent);
2005 		strs_free_all(strs);
2006 		strs_destroy(&strs);
2007 	}
2008 
2009 	return 0;
2010 
2011 exit:
2012 	strs_free_all(strs);
2013 	strs_destroy(&strs);
2014 	return rc;
2015 }
2016 
2017 struct cond_data {
2018 	char *expr;
2019 	struct cond_node *cond;
2020 };
2021 
cond_node_cmp(const void * a,const void * b)2022 static int cond_node_cmp(const void *a, const void *b)
2023 {
2024 	const struct cond_data *aa = a;
2025 	const struct cond_data *bb = b;
2026 	return strcmp(aa->expr, bb->expr);
2027 }
2028 
write_cond_nodes_to_conf(FILE * out,struct policydb * pdb)2029 static int write_cond_nodes_to_conf(FILE *out, struct policydb *pdb)
2030 {
2031 	struct cond_data *cond_data;
2032 	char *expr;
2033 	struct cond_node *cond;
2034 	unsigned i, num;
2035 	int rc = 0;
2036 
2037 	num = 0;
2038 	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
2039 		num++;
2040 	}
2041 
2042 	if (num == 0) {
2043 		return 0;
2044 	}
2045 
2046 	cond_data = calloc(sizeof(struct cond_data), num);
2047 	if (!cond_data) {
2048 		rc = -1;
2049 		goto exit;
2050 	}
2051 
2052 	i = 0;
2053 	for (cond = pdb->cond_list; cond != NULL; cond = cond->next) {
2054 		cond_data[i].cond = cond;
2055 		expr = cond_expr_to_str(pdb, cond->expr);
2056 		if (!expr) {
2057 			num = i;
2058 			goto exit;
2059 		}
2060 		cond_data[i].expr = expr;
2061 		i++;
2062 	}
2063 
2064 	qsort(cond_data, num, sizeof(*cond_data), cond_node_cmp);
2065 
2066 	for (i=0; i<num; i++) {
2067 		expr = cond_data[i].expr;
2068 		cond = cond_data[i].cond;
2069 
2070 		sepol_printf(out, "if (%s) {\n", expr);
2071 
2072 		if (cond->true_list != NULL) {
2073 			rc = write_cond_av_list_to_conf(out, pdb, cond->true_list, 1);
2074 			if (rc != 0) {
2075 				goto exit;
2076 			}
2077 		}
2078 
2079 		if (cond->false_list != NULL) {
2080 			sepol_printf(out, "} else {\n");
2081 			rc = write_cond_av_list_to_conf(out, pdb, cond->false_list, 1);
2082 			if (rc != 0) {
2083 				goto exit;
2084 			}
2085 		}
2086 		sepol_printf(out, "}\n");
2087 	}
2088 
2089 exit:
2090 	if (cond_data) {
2091 		for (i=0; i<num; i++) {
2092 			free(cond_data[i].expr);
2093 		}
2094 		free(cond_data);
2095 	}
2096 
2097 	if (rc != 0) {
2098 		sepol_log_err("Error writing conditional rules to policy.conf\n");
2099 	}
2100 
2101 	return rc;
2102 }
2103 
write_role_decl_rules_to_conf(FILE * out,struct policydb * pdb)2104 static int write_role_decl_rules_to_conf(FILE *out, struct policydb *pdb)
2105 {
2106 	struct role_datum *role;
2107 	struct strs *strs;
2108 	char *name, *types, *p1, *p2;
2109 	unsigned i, num;
2110 	int rc = 0;
2111 
2112 	rc = strs_init(&strs, pdb->p_roles.nprim);
2113 	if (rc != 0) {
2114 		goto exit;
2115 	}
2116 
2117 	/* Start at 1 to skip object_r */
2118 	for (i=1; i < pdb->p_roles.nprim; i++) {
2119 		role = pdb->role_val_to_struct[i];
2120 		if (role && role->flavor == ROLE_ROLE) {
2121 			rc = strs_add(strs, pdb->p_role_val_to_name[i]);
2122 			if (rc != 0) {
2123 				goto exit;
2124 			}
2125 		}
2126 	}
2127 
2128 	strs_sort(strs);
2129 
2130 	num = strs_num_items(strs);
2131 
2132 	for (i=0; i<num; i++) {
2133 		name = strs_read_at_index(strs, i);
2134 		if (!name) {
2135 			continue;
2136 		}
2137 		sepol_printf(out, "role %s;\n", name);
2138 	}
2139 
2140 	for (i=0; i<num; i++) {
2141 		name = strs_read_at_index(strs, i);
2142 		if (!name) continue;
2143 		role = hashtab_search(pdb->p_roles.table, name);
2144 		if (!role) {
2145 			rc = -1;
2146 			goto exit;
2147 		}
2148 		if (ebitmap_cardinality(&role->types.types) == 0) continue;
2149 		types = ebitmap_to_str(&role->types.types, pdb->p_type_val_to_name, 1);
2150 		if (!types) {
2151 			rc = -1;
2152 			goto exit;
2153 		}
2154 		if (strlen(types) > 900) {
2155 			p1 = types;
2156 			while (p1) {
2157 				p2 = p1;
2158 				while (p2 - p1 < 600) {
2159 					p2 = strchr(p2, ' ');
2160 					if (!p2)
2161 						break;
2162 					p2++;
2163 				}
2164 				if (p2) {
2165 					*(p2-1) = '\0';
2166 				}
2167 				sepol_printf(out, "role %s types { %s };\n", name, p1);
2168 				p1 = p2;
2169 			}
2170 		} else {
2171 			sepol_printf(out, "role %s types { %s };\n", name, types);
2172 		}
2173 		free(types);
2174 	}
2175 
2176 exit:
2177 	strs_destroy(&strs);
2178 
2179 	if (rc != 0) {
2180 		sepol_log_err("Error writing role declarations to policy.conf\n");
2181 	}
2182 
2183 	return rc;
2184 }
2185 
write_role_transition_rules_to_conf(FILE * out,struct policydb * pdb)2186 static int write_role_transition_rules_to_conf(FILE *out, struct policydb *pdb)
2187 {
2188 	role_trans_t *curr = pdb->role_tr;
2189 	struct strs *strs;
2190 	char *role, *type, *class, *new;
2191 	int rc = 0;
2192 
2193 	rc = strs_init(&strs, 32);
2194 	if (rc != 0) {
2195 		goto exit;
2196 	}
2197 
2198 	while (curr) {
2199 		role = pdb->p_role_val_to_name[curr->role - 1];
2200 		type = pdb->p_type_val_to_name[curr->type - 1];
2201 		class = pdb->p_class_val_to_name[curr->tclass - 1];
2202 		new = pdb->p_role_val_to_name[curr->new_role - 1];
2203 
2204 		rc = strs_create_and_add(strs, "role_transition %s %s:%s %s;", 4,
2205 					 role, type, class, new);
2206 		if (rc != 0) {
2207 			goto exit;
2208 		}
2209 
2210 		curr = curr->next;
2211 	}
2212 
2213 	strs_sort(strs);
2214 	strs_write_each(strs, out);
2215 
2216 exit:
2217 	strs_free_all(strs);
2218 	strs_destroy(&strs);
2219 
2220 	if (rc != 0) {
2221 		sepol_log_err("Error writing role transition rules to policy.conf\n");
2222 	}
2223 
2224 	return rc;
2225 }
2226 
write_role_allow_rules_to_conf(FILE * out,struct policydb * pdb)2227 static int write_role_allow_rules_to_conf(FILE *out, struct policydb *pdb)
2228 {
2229 	role_allow_t *curr = pdb->role_allow;
2230 	struct strs *strs;
2231 	char *role, *new;
2232 	int rc = 0;
2233 
2234 	rc = strs_init(&strs, 32);
2235 	if (rc != 0) {
2236 		goto exit;
2237 	}
2238 
2239 	while (curr) {
2240 		role = pdb->p_role_val_to_name[curr->role - 1];
2241 		new =  pdb->p_role_val_to_name[curr->new_role - 1];
2242 
2243 		rc = strs_create_and_add(strs, "allow %s %s;", 2, role, new);
2244 		if (rc != 0) {
2245 			goto exit;
2246 		}
2247 
2248 		curr = curr->next;
2249 	}
2250 
2251 	strs_sort(strs);
2252 	strs_write_each(strs, out);
2253 
2254 exit:
2255 	strs_free_all(strs);
2256 	strs_destroy(&strs);
2257 
2258 	if (rc != 0) {
2259 		sepol_log_err("Error writing role allow rules to policy.conf\n");
2260 	}
2261 
2262 	return rc;
2263 }
2264 
write_user_decl_rules_to_conf(FILE * out,struct policydb * pdb)2265 static int write_user_decl_rules_to_conf(FILE *out, struct policydb *pdb)
2266 {
2267 	struct user_datum *user;
2268 	struct strs *strs;
2269 	char *name, *roles, *level, *range;
2270 	unsigned i, num;
2271 	int rc = 0;
2272 
2273 	rc = strs_init(&strs, pdb->p_users.nprim);
2274 	if (rc != 0) {
2275 		goto exit;
2276 	}
2277 
2278 	for (i=0; i < pdb->p_users.nprim; i++) {
2279 		rc = strs_add(strs, pdb->p_user_val_to_name[i]);
2280 		if (rc != 0) {
2281 			goto exit;
2282 		}
2283 	}
2284 
2285 	strs_sort(strs);
2286 
2287 	num = strs_num_items(strs);
2288 
2289 	for (i=0; i<num; i++) {
2290 		name = strs_read_at_index(strs, i);
2291 		if (!name) {
2292 			continue;
2293 		}
2294 		user = hashtab_search(pdb->p_users.table, name);
2295 		if (!user) {
2296 			rc = -1;
2297 			goto exit;
2298 		}
2299 		sepol_printf(out, "user %s", name);
2300 
2301 		if (ebitmap_cardinality(&user->roles.roles) > 0) {
2302 			roles = ebitmap_to_str(&user->roles.roles,
2303 					       pdb->p_role_val_to_name, 1);
2304 			if (!roles) {
2305 				rc = -1;
2306 				goto exit;
2307 			}
2308 			if (strchr(roles, ' ')) {
2309 				sepol_printf(out, " roles { %s }", roles);
2310 			} else {
2311 				sepol_printf(out, " roles %s", roles);
2312 			}
2313 			free(roles);
2314 		}
2315 
2316 		if (pdb->mls) {
2317 			level = level_to_str(pdb, &user->exp_dfltlevel);
2318 			if (!level) {
2319 				rc = -1;
2320 				goto exit;
2321 			}
2322 			sepol_printf(out, " level %s", level);
2323 			free(level);
2324 
2325 			range = range_to_str(pdb, &user->exp_range);
2326 			if (!range) {
2327 				rc = -1;
2328 				goto exit;
2329 			}
2330 			sepol_printf(out, " range %s", range);
2331 			free(range);
2332 		}
2333 		sepol_printf(out, ";\n");
2334 	}
2335 
2336 	strs_destroy(&strs);
2337 
2338 exit:
2339 	if (rc != 0) {
2340 		sepol_log_err("Error writing user declarations to policy.conf\n");
2341 	}
2342 
2343 	return rc;
2344 }
2345 
context_to_str(struct policydb * pdb,struct context_struct * con)2346 static char *context_to_str(struct policydb *pdb, struct context_struct *con)
2347 {
2348 	char *user, *role, *type, *range;
2349 	char *ctx = NULL;
2350 
2351 	user = pdb->p_user_val_to_name[con->user - 1];
2352 	role = pdb->p_role_val_to_name[con->role - 1];
2353 	type = pdb->p_type_val_to_name[con->type - 1];
2354 
2355 	if (pdb->mls) {
2356 		range = range_to_str(pdb, &con->range);
2357 		ctx = create_str("%s:%s:%s:%s", 4, user, role, type, range);
2358 		free(range);
2359 	} else {
2360 		ctx = create_str("%s:%s:%s", 3, user, role, type);
2361 	}
2362 
2363 	return ctx;
2364 }
2365 
write_sid_context_rules_to_conf(FILE * out,struct policydb * pdb,const char * const * sid_to_str,unsigned num_sids)2366 static int write_sid_context_rules_to_conf(FILE *out, struct policydb *pdb, const char *const *sid_to_str, unsigned num_sids)
2367 {
2368 	struct ocontext *isid;
2369 	struct strs *strs;
2370 	char *sid;
2371 	char unknown[18];
2372 	char *ctx, *rule;
2373 	unsigned i;
2374 	int rc;
2375 
2376 	rc = strs_init(&strs, 32);
2377 	if (rc != 0) {
2378 		goto exit;
2379 	}
2380 
2381 	for (isid = pdb->ocontexts[0]; isid != NULL; isid = isid->next) {
2382 		i = isid->sid[0];
2383 		if (i < num_sids) {
2384 			sid = (char *)sid_to_str[i];
2385 		} else {
2386 			snprintf(unknown, sizeof(unknown), "%s%u", "UNKNOWN", i);
2387 			sid = unknown;
2388 		}
2389 
2390 		ctx = context_to_str(pdb, &isid->context[0]);
2391 		if (!ctx) {
2392 			rc = -1;
2393 			goto exit;
2394 		}
2395 
2396 		rule = create_str("sid %s %s", 2, sid, ctx);
2397 		free(ctx);
2398 		if (!rule) {
2399 			rc = -1;
2400 			goto exit;
2401 		}
2402 
2403 		rc = strs_add_at_index(strs, rule, i);
2404 		if (rc != 0) {
2405 			free(rule);
2406 			goto exit;
2407 		}
2408 	}
2409 
2410 	strs_write_each(strs, out);
2411 
2412 exit:
2413 	strs_free_all(strs);
2414 	strs_destroy(&strs);
2415 
2416 	if (rc != 0) {
2417 		sepol_log_err("Error writing sidcontext rules to policy.conf\n");
2418 	}
2419 
2420 	return rc;
2421 }
2422 
write_selinux_isid_rules_to_conf(FILE * out,struct policydb * pdb)2423 static int write_selinux_isid_rules_to_conf(FILE *out, struct policydb *pdb)
2424 {
2425 	return write_sid_context_rules_to_conf(out, pdb, selinux_sid_to_str,
2426 					       SELINUX_SID_SZ);
2427 }
2428 
write_selinux_fsuse_rules_to_conf(FILE * out,struct policydb * pdb)2429 static int write_selinux_fsuse_rules_to_conf(FILE *out, struct policydb *pdb)
2430 {
2431 	struct ocontext *fsuse;
2432 	const char *behavior;
2433 	char *name, *ctx;
2434 	int rc = 0;
2435 
2436 	for (fsuse = pdb->ocontexts[5]; fsuse != NULL; fsuse = fsuse->next) {
2437 		switch (fsuse->v.behavior) {
2438 		case SECURITY_FS_USE_XATTR: behavior = "xattr"; break;
2439 		case SECURITY_FS_USE_TRANS: behavior = "trans"; break;
2440 		case SECURITY_FS_USE_TASK:  behavior = "task"; break;
2441 		default:
2442 			sepol_log_err("Unknown fsuse behavior: %i", fsuse->v.behavior);
2443 			rc = -1;
2444 			goto exit;
2445 		}
2446 
2447 		name = fsuse->u.name;
2448 		ctx = context_to_str(pdb, &fsuse->context[0]);
2449 		if (!ctx) {
2450 			rc = -1;
2451 			goto exit;
2452 		}
2453 
2454 		sepol_printf(out, "fs_use_%s %s %s;\n", behavior, name, ctx);
2455 
2456 		free(ctx);
2457 	}
2458 
2459 exit:
2460 	if (rc != 0) {
2461 		sepol_log_err("Error writing fsuse rules to policy.conf\n");
2462 	}
2463 
2464 	return rc;
2465 }
2466 
write_genfscon_rules_to_conf(FILE * out,struct policydb * pdb)2467 static int write_genfscon_rules_to_conf(FILE *out, struct policydb *pdb)
2468 {
2469 	struct genfs *genfs;
2470 	struct ocontext *ocon;
2471 	struct strs *strs;
2472 	char *fstype, *name, *ctx;
2473 	int rc;
2474 
2475 	rc = strs_init(&strs, 32);
2476 	if (rc != 0) {
2477 		goto exit;
2478 	}
2479 
2480 	for (genfs = pdb->genfs; genfs != NULL; genfs = genfs->next) {
2481 		for (ocon = genfs->head; ocon != NULL; ocon = ocon->next) {
2482 			fstype = genfs->fstype;
2483 			name = ocon->u.name;
2484 
2485 			ctx = context_to_str(pdb, &ocon->context[0]);
2486 			if (!ctx) {
2487 				rc = -1;
2488 				goto exit;
2489 			}
2490 
2491 			rc = strs_create_and_add(strs, "genfscon %s %s %s", 3,
2492 						 fstype, name, ctx);
2493 			free(ctx);
2494 			if (rc != 0) {
2495 				goto exit;
2496 			}
2497 		}
2498 	}
2499 
2500 	strs_sort(strs);
2501 	strs_write_each(strs, out);
2502 
2503 exit:
2504 	strs_free_all(strs);
2505 	strs_destroy(&strs);
2506 
2507 	if (rc != 0) {
2508 		sepol_log_err("Error writing genfscon rules to policy.conf\n");
2509 	}
2510 
2511 	return rc;
2512 }
2513 
write_selinux_port_rules_to_conf(FILE * out,struct policydb * pdb)2514 static int write_selinux_port_rules_to_conf(FILE *out, struct policydb *pdb)
2515 {
2516 	struct ocontext *portcon;
2517 	const char *protocol;
2518 	uint16_t low;
2519 	uint16_t high;
2520 	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
2521 	char *ctx;
2522 	int rc = 0;
2523 
2524 	for (portcon = pdb->ocontexts[2]; portcon != NULL; portcon = portcon->next) {
2525 		switch (portcon->u.port.protocol) {
2526 		case IPPROTO_TCP: protocol = "tcp"; break;
2527 		case IPPROTO_UDP: protocol = "udp"; break;
2528 		case IPPROTO_DCCP: protocol = "dccp"; break;
2529 		case IPPROTO_SCTP: protocol = "sctp"; break;
2530 		default:
2531 			sepol_log_err("Unknown portcon protocol: %i", portcon->u.port.protocol);
2532 			rc = -1;
2533 			goto exit;
2534 		}
2535 
2536 		low = portcon->u.port.low_port;
2537 		high = portcon->u.port.high_port;
2538 		if (low == high) {
2539 			rc = snprintf(low_high_str, 44, "%u", low);
2540 		} else {
2541 			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
2542 		}
2543 		if (rc < 0 || rc >= 44) {
2544 			rc = -1;
2545 			goto exit;
2546 		}
2547 
2548 		ctx = context_to_str(pdb, &portcon->context[0]);
2549 		if (!ctx) {
2550 			rc = -1;
2551 			goto exit;
2552 		}
2553 
2554 		sepol_printf(out, "portcon %s %s %s\n", protocol, low_high_str, ctx);
2555 
2556 		free(ctx);
2557 	}
2558 
2559 	rc = 0;
2560 
2561 exit:
2562 	if (rc != 0) {
2563 		sepol_log_err("Error writing portcon rules to policy.conf\n");
2564 	}
2565 
2566 	return rc;
2567 }
2568 
write_selinux_netif_rules_to_conf(FILE * out,struct policydb * pdb)2569 static int write_selinux_netif_rules_to_conf(FILE *out, struct policydb *pdb)
2570 {
2571 	struct ocontext *netif;
2572 	char *name, *ctx1, *ctx2;
2573 	int rc = 0;
2574 
2575 	for (netif = pdb->ocontexts[3]; netif != NULL; netif = netif->next) {
2576 		name = netif->u.name;
2577 		ctx1 = context_to_str(pdb, &netif->context[0]);
2578 		if (!ctx1) {
2579 			rc = -1;
2580 			goto exit;
2581 		}
2582 		ctx2 = context_to_str(pdb, &netif->context[1]);
2583 		if (!ctx2) {
2584 			free(ctx1);
2585 			rc = -1;
2586 			goto exit;
2587 		}
2588 
2589 		sepol_printf(out, "netifcon %s %s %s\n", name, ctx1, ctx2);
2590 
2591 		free(ctx1);
2592 		free(ctx2);
2593 	}
2594 
2595 exit:
2596 	if (rc != 0) {
2597 		sepol_log_err("Error writing netifcon rules to policy.conf\n");
2598 	}
2599 
2600 	return rc;
2601 }
2602 
write_selinux_node_rules_to_conf(FILE * out,struct policydb * pdb)2603 static int write_selinux_node_rules_to_conf(FILE *out, struct policydb *pdb)
2604 {
2605 	struct ocontext *node;
2606 	char addr[INET_ADDRSTRLEN];
2607 	char mask[INET_ADDRSTRLEN];
2608 	char *ctx;
2609 	int rc = 0;
2610 
2611 	for (node = pdb->ocontexts[4]; node != NULL; node = node->next) {
2612 		if (inet_ntop(AF_INET, &node->u.node.addr, addr, INET_ADDRSTRLEN) == NULL) {
2613 			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
2614 			rc = -1;
2615 			goto exit;
2616 		}
2617 
2618 		if (inet_ntop(AF_INET, &node->u.node.mask, mask, INET_ADDRSTRLEN) == NULL) {
2619 			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
2620 			rc = -1;
2621 			goto exit;
2622 		}
2623 
2624 		ctx = context_to_str(pdb, &node->context[0]);
2625 		if (!ctx) {
2626 			rc = -1;
2627 			goto exit;
2628 		}
2629 
2630 		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
2631 
2632 		free(ctx);
2633 	}
2634 
2635 exit:
2636 	if (rc != 0) {
2637 		sepol_log_err("Error writing nodecon rules to policy.conf\n");
2638 	}
2639 
2640 	return rc;
2641 }
2642 
2643 
write_selinux_node6_rules_to_conf(FILE * out,struct policydb * pdb)2644 static int write_selinux_node6_rules_to_conf(FILE *out, struct policydb *pdb)
2645 {
2646 	struct ocontext *node6;
2647 	char addr[INET6_ADDRSTRLEN];
2648 	char mask[INET6_ADDRSTRLEN];
2649 	char *ctx;
2650 	int rc = 0;
2651 
2652 	for (node6 = pdb->ocontexts[6]; node6 != NULL; node6 = node6->next) {
2653 		if (inet_ntop(AF_INET6, &node6->u.node6.addr, addr, INET6_ADDRSTRLEN) == NULL) {
2654 			sepol_log_err("Nodecon address is invalid: %s", strerror(errno));
2655 			rc = -1;
2656 			goto exit;
2657 		}
2658 
2659 		if (inet_ntop(AF_INET6, &node6->u.node6.mask, mask, INET6_ADDRSTRLEN) == NULL) {
2660 			sepol_log_err("Nodecon mask is invalid: %s", strerror(errno));
2661 			rc = -1;
2662 			goto exit;
2663 		}
2664 
2665 		ctx = context_to_str(pdb, &node6->context[0]);
2666 		if (!ctx) {
2667 			rc = -1;
2668 			goto exit;
2669 		}
2670 
2671 		sepol_printf(out, "nodecon %s %s %s\n", addr, mask, ctx);
2672 
2673 		free(ctx);
2674 	}
2675 
2676 exit:
2677 	if (rc != 0) {
2678 		sepol_log_err("Error writing nodecon rules to policy.conf\n");
2679 	}
2680 
2681 	return rc;
2682 }
2683 
write_selinux_ibpkey_rules_to_conf(FILE * out,struct policydb * pdb)2684 static int write_selinux_ibpkey_rules_to_conf(FILE *out, struct policydb *pdb)
2685 {
2686 	struct ocontext *ibpkeycon;
2687 	char subnet_prefix_str[INET6_ADDRSTRLEN];
2688 	struct in6_addr subnet_prefix = IN6ADDR_ANY_INIT;
2689 	uint16_t low;
2690 	uint16_t high;
2691 	char low_high_str[44]; /* 2^64 <= 20 digits so "low-high" <= 44 chars */
2692 	char *ctx;
2693 	int rc = 0;
2694 
2695 	for (ibpkeycon = pdb->ocontexts[OCON_IBPKEY]; ibpkeycon != NULL;
2696 	     ibpkeycon = ibpkeycon->next) {
2697 		memcpy(&subnet_prefix.s6_addr, &ibpkeycon->u.ibpkey.subnet_prefix,
2698 		       sizeof(ibpkeycon->u.ibpkey.subnet_prefix));
2699 
2700 		if (inet_ntop(AF_INET6, &subnet_prefix.s6_addr,
2701 			      subnet_prefix_str, INET6_ADDRSTRLEN) == NULL) {
2702 			sepol_log_err("ibpkeycon address is invalid: %s",
2703 				      strerror(errno));
2704 			rc = -1;
2705 			goto exit;
2706 		}
2707 
2708 		low = ibpkeycon->u.ibpkey.low_pkey;
2709 		high = ibpkeycon->u.ibpkey.high_pkey;
2710 		if (low == high) {
2711 			rc = snprintf(low_high_str, 44, "%u", low);
2712 		} else {
2713 			rc = snprintf(low_high_str, 44, "%u-%u", low, high);
2714 		}
2715 		if (rc < 0 || rc >= 44) {
2716 			rc = -1;
2717 			goto exit;
2718 		}
2719 
2720 		ctx = context_to_str(pdb, &ibpkeycon->context[0]);
2721 		if (!ctx) {
2722 			rc = -1;
2723 			goto exit;
2724 		}
2725 
2726 		sepol_printf(out, "ibpkeycon %s %s %s\n", subnet_prefix_str,
2727 			     low_high_str, ctx);
2728 
2729 		free(ctx);
2730 	}
2731 
2732 	rc = 0;
2733 
2734 exit:
2735 	if (rc != 0) {
2736 		sepol_log_err("Error writing ibpkeycon rules to policy.conf\n");
2737 	}
2738 
2739 	return rc;
2740 }
2741 
write_selinux_ibendport_rules_to_conf(FILE * out,struct policydb * pdb)2742 static int write_selinux_ibendport_rules_to_conf(FILE *out, struct policydb *pdb)
2743 {
2744 	struct ocontext *ibendportcon;
2745 	char port_str[4];
2746 	char *ctx;
2747 	int rc = 0;
2748 
2749 	for (ibendportcon = pdb->ocontexts[OCON_IBENDPORT];
2750 	     ibendportcon != NULL; ibendportcon = ibendportcon->next) {
2751 		rc = snprintf(port_str, 4, "%u", ibendportcon->u.ibendport.port);
2752 		if (rc < 0 || rc >= 4) {
2753 			rc = -1;
2754 			goto exit;
2755 		}
2756 
2757 		ctx = context_to_str(pdb, &ibendportcon->context[0]);
2758 		if (!ctx) {
2759 			rc = -1;
2760 			goto exit;
2761 		}
2762 
2763 		sepol_printf(out, "ibendportcon %s %s %s\n", ibendportcon->u.ibendport.dev_name, port_str, ctx);
2764 
2765 		free(ctx);
2766 	}
2767 
2768 	rc = 0;
2769 
2770 exit:
2771 	if (rc != 0) {
2772 		sepol_log_err("Error writing ibendportcon rules to policy.conf\n");
2773 	}
2774 
2775 	return rc;
2776 }
2777 
write_xen_isid_rules_to_conf(FILE * out,struct policydb * pdb)2778 static int write_xen_isid_rules_to_conf(FILE *out, struct policydb *pdb)
2779 {
2780 	return write_sid_context_rules_to_conf(out, pdb, xen_sid_to_str, XEN_SID_SZ);
2781 }
2782 
2783 
write_xen_pirq_rules_to_conf(FILE * out,struct policydb * pdb)2784 static int write_xen_pirq_rules_to_conf(FILE *out, struct policydb *pdb)
2785 {
2786 	struct ocontext *pirq;
2787 	char pirq_str[21]; /* 2^64-1 <= 20 digits */
2788 	char *ctx;
2789 	int rc = 0;
2790 
2791 	for (pirq = pdb->ocontexts[1]; pirq != NULL; pirq = pirq->next) {
2792 		rc = snprintf(pirq_str, 21, "%i", pirq->u.pirq);
2793 		if (rc < 0 || rc >= 21) {
2794 			fprintf(stderr,"error1\n");
2795 			rc = -1;
2796 			goto exit;
2797 		}
2798 
2799 		ctx = context_to_str(pdb, &pirq->context[0]);
2800 		if (!ctx) {
2801 			rc = -1;
2802 			fprintf(stderr,"error2\n");
2803 			goto exit;
2804 		}
2805 
2806 		sepol_printf(out, "pirqcon %s %s\n", pirq_str, ctx);
2807 
2808 		free(ctx);
2809 	}
2810 
2811 	rc = 0;
2812 
2813 exit:
2814 	if (rc != 0) {
2815 		sepol_log_err("Error writing pirqcon rules to policy.conf\n");
2816 	}
2817 
2818 	return rc;
2819 }
2820 
write_xen_ioport_rules_to_conf(FILE * out,struct policydb * pdb)2821 static int write_xen_ioport_rules_to_conf(FILE *out, struct policydb *pdb)
2822 {
2823 	struct ocontext *ioport;
2824 	uint32_t low;
2825 	uint32_t high;
2826 	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
2827 	char *ctx;
2828 	int rc = 0;
2829 
2830 	for (ioport = pdb->ocontexts[2]; ioport != NULL; ioport = ioport->next) {
2831 		low = ioport->u.ioport.low_ioport;
2832 		high = ioport->u.ioport.high_ioport;
2833 		if (low == high) {
2834 			rc = snprintf(low_high_str, 40, "0x%x", low);
2835 		} else {
2836 			rc = snprintf(low_high_str, 40, "0x%x-0x%x", low, high);
2837 		}
2838 		if (rc < 0 || rc >= 40) {
2839 			rc = -1;
2840 			goto exit;
2841 		}
2842 
2843 		ctx = context_to_str(pdb, &ioport->context[0]);
2844 		if (!ctx) {
2845 			rc = -1;
2846 			goto exit;
2847 		}
2848 
2849 		sepol_printf(out, "ioportcon %s %s\n", low_high_str, ctx);
2850 
2851 		free(ctx);
2852 	}
2853 
2854 	rc = 0;
2855 
2856 exit:
2857 	if (rc != 0) {
2858 		sepol_log_err("Error writing ioportcon rules to policy.conf\n");
2859 	}
2860 
2861 	return rc;
2862 }
2863 
write_xen_iomem_rules_to_conf(FILE * out,struct policydb * pdb)2864 static int write_xen_iomem_rules_to_conf(FILE *out, struct policydb *pdb)
2865 {
2866 	struct ocontext *iomem;
2867 	uint64_t low;
2868 	uint64_t high;
2869 	char low_high_str[40]; /* 2^64-1 <= 16 digits (hex) so low-high < 40 chars */
2870 	char *ctx;
2871 	int rc = 0;
2872 
2873 	for (iomem = pdb->ocontexts[3]; iomem != NULL; iomem = iomem->next) {
2874 		low = iomem->u.iomem.low_iomem;
2875 		high = iomem->u.iomem.high_iomem;
2876 		if (low == high) {
2877 			rc = snprintf(low_high_str, 40, "0x%"PRIx64, low);
2878 		} else {
2879 			rc = snprintf(low_high_str, 40, "0x%"PRIx64"-0x%"PRIx64, low, high);
2880 		}
2881 		if (rc < 0 || rc >= 40) {
2882 			rc = -1;
2883 			goto exit;
2884 		}
2885 
2886 		ctx = context_to_str(pdb, &iomem->context[0]);
2887 		if (!ctx) {
2888 			rc = -1;
2889 			goto exit;
2890 		}
2891 
2892 		sepol_printf(out, "iomemcon %s %s\n", low_high_str, ctx);
2893 
2894 		free(ctx);
2895 	}
2896 
2897 	rc = 0;
2898 
2899 exit:
2900 	if (rc != 0) {
2901 		sepol_log_err("Error writing iomemcon rules to policy.conf\n");
2902 	}
2903 
2904 	return rc;
2905 }
2906 
write_xen_pcidevice_rules_to_conf(FILE * out,struct policydb * pdb)2907 static int write_xen_pcidevice_rules_to_conf(FILE *out, struct policydb *pdb)
2908 {
2909 	struct ocontext *pcid;
2910 	char device_str[20]; /* 2^64-1 <= 16 digits (hex) so < 19 chars */
2911 	char *ctx;
2912 	int rc = 0;
2913 
2914 	for (pcid = pdb->ocontexts[4]; pcid != NULL; pcid = pcid->next) {
2915 		rc = snprintf(device_str, 20, "0x%lx", (unsigned long)pcid->u.device);
2916 		if (rc < 0 || rc >= 20) {
2917 			rc = -1;
2918 			goto exit;
2919 		}
2920 
2921 		ctx = context_to_str(pdb, &pcid->context[0]);
2922 		if (!ctx) {
2923 			rc = -1;
2924 			goto exit;
2925 		}
2926 
2927 		sepol_printf(out, "pcidevicecon %s %s\n", device_str, ctx);
2928 
2929 		free(ctx);
2930 	}
2931 
2932 	rc = 0;
2933 
2934 exit:
2935 	if (rc != 0) {
2936 		sepol_log_err("Error writing pcidevicecon rules to policy.conf\n");
2937 	}
2938 
2939 	return rc;
2940 }
2941 
write_xen_devicetree_rules_to_conf(FILE * out,struct policydb * pdb)2942 static int write_xen_devicetree_rules_to_conf(FILE *out, struct policydb *pdb)
2943 {
2944 	struct ocontext *dtree;
2945 	char *name, *ctx;
2946 	int rc = 0;
2947 
2948 	for (dtree = pdb->ocontexts[5]; dtree != NULL; dtree = dtree->next) {
2949 		name = dtree->u.name;
2950 		ctx = context_to_str(pdb, &dtree->context[0]);
2951 		if (!ctx) {
2952 			rc = -1;
2953 			goto exit;
2954 		}
2955 
2956 		sepol_printf(out, "devicetreecon %s %s\n", name, ctx);
2957 
2958 		free(ctx);
2959 	}
2960 
2961 exit:
2962 	if (rc != 0) {
2963 		sepol_log_err("Error writing devicetreecon rules to policy.conf\n");
2964 	}
2965 
2966 	return rc;
2967 }
2968 
sepol_kernel_policydb_to_conf(FILE * out,struct policydb * pdb)2969 int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb)
2970 {
2971 	struct strs *mls_constraints = NULL;
2972 	struct strs *non_mls_constraints = NULL;
2973 	struct strs *mls_validatetrans = NULL;
2974 	struct strs *non_mls_validatetrans = NULL;
2975 	int rc = 0;
2976 
2977 	rc = strs_init(&mls_constraints, 32);
2978 	if (rc != 0) {
2979 		goto exit;
2980 	}
2981 
2982 	rc = strs_init(&non_mls_constraints, 32);
2983 	if (rc != 0) {
2984 		goto exit;
2985 	}
2986 
2987 	rc = strs_init(&mls_validatetrans, 32);
2988 	if (rc != 0) {
2989 		goto exit;
2990 	}
2991 
2992 	rc = strs_init(&non_mls_validatetrans, 32);
2993 	if (rc != 0) {
2994 		goto exit;
2995 	}
2996 
2997 	if (pdb == NULL) {
2998 		sepol_log_err("No policy");
2999 		rc = -1;
3000 		goto exit;
3001 	}
3002 
3003 	if (pdb->policy_type != SEPOL_POLICY_KERN) {
3004 		sepol_log_err("Policy is not a kernel policy");
3005 		rc = -1;
3006 		goto exit;
3007 	}
3008 
3009 	rc = constraint_rules_to_strs(pdb, mls_constraints, non_mls_constraints);
3010 	if (rc != 0) {
3011 		goto exit;
3012 	}
3013 
3014 	rc = validatetrans_rules_to_strs(pdb, mls_validatetrans, non_mls_validatetrans);
3015 	if (rc != 0) {
3016 		goto exit;
3017 	}
3018 
3019 	rc = write_handle_unknown_to_conf(out, pdb);
3020 	if (rc != 0) {
3021 		goto exit;
3022 	}
3023 
3024 	rc = write_class_decl_rules_to_conf(out, pdb);
3025 	if (rc != 0) {
3026 		goto exit;
3027 	}
3028 
3029 	rc = write_sid_decl_rules_to_conf(out, pdb);
3030 	if (rc != 0) {
3031 		goto exit;
3032 	}
3033 
3034 	rc = write_class_and_common_rules_to_conf(out, pdb);
3035 	if (rc != 0) {
3036 		goto exit;
3037 	}
3038 
3039 	rc = write_default_rules_to_conf(out, pdb);
3040 	if (rc != 0) {
3041 		goto exit;
3042 	}
3043 
3044 	rc = write_mls_rules_to_conf(out, pdb);
3045 	if (rc != 0) {
3046 		goto exit;
3047 	}
3048 
3049 	strs_write_each(mls_constraints, out);
3050 	strs_write_each(mls_validatetrans, out);
3051 
3052 	rc = write_polcap_rules_to_conf(out, pdb);
3053 	if (rc != 0) {
3054 		goto exit;
3055 	}
3056 
3057 	rc = write_type_attributes_to_conf(out, pdb);
3058 	if (rc != 0) {
3059 		goto exit;
3060 	}
3061 
3062 	rc = write_role_attributes_to_conf(out, pdb);
3063 	if (rc != 0) {
3064 		goto exit;
3065 	}
3066 
3067 	rc = write_boolean_decl_rules_to_conf(out, pdb);
3068 	if (rc != 0) {
3069 		goto exit;
3070 	}
3071 
3072 	rc = write_type_decl_rules_to_conf(out, pdb);
3073 	if (rc != 0) {
3074 		goto exit;
3075 	}
3076 
3077 	rc = write_type_alias_rules_to_conf(out, pdb);
3078 	if (rc != 0) {
3079 		goto exit;
3080 	}
3081 
3082 	rc = write_type_bounds_rules_to_conf(out, pdb);
3083 	if (rc != 0) {
3084 		goto exit;
3085 	}
3086 
3087 	rc = write_type_attribute_sets_to_conf(out, pdb);
3088 	if (rc != 0) {
3089 		goto exit;
3090 	}
3091 
3092 	rc = write_type_permissive_rules_to_conf(out, pdb);
3093 	if (rc != 0) {
3094 		goto exit;
3095 	}
3096 
3097 	rc = write_avtab_to_conf(out, pdb, 0);
3098 	if (rc != 0) {
3099 		goto exit;
3100 	}
3101 	write_filename_trans_rules_to_conf(out, pdb);
3102 
3103 	if (pdb->mls) {
3104 		rc = write_range_trans_rules_to_conf(out, pdb);
3105 		if (rc != 0) {
3106 			goto exit;
3107 		}
3108 	}
3109 
3110 	rc = write_cond_nodes_to_conf(out, pdb);
3111 	if (rc != 0) {
3112 		goto exit;
3113 	}
3114 
3115 	rc = write_role_decl_rules_to_conf(out, pdb);
3116 	if (rc != 0) {
3117 		goto exit;
3118 	}
3119 
3120 	rc = write_role_transition_rules_to_conf(out, pdb);
3121 	if (rc != 0) {
3122 		goto exit;
3123 	}
3124 
3125 	rc = write_role_allow_rules_to_conf(out, pdb);
3126 	if (rc != 0) {
3127 		goto exit;
3128 	}
3129 
3130 	rc = write_user_decl_rules_to_conf(out, pdb);
3131 	if (rc != 0) {
3132 		goto exit;
3133 	}
3134 
3135 	strs_write_each(non_mls_constraints, out);
3136 	strs_write_each(non_mls_validatetrans, out);
3137 
3138 	rc = sort_ocontexts(pdb);
3139 	if (rc != 0) {
3140 		goto exit;
3141 	}
3142 
3143 	if (pdb->target_platform == SEPOL_TARGET_SELINUX) {
3144 		rc = write_selinux_isid_rules_to_conf(out, pdb);
3145 		if (rc != 0) {
3146 			goto exit;
3147 		}
3148 
3149 		rc = write_selinux_fsuse_rules_to_conf(out, pdb);
3150 		if (rc != 0) {
3151 			goto exit;
3152 		}
3153 
3154 		rc = write_genfscon_rules_to_conf(out, pdb);
3155 		if (rc != 0) {
3156 			goto exit;
3157 		}
3158 
3159 		rc = write_selinux_port_rules_to_conf(out, pdb);
3160 		if (rc != 0) {
3161 			goto exit;
3162 		}
3163 
3164 		rc = write_selinux_netif_rules_to_conf(out, pdb);
3165 		if (rc != 0) {
3166 			goto exit;
3167 		}
3168 
3169 		rc = write_selinux_node_rules_to_conf(out, pdb);
3170 		if (rc != 0) {
3171 			goto exit;
3172 		}
3173 
3174 		rc = write_selinux_node6_rules_to_conf(out, pdb);
3175 		if (rc != 0) {
3176 			goto exit;
3177 		}
3178 
3179 		rc = write_selinux_ibpkey_rules_to_conf(out, pdb);
3180 		if (rc != 0) {
3181 			goto exit;
3182 		}
3183 
3184 		rc = write_selinux_ibendport_rules_to_conf(out, pdb);
3185 		if (rc != 0) {
3186 			goto exit;
3187 		}
3188 	} else if (pdb->target_platform == SEPOL_TARGET_XEN) {
3189 		rc = write_xen_isid_rules_to_conf(out, pdb);
3190 		if (rc != 0) {
3191 			goto exit;
3192 		}
3193 
3194 		rc = write_genfscon_rules_to_conf(out, pdb);
3195 		if (rc != 0) {
3196 			goto exit;
3197 		}
3198 
3199 		rc = write_xen_pirq_rules_to_conf(out, pdb);
3200 		if (rc != 0) {
3201 			goto exit;
3202 		}
3203 
3204 		rc = write_xen_iomem_rules_to_conf(out, pdb);
3205 		if (rc != 0) {
3206 			goto exit;
3207 		}
3208 
3209 		rc = write_xen_ioport_rules_to_conf(out, pdb);
3210 		if (rc != 0) {
3211 			goto exit;
3212 		}
3213 
3214 		rc = write_xen_pcidevice_rules_to_conf(out, pdb);
3215 		if (rc != 0) {
3216 			goto exit;
3217 		}
3218 
3219 		rc = write_xen_devicetree_rules_to_conf(out, pdb);
3220 		if (rc != 0) {
3221 			goto exit;
3222 		}
3223 	}
3224 
3225 exit:
3226 	strs_free_all(mls_constraints);
3227 	strs_destroy(&mls_constraints);
3228 	strs_free_all(non_mls_constraints);
3229 	strs_destroy(&non_mls_constraints);
3230 	strs_free_all(mls_validatetrans);
3231 	strs_destroy(&mls_validatetrans);
3232 	strs_free_all(non_mls_validatetrans);
3233 	strs_destroy(&non_mls_validatetrans);
3234 
3235 	return rc;
3236 }
3237