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