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