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