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