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