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