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