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