android.c revision d10c3437e60a40d49e9359e1de23b018859e5d45
1#include <sys/types.h> 2#include <unistd.h> 3#include <string.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <ctype.h> 7#include <errno.h> 8#include <pwd.h> 9#include <grp.h> 10#include <sys/mman.h> 11#include <sys/mount.h> 12#include <sys/types.h> 13#include <sys/stat.h> 14#include <fcntl.h> 15#include <selinux/selinux.h> 16#include <selinux/context.h> 17#include <selinux/android.h> 18#include <selinux/label.h> 19#include <selinux/avc.h> 20#include <private/android_filesystem_config.h> 21#include "policy.h" 22#include "callbacks.h" 23#include "selinux_internal.h" 24 25/* 26 * XXX Where should this configuration file be located? 27 * Needs to be accessible by zygote and installd when 28 * setting credentials for app processes and setting permissions 29 * on app data directories. 30 */ 31static char const * const seapp_contexts_file[] = { 32 "/data/system/seapp_contexts", 33 "/seapp_contexts", 34 0 }; 35 36static const struct selinux_opt seopts[] = { 37 { SELABEL_OPT_PATH, "/data/system/file_contexts" }, 38 { SELABEL_OPT_PATH, "/file_contexts" }, 39 { 0, NULL } }; 40 41static const char *const sepolicy_file[] = { 42 "/data/system/sepolicy", 43 "/sepolicy", 44 0 }; 45 46struct seapp_context { 47 /* input selectors */ 48 char isSystemServer; 49 char *user; 50 size_t len; 51 char prefix; 52 char *seinfo; 53 char *name; 54 /* outputs */ 55 char *domain; 56 char *type; 57 char *level; 58 char *sebool; 59 char levelFromUid; 60}; 61 62static int seapp_context_cmp(const void *A, const void *B) 63{ 64 const struct seapp_context *const *sp1 = A, *const *sp2 = B; 65 const struct seapp_context *s1 = *sp1, *s2 = *sp2; 66 67 /* Give precedence to isSystemServer=true. */ 68 if (s1->isSystemServer != s2->isSystemServer) 69 return (s1->isSystemServer ? -1 : 1); 70 71 /* Give precedence to a specified user= over an unspecified user=. */ 72 if (s1->user && !s2->user) 73 return -1; 74 if (!s1->user && s2->user) 75 return 1; 76 77 if (s1->user) { 78 /* Give precedence to a fixed user= string over a prefix. */ 79 if (s1->prefix != s2->prefix) 80 return (s2->prefix ? -1 : 1); 81 82 /* Give precedence to a longer prefix over a shorter prefix. */ 83 if (s1->prefix && s1->len != s2->len) 84 return (s1->len > s2->len) ? -1 : 1; 85 } 86 87 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */ 88 if (s1->seinfo && !s2->seinfo) 89 return -1; 90 if (!s1->seinfo && s2->seinfo) 91 return 1; 92 93 /* Give precedence to a specified name= over an unspecified name=. */ 94 if (s1->name && !s2->name) 95 return -1; 96 if (!s1->name && s2->name) 97 return 1; 98 99 /* Give precedence to a specified sebool= over an unspecified sebool=. */ 100 if (s1->sebool && !s2->sebool) 101 return -1; 102 if (!s1->sebool && s2->sebool) 103 return 1; 104 105 /* Anything else has equal precedence. */ 106 return 0; 107} 108 109static struct seapp_context **seapp_contexts = NULL; 110static int nspec = 0; 111 112int selinux_android_seapp_context_reload(void) 113{ 114 FILE *fp = NULL; 115 char line_buf[BUFSIZ]; 116 char *token; 117 unsigned lineno; 118 struct seapp_context *cur; 119 char *p, *name = NULL, *value = NULL, *saveptr; 120 size_t len; 121 int i = 0, ret; 122 123 while ((fp==NULL) && seapp_contexts_file[i]) 124 fp = fopen(seapp_contexts_file[i++], "r"); 125 126 if (!fp) { 127 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__); 128 return -1; 129 } 130 131 nspec = 0; 132 while (fgets(line_buf, sizeof line_buf - 1, fp)) { 133 p = line_buf; 134 while (isspace(*p)) 135 p++; 136 if (*p == '#' || *p == 0) 137 continue; 138 nspec++; 139 } 140 141 seapp_contexts = calloc(nspec, sizeof(struct seapp_context *)); 142 if (!seapp_contexts) 143 goto oom; 144 145 rewind(fp); 146 nspec = 0; 147 lineno = 1; 148 while (fgets(line_buf, sizeof line_buf - 1, fp)) { 149 len = strlen(line_buf); 150 if (line_buf[len - 1] == '\n') 151 line_buf[len - 1] = 0; 152 p = line_buf; 153 while (isspace(*p)) 154 p++; 155 if (*p == '#' || *p == 0) 156 continue; 157 158 cur = calloc(1, sizeof(struct seapp_context)); 159 if (!cur) 160 goto oom; 161 162 token = strtok_r(p, " \t", &saveptr); 163 if (!token) 164 goto err; 165 166 while (1) { 167 name = token; 168 value = strchr(name, '='); 169 if (!value) 170 goto err; 171 *value++ = 0; 172 173 if (!strcasecmp(name, "isSystemServer")) { 174 if (!strcasecmp(value, "true")) 175 cur->isSystemServer = 1; 176 else if (!strcasecmp(value, "false")) 177 cur->isSystemServer = 0; 178 else { 179 goto err; 180 } 181 } else if (!strcasecmp(name, "user")) { 182 cur->user = strdup(value); 183 if (!cur->user) 184 goto oom; 185 cur->len = strlen(cur->user); 186 if (cur->user[cur->len-1] == '*') 187 cur->prefix = 1; 188 } else if (!strcasecmp(name, "seinfo")) { 189 cur->seinfo = strdup(value); 190 if (!cur->seinfo) 191 goto oom; 192 } else if (!strcasecmp(name, "name")) { 193 cur->name = strdup(value); 194 if (!cur->name) 195 goto oom; 196 } else if (!strcasecmp(name, "domain")) { 197 cur->domain = strdup(value); 198 if (!cur->domain) 199 goto oom; 200 } else if (!strcasecmp(name, "type")) { 201 cur->type = strdup(value); 202 if (!cur->type) 203 goto oom; 204 } else if (!strcasecmp(name, "levelFromUid")) { 205 if (!strcasecmp(value, "true")) 206 cur->levelFromUid = 1; 207 else if (!strcasecmp(value, "false")) 208 cur->levelFromUid = 0; 209 else { 210 goto err; 211 } 212 } else if (!strcasecmp(name, "level")) { 213 cur->level = strdup(value); 214 if (!cur->level) 215 goto oom; 216 } else if (!strcasecmp(name, "sebool")) { 217 cur->sebool = strdup(value); 218 if (!cur->sebool) 219 goto oom; 220 } else 221 goto err; 222 223 token = strtok_r(NULL, " \t", &saveptr); 224 if (!token) 225 break; 226 } 227 228 seapp_contexts[nspec] = cur; 229 nspec++; 230 lineno++; 231 } 232 233 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *), 234 seapp_context_cmp); 235 236#if DEBUG 237 { 238 int i; 239 for (i = 0; i < nspec; i++) { 240 cur = seapp_contexts[i]; 241 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s user=%s seinfo=%s name=%s sebool=%s -> domain=%s type=%s level=%s levelFromUid=%s", 242 __FUNCTION__, 243 cur->isSystemServer ? "true" : "false", cur->user, 244 cur->seinfo, cur->name, cur->sebool, cur->domain, 245 cur->type, cur->level, 246 cur->levelFromUid ? "true" : "false"); 247 } 248 } 249#endif 250 251 ret = 0; 252 253out: 254 fclose(fp); 255 return ret; 256 257err: 258 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n", 259 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value); 260 ret = -1; 261 goto out; 262oom: 263 selinux_log(SELINUX_ERROR, 264 "%s: Out of memory\n", __FUNCTION__); 265 ret = -1; 266 goto out; 267} 268 269 270static void seapp_context_init(void) 271{ 272 selinux_android_seapp_context_reload(); 273} 274 275static pthread_once_t once = PTHREAD_ONCE_INIT; 276 277/* 278 * Max appid (uid - AID_APP) that can be mapped to category set uniquely 279 * using the current scheme. 280 */ 281#define CAT_MAPPING_MAX_APPID (0x1<<16) 282 283enum seapp_kind { 284 SEAPP_TYPE, 285 SEAPP_DOMAIN 286}; 287 288static int seapp_context_lookup(enum seapp_kind kind, 289 uid_t uid, 290 int isSystemServer, 291 const char *seinfo, 292 const char *pkgname, 293 context_t ctx) 294{ 295 const char *username = NULL; 296 char *end = NULL; 297 struct passwd *pw; 298 struct seapp_context *cur; 299 int i; 300 size_t n; 301 uid_t appid = 0; 302 303 appid = uid % AID_USER; 304 if (appid < AID_APP) { 305 for (n = 0; n < android_id_count; n++) { 306 if (android_ids[n].aid == appid) { 307 username = android_ids[n].name; 308 break; 309 } 310 } 311 if (!username) 312 goto err; 313 } else if (appid < AID_ISOLATED_START) { 314 username = "_app"; 315 appid -= AID_APP; 316 } else { 317 username = "_isolated"; 318 appid -= AID_ISOLATED_START; 319 } 320 321 if (appid >= CAT_MAPPING_MAX_APPID) 322 goto err; 323 324 for (i = 0; i < nspec; i++) { 325 cur = seapp_contexts[i]; 326 327 if (cur->isSystemServer != isSystemServer) 328 continue; 329 330 if (cur->user) { 331 if (cur->prefix) { 332 if (strncasecmp(username, cur->user, cur->len-1)) 333 continue; 334 } else { 335 if (strcasecmp(username, cur->user)) 336 continue; 337 } 338 } 339 340 if (cur->seinfo) { 341 if (!seinfo || strcasecmp(seinfo, cur->seinfo)) 342 continue; 343 } 344 345 if (cur->name) { 346 if (!pkgname || strcasecmp(pkgname, cur->name)) 347 continue; 348 } 349 350 if (kind == SEAPP_TYPE && !cur->type) 351 continue; 352 else if (kind == SEAPP_DOMAIN && !cur->domain) 353 continue; 354 355 if (cur->sebool) { 356 int value = security_get_boolean_active(cur->sebool); 357 if (value == 0) 358 continue; 359 else if (value == -1) { 360 selinux_log(SELINUX_ERROR, \ 361 "Could not find boolean: %s ", cur->sebool); 362 goto err; 363 } 364 } 365 366 if (kind == SEAPP_TYPE) { 367 if (context_type_set(ctx, cur->type)) 368 goto oom; 369 } else if (kind == SEAPP_DOMAIN) { 370 if (context_type_set(ctx, cur->domain)) 371 goto oom; 372 } 373 374 if (cur->levelFromUid) { 375 char level[255]; 376 snprintf(level, sizeof level, "%s:c%u,c%u", 377 context_range_get(ctx), appid & 0xff, 378 256 + (appid>>8 & 0xff)); 379 if (context_range_set(ctx, level)) 380 goto oom; 381 } else if (cur->level) { 382 if (context_range_set(ctx, cur->level)) 383 goto oom; 384 } 385 386 break; 387 } 388 389 if (kind == SEAPP_DOMAIN && i == nspec) { 390 /* 391 * No match. 392 * Fail to prevent staying in the zygote's context. 393 */ 394 selinux_log(SELINUX_ERROR, 395 "%s: No match for app with uid %d, seinfo %s, name %s\n", 396 __FUNCTION__, uid, seinfo, pkgname); 397 398 if (security_getenforce() == 1) 399 goto err; 400 } 401 402 return 0; 403err: 404 return -1; 405oom: 406 return -2; 407} 408 409int selinux_android_setfilecon2(const char *pkgdir, 410 const char *pkgname, 411 const char *seinfo, 412 uid_t uid) 413{ 414 char *orig_ctx_str = NULL, *ctx_str; 415 context_t ctx = NULL; 416 int rc; 417 418 if (is_selinux_enabled() <= 0) 419 return 0; 420 421 __selinux_once(once, seapp_context_init); 422 423 rc = getfilecon(pkgdir, &ctx_str); 424 if (rc < 0) 425 goto err; 426 427 ctx = context_new(ctx_str); 428 orig_ctx_str = ctx_str; 429 if (!ctx) 430 goto oom; 431 432 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx); 433 if (rc == -1) 434 goto err; 435 else if (rc == -2) 436 goto oom; 437 438 ctx_str = context_str(ctx); 439 if (!ctx_str) 440 goto oom; 441 442 rc = security_check_context(ctx_str); 443 if (rc < 0) 444 goto err; 445 446 if (strcmp(ctx_str, orig_ctx_str)) { 447 rc = setfilecon(pkgdir, ctx_str); 448 if (rc < 0) 449 goto err; 450 } 451 452 rc = 0; 453out: 454 freecon(orig_ctx_str); 455 context_free(ctx); 456 return rc; 457err: 458 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n", 459 __FUNCTION__, pkgdir, uid, strerror(errno)); 460 rc = -1; 461 goto out; 462oom: 463 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); 464 rc = -1; 465 goto out; 466} 467 468int selinux_android_setfilecon(const char *pkgdir, 469 const char *pkgname, 470 uid_t uid) 471{ 472 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid); 473} 474 475int selinux_android_setcontext(uid_t uid, 476 int isSystemServer, 477 const char *seinfo, 478 const char *pkgname) 479{ 480 char *orig_ctx_str = NULL, *ctx_str; 481 context_t ctx = NULL; 482 int rc; 483 484 if (is_selinux_enabled() <= 0) 485 return 0; 486 487 __selinux_once(once, seapp_context_init); 488 489 rc = getcon(&ctx_str); 490 if (rc) 491 goto err; 492 493 ctx = context_new(ctx_str); 494 orig_ctx_str = ctx_str; 495 if (!ctx) 496 goto oom; 497 498 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx); 499 if (rc == -1) 500 goto err; 501 else if (rc == -2) 502 goto oom; 503 504 ctx_str = context_str(ctx); 505 if (!ctx_str) 506 goto oom; 507 508 rc = security_check_context(ctx_str); 509 if (rc < 0) 510 goto err; 511 512 if (strcmp(ctx_str, orig_ctx_str)) { 513 rc = setcon(ctx_str); 514 if (rc < 0) 515 goto err; 516 } 517 518 rc = 0; 519out: 520 freecon(orig_ctx_str); 521 context_free(ctx); 522 avc_netlink_close(); 523 return rc; 524err: 525 if (isSystemServer) 526 selinux_log(SELINUX_ERROR, 527 "%s: Error setting context for system server: %s\n", 528 __FUNCTION__, strerror(errno)); 529 else 530 selinux_log(SELINUX_ERROR, 531 "%s: Error setting context for app with uid %d, seinfo %s: %s\n", 532 __FUNCTION__, uid, seinfo, strerror(errno)); 533 534 rc = -1; 535 goto out; 536oom: 537 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__); 538 rc = -1; 539 goto out; 540} 541 542static struct selabel_handle *sehandle = NULL; 543 544static struct selabel_handle *file_context_open(void) 545{ 546 struct selabel_handle *h; 547 int i = 0; 548 549 h = NULL; 550 while ((h == NULL) && seopts[i].value) { 551 h = selabel_open(SELABEL_CTX_FILE, &seopts[i], 1); 552 i++; 553 } 554 555 if (!h) 556 selinux_log(SELINUX_ERROR, "%s: Error getting sehandle label (%s)\n", 557 __FUNCTION__, strerror(errno)); 558 return h; 559} 560 561static void file_context_init(void) 562{ 563 sehandle = file_context_open(); 564} 565 566static pthread_once_t fc_once = PTHREAD_ONCE_INIT; 567 568int selinux_android_restorecon(const char *pathname) 569{ 570 571 if (is_selinux_enabled() <= 0) 572 return 0; 573 574 __selinux_once(fc_once, file_context_init); 575 576 int ret; 577 578 if (!sehandle) 579 goto bail; 580 581 struct stat sb; 582 583 if (lstat(pathname, &sb) < 0) 584 goto err; 585 586 char *oldcontext, *newcontext; 587 588 if (lgetfilecon(pathname, &oldcontext) < 0) 589 goto err; 590 591 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0) 592 goto err; 593 594 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext)) 595 if (lsetfilecon(pathname, newcontext) < 0) 596 goto err; 597 598 ret = 0; 599out: 600 if (oldcontext) 601 freecon(oldcontext); 602 if (newcontext) 603 freecon(newcontext); 604 605 return ret; 606 607err: 608 selinux_log(SELINUX_ERROR, 609 "%s: Error restoring context for %s (%s)\n", 610 __FUNCTION__, pathname, strerror(errno)); 611 612bail: 613 ret = -1; 614 goto out; 615} 616 617 618struct selabel_handle* selinux_android_file_context_handle(void) 619{ 620 return file_context_open(); 621} 622 623int selinux_android_reload_policy(void) 624{ 625 char path[PATH_MAX]; 626 int fd = -1, rc; 627 struct stat sb; 628 void *map = NULL; 629 int i = 0; 630 631 while (fd < 0 && sepolicy_file[i]) { 632 snprintf(path, sizeof(path), "%s", 633 sepolicy_file[i]); 634 fd = open(path, O_RDONLY); 635 i++; 636 } 637 if (fd < 0) { 638 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n", 639 strerror(errno)); 640 return -1; 641 } 642 if (fstat(fd, &sb) < 0) { 643 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n", 644 path, strerror(errno)); 645 close(fd); 646 return -1; 647 } 648 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 649 if (map == MAP_FAILED) { 650 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n", 651 path, strerror(errno)); 652 close(fd); 653 return -1; 654 } 655 656 rc = security_load_policy(map, sb.st_size); 657 if (rc < 0) { 658 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n", 659 strerror(errno)); 660 munmap(map, sb.st_size); 661 close(fd); 662 return -1; 663 } 664 665 munmap(map, sb.st_size); 666 close(fd); 667 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", path); 668 669 return 0; 670} 671 672int selinux_android_load_policy(void) 673{ 674 char *mnt = SELINUXMNT; 675 int rc; 676 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); 677 if (rc < 0) { 678 if (errno == ENODEV) { 679 /* SELinux not enabled in kernel */ 680 return -1; 681 } 682 if (errno == ENOENT) { 683 /* Fall back to legacy mountpoint. */ 684 mnt = OLDSELINUXMNT; 685 mkdir(mnt, 0755); 686 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL); 687 } 688 } 689 if (rc < 0) { 690 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n", 691 strerror(errno)); 692 return -1; 693 } 694 set_selinuxmnt(mnt); 695 696 return selinux_android_reload_policy(); 697} 698