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