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