1 #include <sys/types.h> 2 #include <unistd.h> 3 #include <string.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <stdbool.h> 7 #include <ctype.h> 8 #include <errno.h> 9 #include <pwd.h> 10 #include <grp.h> 11 #include <sys/mman.h> 12 #include <sys/mount.h> 13 #include <sys/types.h> 14 #include <sys/stat.h> 15 #include <sys/xattr.h> 16 #include <fcntl.h> 17 #include <fts.h> 18 #include <selinux/selinux.h> 19 #include <selinux/context.h> 20 #include <selinux/android.h> 21 #include <selinux/label.h> 22 #include <selinux/avc.h> 23 #include <mincrypt/sha.h> 24 #include <private/android_filesystem_config.h> 25 #include <log/log.h> 26 #include "policy.h" 27 #include "callbacks.h" 28 #include "selinux_internal.h" 29 #include "label_internal.h" 30 #include <fnmatch.h> 31 #include <limits.h> 32 33 /* 34 * XXX Where should this configuration file be located? 35 * Needs to be accessible by zygote and installd when 36 * setting credentials for app processes and setting permissions 37 * on app data directories. 38 */ 39 static char const * const seapp_contexts_file[] = { 40 "/seapp_contexts", 41 "/data/security/current/seapp_contexts", 42 NULL }; 43 44 static const struct selinux_opt seopts[] = { 45 { SELABEL_OPT_PATH, "/file_contexts" }, 46 { SELABEL_OPT_PATH, "/data/security/current/file_contexts" }, 47 { 0, NULL } }; 48 49 static const char *const sepolicy_file[] = { 50 "/sepolicy", 51 "/data/security/current/sepolicy", 52 NULL }; 53 54 static const struct selinux_opt seopts_prop[] = { 55 { SELABEL_OPT_PATH, "/property_contexts" }, 56 { SELABEL_OPT_PATH, "/data/security/current/property_contexts" }, 57 { 0, NULL } 58 }; 59 60 static const struct selinux_opt seopts_service[] = { 61 { SELABEL_OPT_PATH, "/service_contexts" }, 62 { SELABEL_OPT_PATH, "/data/security/current/service_contexts" }, 63 { 0, NULL } 64 }; 65 66 enum levelFrom { 67 LEVELFROM_NONE, 68 LEVELFROM_APP, 69 LEVELFROM_USER, 70 LEVELFROM_ALL 71 }; 72 73 #define POLICY_OVERRIDE_VERSION "/data/security/current/selinux_version" 74 #define POLICY_BASE_VERSION "/selinux_version" 75 static int policy_index = 0; 76 77 static void set_policy_index(void) 78 { 79 int fd_base = -1, fd_override = -1; 80 struct stat sb_base; 81 struct stat sb_override; 82 void *map_base, *map_override; 83 84 policy_index = 0; 85 86 fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW); 87 if (fd_base < 0) 88 return; 89 90 if (fstat(fd_base, &sb_base) < 0) 91 goto close_base; 92 93 fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW); 94 if (fd_override < 0) 95 goto close_base; 96 97 if (fstat(fd_override, &sb_override) < 0) 98 goto close_override; 99 100 if (sb_base.st_size != sb_override.st_size) 101 goto close_override; 102 103 map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0); 104 if (map_base == MAP_FAILED) 105 goto close_override; 106 107 map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0); 108 if (map_override == MAP_FAILED) 109 goto unmap_base; 110 111 if (memcmp(map_base, map_override, sb_base.st_size) != 0) 112 goto unmap_override; 113 114 if (access(sepolicy_file[1], R_OK) != 0) 115 goto unmap_override; 116 117 if (access(seopts[1].value, R_OK) != 0) 118 goto unmap_override; 119 120 if (access(seopts_prop[1].value, R_OK) != 0) 121 goto unmap_override; 122 123 if (access(seopts_service[1].value, R_OK) != 0) 124 goto unmap_override; 125 126 if (access(seapp_contexts_file[1], R_OK) != 0) 127 goto unmap_override; 128 129 policy_index = 1; 130 131 unmap_override: 132 munmap(map_override, sb_override.st_size); 133 unmap_base: 134 munmap(map_base, sb_base.st_size); 135 close_override: 136 close(fd_override); 137 close_base: 138 close(fd_base); 139 return; 140 } 141 142 #if DEBUG 143 static char const * const levelFromName[] = { 144 "none", 145 "app", 146 "user", 147 "all" 148 }; 149 #endif 150 151 struct prefix_str { 152 size_t len; 153 char *str; 154 char is_prefix; 155 }; 156 157 static void free_prefix_str(struct prefix_str *p) 158 { 159 if (!p) 160 return; 161 free(p->str); 162 } 163 164 struct seapp_context { 165 /* input selectors */ 166 bool isSystemServer; 167 bool isOwnerSet; 168 bool isOwner; 169 struct prefix_str user; 170 char *seinfo; 171 struct prefix_str name; 172 struct prefix_str path; 173 /* outputs */ 174 char *domain; 175 char *type; 176 char *level; 177 enum levelFrom levelFrom; 178 }; 179 180 static void free_seapp_context(struct seapp_context *s) 181 { 182 if (!s) 183 return; 184 185 free_prefix_str(&s->user); 186 free(s->seinfo); 187 free_prefix_str(&s->name); 188 free_prefix_str(&s->path); 189 free(s->domain); 190 free(s->type); 191 free(s->level); 192 } 193 194 static bool seapp_contexts_dup = false; 195 196 static int seapp_context_cmp(const void *A, const void *B) 197 { 198 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A; 199 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B; 200 const struct seapp_context *s1 = *sp1, *s2 = *sp2; 201 bool dup; 202 203 /* Give precedence to isSystemServer=true. */ 204 if (s1->isSystemServer != s2->isSystemServer) 205 return (s1->isSystemServer ? -1 : 1); 206 207 /* Give precedence to a specified isOwner= over an unspecified isOwner=. */ 208 if (s1->isOwnerSet != s2->isOwnerSet) 209 return (s1->isOwnerSet ? -1 : 1); 210 211 /* Give precedence to a specified user= over an unspecified user=. */ 212 if (s1->user.str && !s2->user.str) 213 return -1; 214 if (!s1->user.str && s2->user.str) 215 return 1; 216 217 if (s1->user.str) { 218 /* Give precedence to a fixed user= string over a prefix. */ 219 if (s1->user.is_prefix != s2->user.is_prefix) 220 return (s2->user.is_prefix ? -1 : 1); 221 222 /* Give precedence to a longer prefix over a shorter prefix. */ 223 if (s1->user.is_prefix && s1->user.len != s2->user.len) 224 return (s1->user.len > s2->user.len) ? -1 : 1; 225 } 226 227 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */ 228 if (s1->seinfo && !s2->seinfo) 229 return -1; 230 if (!s1->seinfo && s2->seinfo) 231 return 1; 232 233 /* Give precedence to a specified name= over an unspecified name=. */ 234 if (s1->name.str && !s2->name.str) 235 return -1; 236 if (!s1->name.str && s2->name.str) 237 return 1; 238 239 if (s1->name.str) { 240 /* Give precedence to a fixed name= string over a prefix. */ 241 if (s1->name.is_prefix != s2->name.is_prefix) 242 return (s2->name.is_prefix ? -1 : 1); 243 244 /* Give precedence to a longer prefix over a shorter prefix. */ 245 if (s1->name.is_prefix && s1->name.len != s2->name.len) 246 return (s1->name.len > s2->name.len) ? -1 : 1; 247 } 248 249 /* Give precedence to a specified path= over an unspecified path=. */ 250 if (s1->path.str && !s2->path.str) 251 return -1; 252 if (!s1->path.str && s2->path.str) 253 return 1; 254 255 if (s1->path.str) { 256 /* Give precedence to a fixed path= string over a prefix. */ 257 if (s1->path.is_prefix != s2->path.is_prefix) 258 return (s2->path.is_prefix ? -1 : 1); 259 260 /* Give precedence to a longer prefix over a shorter prefix. */ 261 if (s1->path.is_prefix && s1->path.len != s2->path.len) 262 return (s1->path.len > s2->path.len) ? -1 : 1; 263 } 264 265 /* 266 * Check for a duplicated entry on the input selectors. 267 * We already compared isSystemServer, isOwnerSet, and isOwner above. 268 * We also have already checked that both entries specify the same 269 * string fields, so if s1 has a non-NULL string, then so does s2. 270 */ 271 dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) && 272 (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) && 273 (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) && 274 (!s1->path.str || !strcmp(s1->path.str, s2->path.str)); 275 if (dup) { 276 seapp_contexts_dup = true; 277 selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n"); 278 if (s1->user.str) 279 selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str); 280 if (s1->seinfo) 281 selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo); 282 if (s1->name.str) 283 selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str); 284 if (s1->path.str) 285 selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str); 286 } 287 288 /* Anything else has equal precedence. */ 289 return 0; 290 } 291 292 static struct seapp_context **seapp_contexts = NULL; 293 static int nspec = 0; 294 295 static void free_seapp_contexts(void) 296 { 297 int n; 298 299 if (!seapp_contexts) 300 return; 301 302 for (n = 0; n < nspec; n++) 303 free_seapp_context(seapp_contexts[n]); 304 305 free(seapp_contexts); 306 seapp_contexts = NULL; 307 nspec = 0; 308 } 309 310 int selinux_android_seapp_context_reload(void) 311 { 312 FILE *fp = NULL; 313 char line_buf[BUFSIZ]; 314 char *token; 315 unsigned lineno; 316 struct seapp_context *cur; 317 char *p, *name = NULL, *value = NULL, *saveptr; 318 size_t len; 319 int n, ret; 320 321 set_policy_index(); 322 323 fp = fopen(seapp_contexts_file[policy_index], "r"); 324 if (!fp) { 325 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); 326 return -1; 327 } 328 329 free_seapp_contexts(); 330 331 nspec = 0; 332 while (fgets(line_buf, sizeof line_buf - 1, fp)) { 333 p = line_buf; 334 while (isspace(*p)) 335 p++; 336 if (*p == '#' || *p == 0) 337 continue; 338 nspec++; 339 } 340 341 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *)); 342 if (!seapp_contexts) 343 goto oom; 344 345 rewind(fp); 346 nspec = 0; 347 lineno = 1; 348 while (fgets(line_buf, sizeof line_buf - 1, fp)) { 349 len = strlen(line_buf); 350 if (line_buf[len - 1] == '\n') 351 line_buf[len - 1] = 0; 352 p = line_buf; 353 while (isspace(*p)) 354 p++; 355 if (*p == '#' || *p == 0) 356 continue; 357 358 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context)); 359 if (!cur) 360 goto oom; 361 362 token = strtok_r(p, " \t", &saveptr); 363 if (!token) { 364 free_seapp_context(cur); 365 goto err; 366 } 367 368 while (1) { 369 name = token; 370 value = strchr(name, '='); 371 if (!value) { 372 free_seapp_context(cur); 373 goto err; 374 } 375 *value++ = 0; 376 377 if (!strcasecmp(name, "isSystemServer")) { 378 if (!strcasecmp(value, "true")) 379 cur->isSystemServer = true; 380 else if (!strcasecmp(value, "false")) 381 cur->isSystemServer = false; 382 else { 383 free_seapp_context(cur); 384 goto err; 385 } 386 } else if (!strcasecmp(name, "isOwner")) { 387 cur->isOwnerSet = true; 388 if (!strcasecmp(value, "true")) 389 cur->isOwner = true; 390 else if (!strcasecmp(value, "false")) 391 cur->isOwner = false; 392 else { 393 free_seapp_context(cur); 394 goto err; 395 } 396 } else if (!strcasecmp(name, "user")) { 397 if (cur->user.str) { 398 free_seapp_context(cur); 399 goto err; 400 } 401 cur->user.str = strdup(value); 402 if (!cur->user.str) { 403 free_seapp_context(cur); 404 goto oom; 405 } 406 cur->user.len = strlen(cur->user.str); 407 if (cur->user.str[cur->user.len-1] == '*') 408 cur->user.is_prefix = 1; 409 } else if (!strcasecmp(name, "seinfo")) { 410 if (cur->seinfo) { 411 free_seapp_context(cur); 412 goto err; 413 } 414 cur->seinfo = strdup(value); 415 if (!cur->seinfo) { 416 free_seapp_context(cur); 417 goto oom; 418 } 419 } else if (!strcasecmp(name, "name")) { 420 if (cur->name.str) { 421 free_seapp_context(cur); 422 goto err; 423 } 424 cur->name.str = strdup(value); 425 if (!cur->name.str) { 426 free_seapp_context(cur); 427 goto oom; 428 } 429 cur->name.len = strlen(cur->name.str); 430 if (cur->name.str[cur->name.len-1] == '*') 431 cur->name.is_prefix = 1; 432 } else if (!strcasecmp(name, "domain")) { 433 if (cur->domain) { 434 free_seapp_context(cur); 435 goto err; 436 } 437 cur->domain = strdup(value); 438 if (!cur->domain) { 439 free_seapp_context(cur); 440 goto oom; 441 } 442 } else if (!strcasecmp(name, "type")) { 443 if (cur->type) { 444 free_seapp_context(cur); 445 goto err; 446 } 447 cur->type = strdup(value); 448 if (!cur->type) { 449 free_seapp_context(cur); 450 goto oom; 451 } 452 } else if (!strcasecmp(name, "levelFromUid")) { 453 if (cur->levelFrom) { 454 free_seapp_context(cur); 455 goto err; 456 } 457 if (!strcasecmp(value, "true")) 458 cur->levelFrom = LEVELFROM_APP; 459 else if (!strcasecmp(value, "false")) 460 cur->levelFrom = LEVELFROM_NONE; 461 else { 462 free_seapp_context(cur); 463 goto err; 464 } 465 } else if (!strcasecmp(name, "levelFrom")) { 466 if (cur->levelFrom) { 467 free_seapp_context(cur); 468 goto err; 469 } 470 if (!strcasecmp(value, "none")) 471 cur->levelFrom = LEVELFROM_NONE; 472 else if (!strcasecmp(value, "app")) 473 cur->levelFrom = LEVELFROM_APP; 474 else if (!strcasecmp(value, "user")) 475 cur->levelFrom = LEVELFROM_USER; 476 else if (!strcasecmp(value, "all")) 477 cur->levelFrom = LEVELFROM_ALL; 478 else { 479 free_seapp_context(cur); 480 goto err; 481 } 482 } else if (!strcasecmp(name, "level")) { 483 if (cur->level) { 484 free_seapp_context(cur); 485 goto err; 486 } 487 cur->level = strdup(value); 488 if (!cur->level) { 489 free_seapp_context(cur); 490 goto oom; 491 } 492 } else if (!strcasecmp(name, "path")) { 493 if (cur->path.str) { 494 free_seapp_context(cur); 495 goto err; 496 } 497 cur->path.str = strdup(value); 498 if (!cur->path.str) { 499 free_seapp_context(cur); 500 goto oom; 501 } 502 cur->path.len = strlen(cur->path.str); 503 if (cur->path.str[cur->path.len-1] == '*') 504 cur->path.is_prefix = 1; 505 } else { 506 free_seapp_context(cur); 507 goto err; 508 } 509 510 token = strtok_r(NULL, " \t", &saveptr); 511 if (!token) 512 break; 513 } 514 515 if (cur->name.str && 516 (!cur->seinfo || !strcmp(cur->seinfo, "default"))) { 517 selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n", 518 seapp_contexts_file[policy_index], cur->name.str, lineno); 519 free_seapp_context(cur); 520 goto err; 521 } 522 523 seapp_contexts[nspec] = cur; 524 nspec++; 525 lineno++; 526 } 527 528 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *), 529 seapp_context_cmp); 530 531 if (seapp_contexts_dup) 532 goto err; 533 534 #if DEBUG 535 { 536 int i; 537 for (i = 0; i < nspec; i++) { 538 cur = seapp_contexts[i]; 539 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isOwner=%s user=%s seinfo=%s name=%s path=%s -> domain=%s type=%s level=%s levelFrom=%s", 540 __FUNCTION__, 541 cur->isSystemServer ? "true" : "false", 542 cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null", 543 cur->user.str, 544 cur->seinfo, cur->name.str, cur->path.str, cur->domain, 545 cur->type, cur->level, 546 levelFromName[cur->levelFrom]); 547 } 548 } 549 #endif 550 551 ret = 0; 552 553 out: 554 fclose(fp); 555 return ret; 556 557 err: 558 selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n", 559 seapp_contexts_file[policy_index], lineno); 560 free_seapp_contexts(); 561 ret = -1; 562 goto out; 563 oom: 564 selinux_log(SELINUX_ERROR, 565 "%s: Out of memory\n", __FUNCTION__); 566 free_seapp_contexts(); 567 ret = -1; 568 goto out; 569 } 570 571 572 static void seapp_context_init(void) 573 { 574 selinux_android_seapp_context_reload(); 575 } 576 577 static pthread_once_t once = PTHREAD_ONCE_INIT; 578 579 /* 580 * Max id that can be mapped to category set uniquely 581 * using the current scheme. 582 */ 583 #define CAT_MAPPING_MAX_ID (0x1<<16) 584 585 enum seapp_kind { 586 SEAPP_TYPE, 587 SEAPP_DOMAIN 588 }; 589 590 static int seapp_context_lookup(enum seapp_kind kind, 591 uid_t uid, 592 bool isSystemServer, 593 const char *seinfo, 594 const char *pkgname, 595 const char *path, 596 context_t ctx) 597 { 598 bool isOwner; 599 const char *username = NULL; 600 struct seapp_context *cur = NULL; 601 int i; 602 size_t n; 603 uid_t userid; 604 uid_t appid; 605 606 __selinux_once(once, seapp_context_init); 607 608 userid = uid / AID_USER; 609 isOwner = (userid == 0); 610 appid = uid % AID_USER; 611 if (appid < AID_APP) { 612 for (n = 0; n < android_id_count; n++) { 613 if (android_ids[n].aid == appid) { 614 username = android_ids[n].name; 615 break; 616 } 617 } 618 if (!username) 619 goto err; 620 } else if (appid < AID_ISOLATED_START) { 621 username = "_app"; 622 appid -= AID_APP; 623 } else { 624 username = "_isolated"; 625 appid -= AID_ISOLATED_START; 626 } 627 628 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID) 629 goto err; 630 631 for (i = 0; i < nspec; i++) { 632 cur = seapp_contexts[i]; 633 634 if (cur->isSystemServer != isSystemServer) 635 continue; 636 637 if (cur->isOwnerSet && cur->isOwner != isOwner) 638 continue; 639 640 if (cur->user.str) { 641 if (cur->user.is_prefix) { 642 if (strncasecmp(username, cur->user.str, cur->user.len-1)) 643 continue; 644 } else { 645 if (strcasecmp(username, cur->user.str)) 646 continue; 647 } 648 } 649 650 if (cur->seinfo) { 651 if (!seinfo || strcasecmp(seinfo, cur->seinfo)) 652 continue; 653 } 654 655 if (cur->name.str) { 656 if(!pkgname) 657 continue; 658 659 if (cur->name.is_prefix) { 660 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1)) 661 continue; 662 } else { 663 if (strcasecmp(pkgname, cur->name.str)) 664 continue; 665 } 666 } 667 668 if (cur->path.str) { 669 if (!path) 670 continue; 671 672 if (cur->path.is_prefix) { 673 if (strncmp(path, cur->path.str, cur->path.len-1)) 674 continue; 675 } else { 676 if (strcmp(path, cur->path.str)) 677 continue; 678 } 679 } 680 681 if (kind == SEAPP_TYPE && !cur->type) 682 continue; 683 else if (kind == SEAPP_DOMAIN && !cur->domain) 684 continue; 685 686 if (kind == SEAPP_TYPE) { 687 if (context_type_set(ctx, cur->type)) 688 goto oom; 689 } else if (kind == SEAPP_DOMAIN) { 690 if (context_type_set(ctx, cur->domain)) 691 goto oom; 692 } 693 694 if (cur->levelFrom != LEVELFROM_NONE) { 695 char level[255]; 696 switch (cur->levelFrom) { 697 case LEVELFROM_APP: 698 snprintf(level, sizeof level, "s0:c%u,c%u", 699 appid & 0xff, 700 256 + (appid>>8 & 0xff)); 701 break; 702 case LEVELFROM_USER: 703 snprintf(level, sizeof level, "s0:c%u,c%u", 704 512 + (userid & 0xff), 705 768 + (userid>>8 & 0xff)); 706 break; 707 case LEVELFROM_ALL: 708 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u", 709 appid & 0xff, 710 256 + (appid>>8 & 0xff), 711 512 + (userid & 0xff), 712 768 + (userid>>8 & 0xff)); 713 break; 714 default: 715 goto err; 716 } 717 if (context_range_set(ctx, level)) 718 goto oom; 719 } else if (cur->level) { 720 if (context_range_set(ctx, cur->level)) 721 goto oom; 722 } 723 724 break; 725 } 726 727 if (kind == SEAPP_DOMAIN && i == nspec) { 728 /* 729 * No match. 730 * Fail to prevent staying in the zygote's context. 731 */ 732 selinux_log(SELINUX_ERROR, 733 "%s: No match for app with uid %d, seinfo %s, name %s\n", 734 __FUNCTION__, uid, seinfo, pkgname); 735 736 if (security_getenforce() == 1) 737 goto err; 738 } 739 740 return 0; 741 err: 742 return -1; 743 oom: 744 return -2; 745 } 746 747 int selinux_android_setfilecon(const char *pkgdir, 748 const char *pkgname, 749 const char *seinfo, 750 uid_t uid) 751 { 752 char *orig_ctx_str = NULL; 753 char *ctx_str = NULL; 754 context_t ctx = NULL; 755 int rc = -1; 756 757 if (is_selinux_enabled() <= 0) 758 return 0; 759 760 rc = getfilecon(pkgdir, &ctx_str); 761 if (rc < 0) 762 goto err; 763 764 ctx = context_new(ctx_str); 765 orig_ctx_str = ctx_str; 766 if (!ctx) 767 goto oom; 768 769 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx); 770 if (rc == -1) 771 goto err; 772 else if (rc == -2) 773 goto oom; 774 775 ctx_str = context_str(ctx); 776 if (!ctx_str) 777 goto oom; 778 779 rc = security_check_context(ctx_str); 780 if (rc < 0) 781 goto err; 782 783 if (strcmp(ctx_str, orig_ctx_str)) { 784 rc = setfilecon(pkgdir, ctx_str); 785 if (rc < 0) 786 goto err; 787 } 788 789 rc = 0; 790 out: 791 freecon(orig_ctx_str); 792 context_free(ctx); 793 return rc; 794 err: 795 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n", 796 __FUNCTION__, pkgdir, uid, strerror(errno)); 797 rc = -1; 798 goto out; 799 oom: 800 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); 801 rc = -1; 802 goto out; 803 } 804 805 int selinux_android_setcontext(uid_t uid, 806 bool isSystemServer, 807 const char *seinfo, 808 const char *pkgname) 809 { 810 char *orig_ctx_str = NULL, *ctx_str; 811 context_t ctx = NULL; 812 int rc = -1; 813 814 if (is_selinux_enabled() <= 0) 815 return 0; 816 817 rc = getcon(&ctx_str); 818 if (rc) 819 goto err; 820 821 ctx = context_new(ctx_str); 822 orig_ctx_str = ctx_str; 823 if (!ctx) 824 goto oom; 825 826 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx); 827 if (rc == -1) 828 goto err; 829 else if (rc == -2) 830 goto oom; 831 832 ctx_str = context_str(ctx); 833 if (!ctx_str) 834 goto oom; 835 836 rc = security_check_context(ctx_str); 837 if (rc < 0) 838 goto err; 839 840 if (strcmp(ctx_str, orig_ctx_str)) { 841 rc = setcon(ctx_str); 842 if (rc < 0) 843 goto err; 844 } 845 846 rc = 0; 847 out: 848 freecon(orig_ctx_str); 849 context_free(ctx); 850 avc_netlink_close(); 851 return rc; 852 err: 853 if (isSystemServer) 854 selinux_log(SELINUX_ERROR, 855 "%s: Error setting context for system server: %s\n", 856 __FUNCTION__, strerror(errno)); 857 else 858 selinux_log(SELINUX_ERROR, 859 "%s: Error setting context for app with uid %d, seinfo %s: %s\n", 860 __FUNCTION__, uid, seinfo, strerror(errno)); 861 862 rc = -1; 863 goto out; 864 oom: 865 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); 866 rc = -1; 867 goto out; 868 } 869 870 static struct selabel_handle *fc_sehandle = NULL; 871 #define FC_DIGEST_SIZE SHA_DIGEST_SIZE 872 static uint8_t fc_digest[FC_DIGEST_SIZE]; 873 874 static bool compute_contexts_hash(const struct selinux_opt opts[], uint8_t c_digest[]) 875 { 876 int fd; 877 struct stat sb; 878 void *map; 879 880 fd = open(opts[policy_index].value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW); 881 if (fd < 0) { 882 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n", 883 opts[policy_index].value, strerror(errno)); 884 return false; 885 } 886 if (fstat(fd, &sb) < 0) { 887 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n", 888 opts[policy_index].value, strerror(errno)); 889 close(fd); 890 return false; 891 } 892 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 893 if (map == MAP_FAILED) { 894 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n", 895 opts[policy_index].value, strerror(errno)); 896 close(fd); 897 return false; 898 } 899 SHA_hash(map, sb.st_size, c_digest); 900 munmap(map, sb.st_size); 901 close(fd); 902 903 return true; 904 } 905 906 static void file_context_init(void) 907 { 908 if (!fc_sehandle) 909 fc_sehandle = selinux_android_file_context_handle(); 910 } 911 912 913 914 static pthread_once_t fc_once = PTHREAD_ONCE_INIT; 915 916 struct pkgInfo { 917 char *name; 918 uid_t uid; 919 bool debuggable; 920 char *dataDir; 921 char *seinfo; 922 struct pkgInfo *next; 923 }; 924 925 #define PKGTAB_SIZE 256 926 static struct pkgInfo *pkgTab[PKGTAB_SIZE]; 927 928 static unsigned int pkghash(const char *pkgname) 929 { 930 unsigned int h = 7; 931 for (; *pkgname; pkgname++) { 932 h = h * 31 + *pkgname; 933 } 934 return h & (PKGTAB_SIZE - 1); 935 } 936 937 /* The file containing the list of installed packages on the system */ 938 #define PACKAGES_LIST_FILE "/data/system/packages.list" 939 940 static void package_info_init(void) 941 { 942 char *buf = NULL; 943 size_t buflen = 0; 944 ssize_t bytesread; 945 FILE *fp; 946 char *cur, *next; 947 struct pkgInfo *pkgInfo = NULL; 948 unsigned int hash; 949 unsigned long lineno = 1; 950 951 fp = fopen(PACKAGES_LIST_FILE, "r"); 952 if (!fp) { 953 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s.\n", 954 PACKAGES_LIST_FILE, strerror(errno)); 955 return; 956 } 957 while ((bytesread = getline(&buf, &buflen, fp)) > 0) { 958 pkgInfo = calloc(1, sizeof(*pkgInfo)); 959 if (!pkgInfo) 960 goto err; 961 next = buf; 962 cur = strsep(&next, " \t\n"); 963 if (!cur) 964 goto err; 965 pkgInfo->name = strdup(cur); 966 if (!pkgInfo->name) 967 goto err; 968 cur = strsep(&next, " \t\n"); 969 if (!cur) 970 goto err; 971 pkgInfo->uid = atoi(cur); 972 if (!pkgInfo->uid) 973 goto err; 974 cur = strsep(&next, " \t\n"); 975 if (!cur) 976 goto err; 977 pkgInfo->debuggable = atoi(cur); 978 cur = strsep(&next, " \t\n"); 979 if (!cur) 980 goto err; 981 pkgInfo->dataDir = strdup(cur); 982 if (!pkgInfo->dataDir) 983 goto err; 984 cur = strsep(&next, " \t\n"); 985 if (!cur) 986 goto err; 987 pkgInfo->seinfo = strdup(cur); 988 if (!pkgInfo->seinfo) 989 goto err; 990 991 hash = pkghash(pkgInfo->name); 992 if (pkgTab[hash]) 993 pkgInfo->next = pkgTab[hash]; 994 pkgTab[hash] = pkgInfo; 995 996 lineno++; 997 } 998 999 #if DEBUG 1000 { 1001 unsigned int buckets, entries, chainlen, longestchain; 1002 1003 buckets = entries = longestchain = 0; 1004 for (hash = 0; hash < PKGTAB_SIZE; hash++) { 1005 if (pkgTab[hash]) { 1006 buckets++; 1007 chainlen = 0; 1008 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) { 1009 chainlen++; 1010 selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n", 1011 __FUNCTION__, 1012 pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo); 1013 } 1014 entries += chainlen; 1015 if (longestchain < chainlen) 1016 longestchain = chainlen; 1017 } 1018 } 1019 selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain); 1020 } 1021 #endif 1022 1023 out: 1024 free(buf); 1025 fclose(fp); 1026 return; 1027 1028 err: 1029 selinux_log(SELINUX_ERROR, "SELinux: Error reading %s on line %lu.\n", 1030 PACKAGES_LIST_FILE, lineno); 1031 if (pkgInfo) { 1032 free(pkgInfo->name); 1033 free(pkgInfo->dataDir); 1034 free(pkgInfo->seinfo); 1035 free(pkgInfo); 1036 } 1037 goto out; 1038 } 1039 1040 static pthread_once_t pkg_once = PTHREAD_ONCE_INIT; 1041 1042 struct pkgInfo *package_info_lookup(const char *name) 1043 { 1044 struct pkgInfo *pkgInfo; 1045 unsigned int hash; 1046 1047 __selinux_once(pkg_once, package_info_init); 1048 1049 hash = pkghash(name); 1050 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) { 1051 if (!strcmp(name, pkgInfo->name)) 1052 return pkgInfo; 1053 } 1054 return NULL; 1055 } 1056 1057 /* The path prefixes of package data directories. */ 1058 #define DATA_DATA_PATH "/data/data" 1059 #define DATA_USER_PATH "/data/user" 1060 #define EXPAND_USER_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user" 1061 #define DATA_DATA_PREFIX DATA_DATA_PATH "/" 1062 #define DATA_USER_PREFIX DATA_USER_PATH "/" 1063 1064 static int pkgdir_selabel_lookup(const char *pathname, 1065 const char *seinfo, 1066 uid_t uid, 1067 char **secontextp) 1068 { 1069 char *pkgname = NULL, *end = NULL; 1070 struct pkgInfo *pkgInfo = NULL; 1071 char *secontext = *secontextp; 1072 context_t ctx = NULL; 1073 int rc = 0; 1074 1075 /* Skip directory prefix before package name. */ 1076 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) { 1077 pathname += sizeof(DATA_DATA_PREFIX) - 1; 1078 } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) { 1079 pathname += sizeof(DATA_USER_PREFIX) - 1; 1080 while (isdigit(*pathname)) 1081 pathname++; 1082 if (*pathname == '/') 1083 pathname++; 1084 else 1085 return 0; 1086 } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) { 1087 pathname += sizeof(EXPAND_USER_PATH); 1088 while (isdigit(*pathname)) 1089 pathname++; 1090 if (*pathname == '/') 1091 pathname++; 1092 else 1093 return 0; 1094 } else 1095 return 0; 1096 1097 if (!(*pathname)) 1098 return 0; 1099 1100 pkgname = strdup(pathname); 1101 if (!pkgname) 1102 return -1; 1103 1104 for (end = pkgname; *end && *end != '/'; end++) 1105 ; 1106 pathname = end; 1107 if (*end) 1108 pathname++; 1109 *end = '\0'; 1110 1111 if (!seinfo) { 1112 pkgInfo = package_info_lookup(pkgname); 1113 if (!pkgInfo) { 1114 selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n", 1115 pkgname, pathname); 1116 free(pkgname); 1117 return -1; 1118 } 1119 } 1120 1121 ctx = context_new(secontext); 1122 if (!ctx) 1123 goto err; 1124 1125 rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0, 1126 pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx); 1127 if (rc < 0) 1128 goto err; 1129 1130 secontext = context_str(ctx); 1131 if (!secontext) 1132 goto err; 1133 1134 if (!strcmp(secontext, *secontextp)) 1135 goto out; 1136 1137 rc = security_check_context(secontext); 1138 if (rc < 0) 1139 goto err; 1140 1141 freecon(*secontextp); 1142 *secontextp = strdup(secontext); 1143 if (!(*secontextp)) 1144 goto err; 1145 1146 rc = 0; 1147 1148 out: 1149 free(pkgname); 1150 context_free(ctx); 1151 return rc; 1152 err: 1153 selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n", 1154 __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno)); 1155 rc = -1; 1156 goto out; 1157 } 1158 1159 #define RESTORECON_LAST "security.restorecon_last" 1160 1161 static int restorecon_sb(const char *pathname, const struct stat *sb, 1162 bool nochange, bool verbose, 1163 const char *seinfo, uid_t uid) 1164 { 1165 char *secontext = NULL; 1166 char *oldsecontext = NULL; 1167 int rc = 0; 1168 1169 if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0) 1170 return 0; /* no match, but not an error */ 1171 1172 if (lgetfilecon(pathname, &oldsecontext) < 0) 1173 goto err; 1174 1175 /* 1176 * For subdirectories of /data/data or /data/user, we ignore selabel_lookup() 1177 * and use pkgdir_selabel_lookup() instead. Files within those directories 1178 * have different labeling rules, based off of /seapp_contexts, and 1179 * installd is responsible for managing these labels instead of init. 1180 */ 1181 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) || 1182 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || 1183 !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) { 1184 if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0) 1185 goto err; 1186 } 1187 1188 if (strcmp(oldsecontext, secontext) != 0) { 1189 if (verbose) 1190 selinux_log(SELINUX_INFO, 1191 "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext); 1192 if (!nochange) { 1193 if (lsetfilecon(pathname, secontext) < 0) 1194 goto err; 1195 } 1196 } 1197 1198 rc = 0; 1199 1200 out: 1201 freecon(oldsecontext); 1202 freecon(secontext); 1203 return rc; 1204 1205 err: 1206 selinux_log(SELINUX_ERROR, 1207 "SELinux: Could not set context for %s: %s\n", 1208 pathname, strerror(errno)); 1209 rc = -1; 1210 goto out; 1211 } 1212 1213 #define SYS_PATH "/sys" 1214 #define SYS_PREFIX SYS_PATH "/" 1215 1216 static int selinux_android_restorecon_common(const char* pathname_orig, 1217 const char *seinfo, 1218 uid_t uid, 1219 unsigned int flags) 1220 { 1221 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false; 1222 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false; 1223 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false; 1224 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false; 1225 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false; 1226 bool issys; 1227 bool setrestoreconlast = true; 1228 struct stat sb; 1229 FTS *fts; 1230 FTSENT *ftsent; 1231 char *pathname; 1232 char * paths[2] = { NULL , NULL }; 1233 int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL; 1234 int error, sverrno; 1235 char xattr_value[FC_DIGEST_SIZE]; 1236 ssize_t size; 1237 1238 if (is_selinux_enabled() <= 0) 1239 return 0; 1240 1241 __selinux_once(fc_once, file_context_init); 1242 1243 if (!fc_sehandle) 1244 return 0; 1245 1246 // convert passed-in pathname to canonical pathname 1247 pathname = realpath(pathname_orig, NULL); 1248 if (!pathname) { 1249 sverrno = errno; 1250 selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path %s restorecon: %s.\n", 1251 pathname_orig, strerror(errno)); 1252 errno = sverrno; 1253 error = -1; 1254 goto cleanup; 1255 } 1256 paths[0] = pathname; 1257 issys = (!strcmp(pathname, SYS_PATH) 1258 || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false; 1259 1260 if (!recurse) { 1261 if (lstat(pathname, &sb) < 0) { 1262 error = -1; 1263 goto cleanup; 1264 } 1265 1266 error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid); 1267 goto cleanup; 1268 } 1269 1270 /* 1271 * Ignore restorecon_last on /data/data or /data/user 1272 * since their labeling is based on seapp_contexts and seinfo 1273 * assignments rather than file_contexts and is managed by 1274 * installd rather than init. 1275 */ 1276 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) || 1277 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || 1278 !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) 1279 setrestoreconlast = false; 1280 1281 /* Also ignore on /sys since it is regenerated on each boot regardless. */ 1282 if (issys) 1283 setrestoreconlast = false; 1284 1285 if (setrestoreconlast) { 1286 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest); 1287 if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) { 1288 selinux_log(SELINUX_INFO, 1289 "SELinux: Skipping restorecon_recursive(%s)\n", 1290 pathname); 1291 error = 0; 1292 goto cleanup; 1293 } 1294 } 1295 1296 fts = fts_open(paths, ftsflags, NULL); 1297 if (!fts) { 1298 error = -1; 1299 goto cleanup; 1300 } 1301 1302 error = 0; 1303 while ((ftsent = fts_read(fts)) != NULL) { 1304 switch (ftsent->fts_info) { 1305 case FTS_DC: 1306 selinux_log(SELINUX_ERROR, 1307 "SELinux: Directory cycle on %s.\n", ftsent->fts_path); 1308 errno = ELOOP; 1309 error = -1; 1310 goto out; 1311 case FTS_DP: 1312 continue; 1313 case FTS_DNR: 1314 selinux_log(SELINUX_ERROR, 1315 "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno)); 1316 fts_set(fts, ftsent, FTS_SKIP); 1317 continue; 1318 case FTS_NS: 1319 selinux_log(SELINUX_ERROR, 1320 "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno)); 1321 fts_set(fts, ftsent, FTS_SKIP); 1322 continue; 1323 case FTS_ERR: 1324 selinux_log(SELINUX_ERROR, 1325 "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno)); 1326 fts_set(fts, ftsent, FTS_SKIP); 1327 continue; 1328 case FTS_D: 1329 if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) { 1330 fts_set(fts, ftsent, FTS_SKIP); 1331 continue; 1332 } 1333 1334 if (!datadata && 1335 (!strcmp(ftsent->fts_path, DATA_DATA_PATH) || 1336 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) || 1337 !fnmatch(EXPAND_USER_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME))) { 1338 // Don't label anything below this directory. 1339 fts_set(fts, ftsent, FTS_SKIP); 1340 // but fall through and make sure we label the directory itself 1341 } 1342 /* fall through */ 1343 default: 1344 error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid); 1345 break; 1346 } 1347 } 1348 1349 // Labeling successful. Mark the top level directory as completed. 1350 if (setrestoreconlast && !nochange && !error) 1351 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0); 1352 1353 out: 1354 sverrno = errno; 1355 (void) fts_close(fts); 1356 errno = sverrno; 1357 cleanup: 1358 free(pathname); 1359 return error; 1360 } 1361 1362 int selinux_android_restorecon(const char *file, unsigned int flags) 1363 { 1364 return selinux_android_restorecon_common(file, NULL, -1, flags); 1365 } 1366 1367 int selinux_android_restorecon_pkgdir(const char *pkgdir, 1368 const char *seinfo, 1369 uid_t uid, 1370 unsigned int flags) 1371 { 1372 return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA); 1373 } 1374 1375 struct selabel_handle* selinux_android_file_context_handle(void) 1376 { 1377 struct selabel_handle *sehandle; 1378 1379 set_policy_index(); 1380 sehandle = selabel_open(SELABEL_CTX_FILE, &seopts[policy_index], 1); 1381 1382 if (!sehandle) { 1383 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n", 1384 __FUNCTION__, strerror(errno)); 1385 return NULL; 1386 } 1387 if (!compute_contexts_hash(seopts, fc_digest)) { 1388 selabel_close(sehandle); 1389 return NULL; 1390 } 1391 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n", 1392 seopts[policy_index].value); 1393 1394 return sehandle; 1395 } 1396 1397 struct selabel_handle* selinux_android_prop_context_handle(void) 1398 { 1399 struct selabel_handle* sehandle; 1400 1401 set_policy_index(); 1402 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, 1403 &seopts_prop[policy_index], 1); 1404 if (!sehandle) { 1405 selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n", 1406 __FUNCTION__, strerror(errno)); 1407 return NULL; 1408 } 1409 selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n", 1410 seopts_prop[policy_index].value); 1411 1412 return sehandle; 1413 } 1414 1415 struct selabel_handle* selinux_android_service_context_handle(void) 1416 { 1417 struct selabel_handle* sehandle; 1418 1419 set_policy_index(); 1420 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP, 1421 &seopts_service[policy_index], 1); 1422 1423 if (!sehandle) { 1424 selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n", 1425 __FUNCTION__, strerror(errno)); 1426 return NULL; 1427 } 1428 selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n", 1429 seopts_service[policy_index].value); 1430 1431 return sehandle; 1432 } 1433 1434 void selinux_android_set_sehandle(const struct selabel_handle *hndl) 1435 { 1436 fc_sehandle = (struct selabel_handle *) hndl; 1437 } 1438 1439 static int selinux_android_load_policy_helper(bool reload) 1440 { 1441 int fd = -1, rc; 1442 struct stat sb; 1443 void *map = NULL; 1444 int old_policy_index = policy_index; 1445 1446 /* 1447 * If reloading policy and there is no /data policy or 1448 * that /data policy has the wrong version and our prior 1449 * load was from the / policy, then just return. 1450 * There is no point in reloading policy from / a second time. 1451 */ 1452 set_policy_index(); 1453 if (reload && !policy_index && !old_policy_index) 1454 return 0; 1455 1456 fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW); 1457 if (fd < 0) { 1458 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n", 1459 strerror(errno)); 1460 return -1; 1461 } 1462 if (fstat(fd, &sb) < 0) { 1463 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n", 1464 sepolicy_file[policy_index], strerror(errno)); 1465 close(fd); 1466 return -1; 1467 } 1468 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 1469 if (map == MAP_FAILED) { 1470 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n", 1471 sepolicy_file[policy_index], strerror(errno)); 1472 close(fd); 1473 return -1; 1474 } 1475 1476 rc = security_load_policy(map, sb.st_size); 1477 if (rc < 0) { 1478 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n", 1479 strerror(errno)); 1480 munmap(map, sb.st_size); 1481 close(fd); 1482 return -1; 1483 } 1484 1485 munmap(map, sb.st_size); 1486 close(fd); 1487 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]); 1488 1489 return 0; 1490 } 1491 1492 int selinux_android_reload_policy(void) 1493 { 1494 return selinux_android_load_policy_helper(true); 1495 } 1496 1497 int selinux_android_load_policy(void) 1498 { 1499 const char *mnt = SELINUXMNT; 1500 int rc; 1501 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); 1502 if (rc < 0) { 1503 if (errno == ENODEV) { 1504 /* SELinux not enabled in kernel */ 1505 return -1; 1506 } 1507 if (errno == ENOENT) { 1508 /* Fall back to legacy mountpoint. */ 1509 mnt = OLDSELINUXMNT; 1510 rc = mkdir(mnt, 0755); 1511 if (rc == -1 && errno != EEXIST) { 1512 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n", 1513 strerror(errno)); 1514 return -1; 1515 } 1516 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); 1517 } 1518 } 1519 if (rc < 0) { 1520 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n", 1521 strerror(errno)); 1522 return -1; 1523 } 1524 set_selinuxmnt(mnt); 1525 1526 return selinux_android_load_policy_helper(false); 1527 } 1528 1529 int selinux_log_callback(int type, const char *fmt, ...) 1530 { 1531 va_list ap; 1532 int priority; 1533 char *strp; 1534 1535 switch(type) { 1536 case SELINUX_WARNING: 1537 priority = ANDROID_LOG_WARN; 1538 break; 1539 case SELINUX_INFO: 1540 priority = ANDROID_LOG_INFO; 1541 break; 1542 default: 1543 priority = ANDROID_LOG_ERROR; 1544 break; 1545 } 1546 1547 va_start(ap, fmt); 1548 if (vasprintf(&strp, fmt, ap) != -1) { 1549 LOG_PRI(priority, "SELinux", "%s", strp); 1550 LOG_EVENT_STRING(AUDITD_LOG_TAG, strp); 1551 free(strp); 1552 } 1553 va_end(ap); 1554 return 0; 1555 } 1556