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