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