1#include <stdio.h> 2#include <stdlib.h> 3#include <stdarg.h> 4#include <string.h> 5#include <sys/types.h> 6#include <unistd.h> 7 8#include <arpa/inet.h> 9#include <netinet/in.h> 10#ifndef IPPROTO_DCCP 11#define IPPROTO_DCCP 33 12#endif 13#ifndef IPPROTO_SCTP 14#define IPPROTO_SCTP 132 15#endif 16 17#include <sepol/policydb/ebitmap.h> 18#include <sepol/policydb/hashtab.h> 19#include <sepol/policydb/symtab.h> 20 21#include "private.h" 22#include "kernel_to_common.h" 23 24 25void sepol_log_err(const char *fmt, ...) 26{ 27 va_list argptr; 28 va_start(argptr, fmt); 29 if (vfprintf(stderr, fmt, argptr) < 0) { 30 _exit(EXIT_FAILURE); 31 } 32 va_end(argptr); 33 if (fprintf(stderr, "\n") < 0) { 34 _exit(EXIT_FAILURE); 35 } 36} 37 38void sepol_indent(FILE *out, int indent) 39{ 40 if (fprintf(out, "%*s", indent * 4, "") < 0) { 41 sepol_log_err("Failed to write to output"); 42 } 43} 44 45void sepol_printf(FILE *out, const char *fmt, ...) 46{ 47 va_list argptr; 48 va_start(argptr, fmt); 49 if (vfprintf(out, fmt, argptr) < 0) { 50 sepol_log_err("Failed to write to output"); 51 } 52 va_end(argptr); 53} 54 55__attribute__ ((format(printf, 1, 0))) 56static char *create_str_helper(const char *fmt, int num, va_list vargs) 57{ 58 va_list vargs2; 59 char *str = NULL; 60 char *s; 61 size_t len, s_len; 62 int i, rc; 63 64 va_copy(vargs2, vargs); 65 66 len = strlen(fmt) + 1; /* +1 for '\0' */ 67 68 for (i=0; i<num; i++) { 69 s = va_arg(vargs, char *); 70 s_len = strlen(s); 71 len += s_len > 1 ? s_len - 2 : 0; /* -2 for each %s in fmt */ 72 } 73 74 str = malloc(len); 75 if (!str) { 76 sepol_log_err("Out of memory"); 77 goto exit; 78 } 79 80 rc = vsnprintf(str, len, fmt, vargs2); 81 if (rc < 0 || rc >= (int)len) { 82 goto exit; 83 } 84 85 va_end(vargs2); 86 87 return str; 88 89exit: 90 free(str); 91 va_end(vargs2); 92 return NULL; 93} 94 95char *create_str(const char *fmt, int num, ...) 96{ 97 char *str = NULL; 98 va_list vargs; 99 100 va_start(vargs, num); 101 str = create_str_helper(fmt, num, vargs); 102 va_end(vargs); 103 104 return str; 105} 106 107int strs_init(struct strs **strs, size_t size) 108{ 109 struct strs *new; 110 111 if (size == 0) { 112 size = 1; 113 } 114 115 *strs = NULL; 116 117 new = malloc(sizeof(struct strs)); 118 if (!new) { 119 sepol_log_err("Out of memory"); 120 return -1; 121 } 122 123 new->list = calloc(size, sizeof(char *)); 124 if (!new->list) { 125 sepol_log_err("Out of memory"); 126 free(new); 127 return -1; 128 } 129 130 new->num = 0; 131 new->size = size; 132 133 *strs = new; 134 135 return 0; 136} 137 138void strs_destroy(struct strs **strs) 139{ 140 if (!strs || !*strs) { 141 return; 142 } 143 144 free((*strs)->list); 145 (*strs)->list = NULL; 146 (*strs)->num = 0; 147 (*strs)->size = 0; 148 free(*strs); 149 *strs = NULL; 150} 151 152void strs_free_all(struct strs *strs) 153{ 154 if (!strs) { 155 return; 156 } 157 158 while (strs->num > 0) { 159 strs->num--; 160 free(strs->list[strs->num]); 161 } 162} 163 164int strs_add(struct strs *strs, char *s) 165{ 166 if (strs->num + 1 > strs->size) { 167 char **new; 168 size_t i = strs->size; 169 strs->size *= 2; 170 new = reallocarray(strs->list, strs->size, sizeof(char *)); 171 if (!new) { 172 sepol_log_err("Out of memory"); 173 return -1; 174 } 175 strs->list = new; 176 memset(&strs->list[i], 0, sizeof(char *)*(strs->size-i)); 177 } 178 179 strs->list[strs->num] = s; 180 strs->num++; 181 182 return 0; 183} 184 185int strs_create_and_add(struct strs *strs, const char *fmt, int num, ...) 186{ 187 char *str; 188 va_list vargs; 189 int rc; 190 191 va_start(vargs, num); 192 str = create_str_helper(fmt, num, vargs); 193 va_end(vargs); 194 195 if (!str) { 196 rc = -1; 197 goto exit; 198 } 199 200 rc = strs_add(strs, str); 201 if (rc != 0) { 202 free(str); 203 goto exit; 204 } 205 206 return 0; 207 208exit: 209 return rc; 210} 211 212char *strs_remove_last(struct strs *strs) 213{ 214 if (strs->num == 0) { 215 return NULL; 216 } 217 strs->num--; 218 return strs->list[strs->num]; 219} 220 221int strs_add_at_index(struct strs *strs, char *s, size_t index) 222{ 223 if (index >= strs->size) { 224 char **new; 225 size_t i = strs->size; 226 while (index >= strs->size) { 227 strs->size *= 2; 228 } 229 new = reallocarray(strs->list, strs->size, sizeof(char *)); 230 if (!new) { 231 sepol_log_err("Out of memory"); 232 return -1; 233 } 234 strs->list = new; 235 memset(&strs->list[i], 0, sizeof(char *)*(strs->size - i)); 236 } 237 238 strs->list[index] = s; 239 if (index >= strs->num) { 240 strs->num = index+1; 241 } 242 243 return 0; 244} 245 246char *strs_read_at_index(struct strs *strs, size_t index) 247{ 248 if (index >= strs->num) { 249 return NULL; 250 } 251 252 return strs->list[index]; 253} 254 255static int strs_cmp(const void *a, const void *b) 256{ 257 char *const *aa = a; 258 char *const *bb = b; 259 return strcmp(*aa,*bb); 260} 261 262void strs_sort(struct strs *strs) 263{ 264 if (strs->num == 0) { 265 return; 266 } 267 qsort(strs->list, strs->num, sizeof(char *), strs_cmp); 268} 269 270unsigned strs_num_items(const struct strs *strs) 271{ 272 return strs->num; 273} 274 275size_t strs_len_items(const struct strs *strs) 276{ 277 unsigned i; 278 size_t len = 0; 279 280 for (i=0; i<strs->num; i++) { 281 if (!strs->list[i]) continue; 282 len += strlen(strs->list[i]); 283 } 284 285 return len; 286} 287 288char *strs_to_str(const struct strs *strs) 289{ 290 char *str = NULL; 291 size_t len = 0; 292 char *p; 293 unsigned i; 294 int rc; 295 296 if (strs->num == 0) { 297 goto exit; 298 } 299 300 /* strs->num added because either ' ' or '\0' follows each item */ 301 len = strs_len_items(strs) + strs->num; 302 str = malloc(len); 303 if (!str) { 304 sepol_log_err("Out of memory"); 305 goto exit; 306 } 307 308 p = str; 309 for (i=0; i<strs->num; i++) { 310 if (!strs->list[i]) continue; 311 len = strlen(strs->list[i]); 312 rc = snprintf(p, len+1, "%s", strs->list[i]); 313 if (rc < 0 || rc > (int)len) { 314 free(str); 315 str = NULL; 316 goto exit; 317 } 318 p += len; 319 if (i < strs->num - 1) { 320 *p++ = ' '; 321 } 322 } 323 324 *p = '\0'; 325 326exit: 327 return str; 328} 329 330void strs_write_each(const struct strs *strs, FILE *out) 331{ 332 unsigned i; 333 334 for (i=0; i<strs->num; i++) { 335 if (!strs->list[i]) { 336 continue; 337 } 338 sepol_printf(out, "%s\n",strs->list[i]); 339 } 340} 341 342void strs_write_each_indented(const struct strs *strs, FILE *out, int indent) 343{ 344 unsigned i; 345 346 for (i=0; i<strs->num; i++) { 347 if (!strs->list[i]) { 348 continue; 349 } 350 sepol_indent(out, indent); 351 sepol_printf(out, "%s\n",strs->list[i]); 352 } 353} 354 355int hashtab_ordered_to_strs(char *key, void *data, void *args) 356{ 357 struct strs *strs = (struct strs *)args; 358 symtab_datum_t *datum = data; 359 360 return strs_add_at_index(strs, key, datum->value-1); 361} 362 363int ebitmap_to_strs(const struct ebitmap *map, struct strs *strs, char **val_to_name) 364{ 365 struct ebitmap_node *node; 366 uint32_t i; 367 int rc; 368 369 ebitmap_for_each_positive_bit(map, node, i) { 370 if (!val_to_name[i]) 371 continue; 372 373 rc = strs_add(strs, val_to_name[i]); 374 if (rc != 0) { 375 return -1; 376 } 377 } 378 379 return 0; 380} 381 382char *ebitmap_to_str(const struct ebitmap *map, char **val_to_name, int sort) 383{ 384 struct strs *strs; 385 char *str = NULL; 386 int rc; 387 388 rc = strs_init(&strs, 32); 389 if (rc != 0) { 390 goto exit; 391 } 392 393 rc = ebitmap_to_strs(map, strs, val_to_name); 394 if (rc != 0) { 395 goto exit; 396 } 397 398 if (sort) { 399 strs_sort(strs); 400 } 401 402 str = strs_to_str(strs); 403 404exit: 405 strs_destroy(&strs); 406 407 return str; 408} 409 410int strs_stack_init(struct strs **stack) 411{ 412 return strs_init(stack, STACK_SIZE); 413} 414 415void strs_stack_destroy(struct strs **stack) 416{ 417 return strs_destroy(stack); 418} 419 420int strs_stack_push(struct strs *stack, char *s) 421{ 422 return strs_add(stack, s); 423} 424 425char *strs_stack_pop(struct strs *stack) 426{ 427 return strs_remove_last(stack); 428} 429 430int strs_stack_empty(const struct strs *stack) 431{ 432 return strs_num_items(stack) == 0; 433} 434 435static int compare_ranges(uint64_t l1, uint64_t h1, uint64_t l2, uint64_t h2) 436{ 437 uint64_t d1, d2; 438 439 d1 = h1-l1; 440 d2 = h2-l2; 441 442 if (d1 < d2) { 443 return -1; 444 } else if (d1 > d2) { 445 return 1; 446 } else { 447 if (l1 < l2) { 448 return -1; 449 } else if (l1 > l2) { 450 return 1; 451 } 452 } 453 454 return 0; 455} 456 457static int fsuse_data_cmp(const void *a, const void *b) 458{ 459 struct ocontext *const *aa = a; 460 struct ocontext *const *bb = b; 461 462 if ((*aa)->v.behavior != (*bb)->v.behavior) { 463 if ((*aa)->v.behavior < (*bb)->v.behavior) { 464 return -1; 465 } else { 466 return 1; 467 } 468 } 469 470 return strcmp((*aa)->u.name, (*bb)->u.name); 471} 472 473static int portcon_data_cmp(const void *a, const void *b) 474{ 475 struct ocontext *const *aa = a; 476 struct ocontext *const *bb = b; 477 int rc; 478 479 rc = compare_ranges((*aa)->u.port.low_port, (*aa)->u.port.high_port, 480 (*bb)->u.port.low_port, (*bb)->u.port.high_port); 481 if (rc == 0) { 482 if ((*aa)->u.port.protocol < (*bb)->u.port.protocol) { 483 rc = -1; 484 } else if ((*aa)->u.port.protocol > (*bb)->u.port.protocol) { 485 rc = 1; 486 } 487 } 488 489 return rc; 490} 491 492static int netif_data_cmp(const void *a, const void *b) 493{ 494 struct ocontext *const *aa = a; 495 struct ocontext *const *bb = b; 496 497 return strcmp((*aa)->u.name, (*bb)->u.name); 498} 499 500static int node_data_cmp(const void *a, const void *b) 501{ 502 struct ocontext *const *aa = a; 503 struct ocontext *const *bb = b; 504 int rc; 505 506 rc = memcmp(&(*aa)->u.node.mask, &(*bb)->u.node.mask, sizeof((*aa)->u.node.mask)); 507 if (rc > 0) { 508 return -1; 509 } else if (rc < 0) { 510 return 1; 511 } 512 513 return memcmp(&(*aa)->u.node.addr, &(*bb)->u.node.addr, sizeof((*aa)->u.node.addr)); 514} 515 516static int node6_data_cmp(const void *a, const void *b) 517{ 518 struct ocontext *const *aa = a; 519 struct ocontext *const *bb = b; 520 int rc; 521 522 rc = memcmp(&(*aa)->u.node6.mask, &(*bb)->u.node6.mask, sizeof((*aa)->u.node6.mask)); 523 if (rc > 0) { 524 return -1; 525 } else if (rc < 0) { 526 return 1; 527 } 528 529 return memcmp(&(*aa)->u.node6.addr, &(*bb)->u.node6.addr, sizeof((*aa)->u.node6.addr)); 530} 531 532static int ibpkey_data_cmp(const void *a, const void *b) 533{ 534 int rc; 535 struct ocontext *const *aa = a; 536 struct ocontext *const *bb = b; 537 538 rc = (*aa)->u.ibpkey.subnet_prefix - (*bb)->u.ibpkey.subnet_prefix; 539 if (rc) 540 return rc; 541 542 return compare_ranges((*aa)->u.ibpkey.low_pkey, (*aa)->u.ibpkey.high_pkey, 543 (*bb)->u.ibpkey.low_pkey, (*bb)->u.ibpkey.high_pkey); 544} 545 546static int ibendport_data_cmp(const void *a, const void *b) 547{ 548 int rc; 549 struct ocontext *const *aa = a; 550 struct ocontext *const *bb = b; 551 552 rc = strcmp((*aa)->u.ibendport.dev_name, (*bb)->u.ibendport.dev_name); 553 if (rc) 554 return rc; 555 556 return (*aa)->u.ibendport.port - (*bb)->u.ibendport.port; 557} 558 559static int pirq_data_cmp(const void *a, const void *b) 560{ 561 struct ocontext *const *aa = a; 562 struct ocontext *const *bb = b; 563 564 if ((*aa)->u.pirq < (*bb)->u.pirq) { 565 return -1; 566 } else if ((*aa)->u.pirq > (*bb)->u.pirq) { 567 return 1; 568 } 569 570 return 0; 571} 572 573static int ioport_data_cmp(const void *a, const void *b) 574{ 575 struct ocontext *const *aa = a; 576 struct ocontext *const *bb = b; 577 578 return compare_ranges((*aa)->u.ioport.low_ioport, (*aa)->u.ioport.high_ioport, 579 (*bb)->u.ioport.low_ioport, (*bb)->u.ioport.high_ioport); 580} 581 582static int iomem_data_cmp(const void *a, const void *b) 583{ 584 struct ocontext *const *aa = a; 585 struct ocontext *const *bb = b; 586 587 return compare_ranges((*aa)->u.iomem.low_iomem, (*aa)->u.iomem.high_iomem, 588 (*bb)->u.iomem.low_iomem, (*bb)->u.iomem.high_iomem); 589} 590 591static int pcid_data_cmp(const void *a, const void *b) 592{ 593 struct ocontext *const *aa = a; 594 struct ocontext *const *bb = b; 595 596 if ((*aa)->u.device < (*bb)->u.device) { 597 return -1; 598 } else if ((*aa)->u.device > (*bb)->u.device) { 599 return 1; 600 } 601 602 return 0; 603} 604 605static int dtree_data_cmp(const void *a, const void *b) 606{ 607 struct ocontext *const *aa = a; 608 struct ocontext *const *bb = b; 609 610 return strcmp((*aa)->u.name, (*bb)->u.name); 611} 612 613static int sort_ocontext_data(struct ocontext **ocons, int (*cmp)(const void *, const void *)) 614{ 615 struct ocontext *ocon; 616 struct ocontext **data; 617 unsigned i, num; 618 619 num = 0; 620 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) { 621 num++; 622 } 623 624 if (num == 0) { 625 return 0; 626 } 627 628 data = calloc(sizeof(*data), num); 629 if (!data) { 630 sepol_log_err("Out of memory\n"); 631 return -1; 632 } 633 634 i = 0; 635 for (ocon = *ocons; ocon != NULL; ocon = ocon->next) { 636 data[i] = ocon; 637 i++; 638 } 639 640 qsort(data, num, sizeof(*data), cmp); 641 642 *ocons = data[0]; 643 for (i=1; i < num; i++) { 644 data[i-1]->next = data[i]; 645 } 646 data[num-1]->next = NULL; 647 648 free(data); 649 650 return 0; 651} 652 653int sort_ocontexts(struct policydb *pdb) 654{ 655 int rc = 0; 656 657 if (pdb->target_platform == SEPOL_TARGET_SELINUX) { 658 rc = sort_ocontext_data(&pdb->ocontexts[5], fsuse_data_cmp); 659 if (rc != 0) { 660 goto exit; 661 } 662 663 rc = sort_ocontext_data(&pdb->ocontexts[2], portcon_data_cmp); 664 if (rc != 0) { 665 goto exit; 666 } 667 668 rc = sort_ocontext_data(&pdb->ocontexts[3], netif_data_cmp); 669 if (rc != 0) { 670 goto exit; 671 } 672 673 rc = sort_ocontext_data(&pdb->ocontexts[4], node_data_cmp); 674 if (rc != 0) { 675 goto exit; 676 } 677 678 rc = sort_ocontext_data(&pdb->ocontexts[6], node6_data_cmp); 679 if (rc != 0) { 680 goto exit; 681 } 682 683 rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBPKEY], ibpkey_data_cmp); 684 if (rc != 0) { 685 goto exit; 686 } 687 688 rc = sort_ocontext_data(&pdb->ocontexts[OCON_IBENDPORT], ibendport_data_cmp); 689 if (rc != 0) { 690 goto exit; 691 } 692 } else if (pdb->target_platform == SEPOL_TARGET_XEN) { 693 rc = sort_ocontext_data(&pdb->ocontexts[1], pirq_data_cmp); 694 if (rc != 0) { 695 goto exit; 696 } 697 698 rc = sort_ocontext_data(&pdb->ocontexts[2], ioport_data_cmp); 699 if (rc != 0) { 700 goto exit; 701 } 702 703 rc = sort_ocontext_data(&pdb->ocontexts[3], iomem_data_cmp); 704 if (rc != 0) { 705 goto exit; 706 } 707 708 rc = sort_ocontext_data(&pdb->ocontexts[4], pcid_data_cmp); 709 if (rc != 0) { 710 goto exit; 711 } 712 713 rc = sort_ocontext_data(&pdb->ocontexts[5], dtree_data_cmp); 714 if (rc != 0) { 715 goto exit; 716 } 717 } 718 719exit: 720 if (rc != 0) { 721 sepol_log_err("Error sorting ocontexts\n"); 722 } 723 724 return rc; 725} 726