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