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