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