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 30static 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 108exit: 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 119static 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 259exit: 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 270static 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; 320exit: 321 sepol_log_err("Error gathering constraint rules\n"); 322 return rc; 323} 324 325static 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 359exit: 360 return rc; 361} 362 363static 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 384exit: 385 return rc; 386} 387 388static 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 409exit: 410 return rc; 411} 412 413static 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 437static 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 450static 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 491exit: 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 504static 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} 521static 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 541exit: 542 strs_destroy(&strs); 543 544 return perms; 545} 546 547static 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 611exit: 612 if (rc != 0) { 613 sepol_log_err("Error writing class rules to policy.conf\n"); 614 } 615 616 return rc; 617} 618 619static 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 639static 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 659static 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 679static 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 714static 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 772exit: 773 if (rc != 0) { 774 sepol_log_err("Error writing default rules to policy.conf\n"); 775 } 776 777 return rc; 778} 779 780static 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 793static 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 894exit: 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 911static 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 924static 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 1002exit: 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 1019static size_t cats_ebitmap_len(struct ebitmap *cats, char **val_to_name) 1020{ 1021 struct ebitmap_node *node; 1022 uint32_t i, start, range; 1023 size_t len = 0; 1024 1025 range = 0; 1026 ebitmap_for_each_positive_bit(cats, node, i) { 1027 if (range == 0) 1028 start = i; 1029 1030 range++; 1031 1032 if (ebitmap_get_bit(cats, i+1)) 1033 continue; 1034 1035 len += strlen(val_to_name[start]) + 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 1046static 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 1099exit: 1100 free(catsbuf); 1101 return NULL; 1102} 1103 1104static 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 1130exit: 1131 if (rc != 0) { 1132 sepol_log_err("Error writing level rules to policy.conf\n"); 1133 } 1134 1135 return rc; 1136} 1137 1138static 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 1161exit: 1162 if (rc != 0) { 1163 sepol_log_err("Error writing mls rules to policy.conf\n"); 1164 } 1165 1166 return rc; 1167} 1168 1169static 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 1199exit: 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 1210static 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 1245exit: 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 1255static 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 1290exit: 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 1300static 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 1311static 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 1329exit: 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 1340static 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 1375exit: 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 1385static 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 1396static 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 1408static 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 1449exit: 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 1459static 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 1503exit: 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 1513static 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 1552exit: 1553 return str; 1554} 1555 1556static 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 1576exit: 1577 strs_destroy(&strs); 1578 1579 return str; 1580} 1581 1582static 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 1629exit: 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 1640static 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 1672exit: 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 1682static 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 1761exit: 1762 return NULL; 1763} 1764 1765struct map_avtab_args { 1766 struct policydb *pdb; 1767 uint32_t flavor; 1768 struct strs *strs; 1769}; 1770 1771static 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 1793exit: 1794 return rc; 1795} 1796 1797static 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 1820exit: 1821 strs_free_all(strs); 1822 strs_destroy(&strs); 1823 1824 return rc; 1825} 1826 1827static 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 1839exit: 1840 if (rc != 0) { 1841 sepol_log_err("Error writing avtab rules to policy.conf\n"); 1842 } 1843 1844 return rc; 1845} 1846 1847struct map_filename_trans_args { 1848 struct policydb *pdb; 1849 struct strs *strs; 1850}; 1851 1852static 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 1885static 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 1907exit: 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 1918static 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 1936static 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 1954exit: 1955 free(low); 1956 free(high); 1957 1958 return range_str; 1959} 1960 1961struct map_range_trans_args { 1962 struct policydb *pdb; 1963 struct strs *strs; 1964}; 1965 1966static 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 1992exit: 1993 return rc; 1994} 1995 1996static 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 2018exit: 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 2029static 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 2074exit: 2075 strs_free_all(strs); 2076 strs_destroy(&strs); 2077 return rc; 2078} 2079 2080struct cond_data { 2081 char *expr; 2082 struct cond_node *cond; 2083}; 2084 2085static 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 2092static 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 2152exit: 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 2167static 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 2239exit: 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 2249static 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 2279exit: 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 2290static 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 2317exit: 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 2328static 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 2400exit: 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 2411static 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 2431static 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 2477exit: 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 2488static 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 2494static 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 2524exit: 2525 if (rc != 0) { 2526 sepol_log_err("Error writing fsuse rules to policy.conf\n"); 2527 } 2528 2529 return rc; 2530} 2531 2532static 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 2599exit: 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 2610static 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 2657exit: 2658 if (rc != 0) { 2659 sepol_log_err("Error writing portcon rules to policy.conf\n"); 2660 } 2661 2662 return rc; 2663} 2664 2665static 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 2691exit: 2692 if (rc != 0) { 2693 sepol_log_err("Error writing netifcon rules to policy.conf\n"); 2694 } 2695 2696 return rc; 2697} 2698 2699static 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 2731exit: 2732 if (rc != 0) { 2733 sepol_log_err("Error writing nodecon rules to policy.conf\n"); 2734 } 2735 2736 return rc; 2737} 2738 2739 2740static 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 2772exit: 2773 if (rc != 0) { 2774 sepol_log_err("Error writing nodecon rules to policy.conf\n"); 2775 } 2776 2777 return rc; 2778} 2779 2780static 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 2829exit: 2830 if (rc != 0) { 2831 sepol_log_err("Error writing ibpkeycon rules to policy.conf\n"); 2832 } 2833 2834 return rc; 2835} 2836 2837static 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 2865exit: 2866 if (rc != 0) { 2867 sepol_log_err("Error writing ibendportcon rules to policy.conf\n"); 2868 } 2869 2870 return rc; 2871} 2872 2873static 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 2879static 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 2908exit: 2909 if (rc != 0) { 2910 sepol_log_err("Error writing pirqcon rules to policy.conf\n"); 2911 } 2912 2913 return rc; 2914} 2915 2916static 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 2951exit: 2952 if (rc != 0) { 2953 sepol_log_err("Error writing ioportcon rules to policy.conf\n"); 2954 } 2955 2956 return rc; 2957} 2958 2959static 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 2994exit: 2995 if (rc != 0) { 2996 sepol_log_err("Error writing iomemcon rules to policy.conf\n"); 2997 } 2998 2999 return rc; 3000} 3001 3002static 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 3029exit: 3030 if (rc != 0) { 3031 sepol_log_err("Error writing pcidevicecon rules to policy.conf\n"); 3032 } 3033 3034 return rc; 3035} 3036 3037static 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 3056exit: 3057 if (rc != 0) { 3058 sepol_log_err("Error writing devicetreecon rules to policy.conf\n"); 3059 } 3060 3061 return rc; 3062} 3063 3064int 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 3332exit: 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