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