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