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