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