Home | History | Annotate | Download | only in src
      1 #include <sys/types.h>
      2 #include <unistd.h>
      3 #include <string.h>
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 #include <ctype.h>
      7 #include <errno.h>
      8 #include <pwd.h>
      9 #include <grp.h>
     10 #include <dirent.h>
     11 #include <sys/mman.h>
     12 #include <sys/mount.h>
     13 #include <sys/types.h>
     14 #include <sys/stat.h>
     15 #include <fcntl.h>
     16 #include <selinux/selinux.h>
     17 #include <selinux/context.h>
     18 #include <selinux/android.h>
     19 #include <selinux/label.h>
     20 #include <selinux/avc.h>
     21 #include <private/android_filesystem_config.h>
     22 #include "policy.h"
     23 #include "callbacks.h"
     24 #include "selinux_internal.h"
     25 
     26 /*
     27  * XXX Where should this configuration file be located?
     28  * Needs to be accessible by zygote and installd when
     29  * setting credentials for app processes and setting permissions
     30  * on app data directories.
     31  */
     32 static char const * const seapp_contexts_file[] = {
     33 	"/data/security/current/seapp_contexts",
     34 	"/seapp_contexts",
     35 	0 };
     36 
     37 static const struct selinux_opt seopts[] = {
     38 	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
     39 	{ SELABEL_OPT_PATH, "/file_contexts" },
     40 	{ 0, NULL } };
     41 
     42 static const struct selinux_opt seopt_backup[] = {
     43 	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts_backup" },
     44 	{ SELABEL_OPT_PATH, "/file_contexts" },
     45 	{ 0, NULL } };
     46 
     47 static const char *const sepolicy_file[] = {
     48         "/data/security/current/sepolicy",
     49         "/sepolicy",
     50         0 };
     51 
     52 enum levelFrom {
     53 	LEVELFROM_NONE,
     54 	LEVELFROM_APP,
     55 	LEVELFROM_USER,
     56 	LEVELFROM_ALL
     57 };
     58 
     59 #if DEBUG
     60 static char const * const levelFromName[] = {
     61 	"none",
     62 	"app",
     63 	"user",
     64 	"all"
     65 };
     66 #endif
     67 
     68 struct seapp_context {
     69 	/* input selectors */
     70 	char isSystemServer;
     71 	char *user;
     72 	size_t len;
     73 	char prefix;
     74 	char *seinfo;
     75 	char *name;
     76 	/* outputs */
     77 	char *domain;
     78 	char *type;
     79 	char *level;
     80 	char *sebool;
     81 	enum levelFrom levelFrom;
     82 };
     83 
     84 static int seapp_context_cmp(const void *A, const void *B)
     85 {
     86 	const struct seapp_context *const *sp1 = A, *const *sp2 = B;
     87 	const struct seapp_context *s1 = *sp1, *s2 = *sp2;
     88 
     89 	/* Give precedence to isSystemServer=true. */
     90 	if (s1->isSystemServer != s2->isSystemServer)
     91 		return (s1->isSystemServer ? -1 : 1);
     92 
     93 	/* Give precedence to a specified user= over an unspecified user=. */
     94 	if (s1->user && !s2->user)
     95 		return -1;
     96 	if (!s1->user && s2->user)
     97 		return 1;
     98 
     99 	if (s1->user) {
    100 		/* Give precedence to a fixed user= string over a prefix. */
    101 		if (s1->prefix != s2->prefix)
    102 			return (s2->prefix ? -1 : 1);
    103 
    104 		/* Give precedence to a longer prefix over a shorter prefix. */
    105 		if (s1->prefix && s1->len != s2->len)
    106 			return (s1->len > s2->len) ? -1 : 1;
    107 	}
    108 
    109 	/* Give precedence to a specified seinfo= over an unspecified seinfo=. */
    110 	if (s1->seinfo && !s2->seinfo)
    111 		return -1;
    112 	if (!s1->seinfo && s2->seinfo)
    113 		return 1;
    114 
    115 	/* Give precedence to a specified name= over an unspecified name=. */
    116 	if (s1->name && !s2->name)
    117 		return -1;
    118 	if (!s1->name && s2->name)
    119 		return 1;
    120 
    121         /* Give precedence to a specified sebool= over an unspecified sebool=. */
    122         if (s1->sebool && !s2->sebool)
    123                 return -1;
    124         if (!s1->sebool && s2->sebool)
    125                 return 1;
    126 
    127 	/* Anything else has equal precedence. */
    128 	return 0;
    129 }
    130 
    131 static struct seapp_context **seapp_contexts = NULL;
    132 static int nspec = 0;
    133 
    134 int selinux_android_seapp_context_reload(void)
    135 {
    136 	FILE *fp = NULL;
    137 	char line_buf[BUFSIZ];
    138 	char *token;
    139 	unsigned lineno;
    140 	struct seapp_context *cur;
    141 	char *p, *name = NULL, *value = NULL, *saveptr;
    142 	size_t len;
    143 	int i = 0, n, ret;
    144 
    145 	while ((fp==NULL) && seapp_contexts_file[i])
    146 		fp = fopen(seapp_contexts_file[i++], "r");
    147 
    148 	if (!fp) {
    149 		selinux_log(SELINUX_ERROR, "%s:  could not open any seapp_contexts file", __FUNCTION__);
    150 		return -1;
    151 	}
    152 
    153 	if (seapp_contexts) {
    154 		for (n = 0; n < nspec; n++) {
    155 			cur = seapp_contexts[n];
    156 			free(cur->user);
    157 			free(cur->seinfo);
    158 			free(cur->name);
    159 			free(cur->domain);
    160 			free(cur->type);
    161 			free(cur->level);
    162 			free(cur->sebool);
    163 		}
    164 		free(seapp_contexts);
    165 	}
    166 
    167 	nspec = 0;
    168 	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
    169 		p = line_buf;
    170 		while (isspace(*p))
    171 			p++;
    172 		if (*p == '#' || *p == 0)
    173 			continue;
    174 		nspec++;
    175 	}
    176 
    177 	seapp_contexts = calloc(nspec, sizeof(struct seapp_context *));
    178 	if (!seapp_contexts)
    179 		goto oom;
    180 
    181 	rewind(fp);
    182 	nspec = 0;
    183 	lineno = 1;
    184 	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
    185 		len = strlen(line_buf);
    186 		if (line_buf[len - 1] == '\n')
    187 			line_buf[len - 1] = 0;
    188 		p = line_buf;
    189 		while (isspace(*p))
    190 			p++;
    191 		if (*p == '#' || *p == 0)
    192 			continue;
    193 
    194 		cur = calloc(1, sizeof(struct seapp_context));
    195 		if (!cur)
    196 			goto oom;
    197 
    198 		token = strtok_r(p, " \t", &saveptr);
    199 		if (!token)
    200 			goto err;
    201 
    202 		while (1) {
    203 			name = token;
    204 			value = strchr(name, '=');
    205 			if (!value)
    206 				goto err;
    207 			*value++ = 0;
    208 
    209 			if (!strcasecmp(name, "isSystemServer")) {
    210 				if (!strcasecmp(value, "true"))
    211 					cur->isSystemServer = 1;
    212 				else if (!strcasecmp(value, "false"))
    213 					cur->isSystemServer = 0;
    214 				else {
    215 					goto err;
    216 				}
    217 			} else if (!strcasecmp(name, "user")) {
    218 				cur->user = strdup(value);
    219 				if (!cur->user)
    220 					goto oom;
    221 				cur->len = strlen(cur->user);
    222 				if (cur->user[cur->len-1] == '*')
    223 					cur->prefix = 1;
    224 			} else if (!strcasecmp(name, "seinfo")) {
    225 				cur->seinfo = strdup(value);
    226 				if (!cur->seinfo)
    227 					goto oom;
    228 			} else if (!strcasecmp(name, "name")) {
    229 				cur->name = strdup(value);
    230 				if (!cur->name)
    231 					goto oom;
    232 			} else if (!strcasecmp(name, "domain")) {
    233 				cur->domain = strdup(value);
    234 				if (!cur->domain)
    235 					goto oom;
    236 			} else if (!strcasecmp(name, "type")) {
    237 				cur->type = strdup(value);
    238 				if (!cur->type)
    239 					goto oom;
    240 			} else if (!strcasecmp(name, "levelFromUid")) {
    241 				if (!strcasecmp(value, "true"))
    242 					cur->levelFrom = LEVELFROM_APP;
    243 				else if (!strcasecmp(value, "false"))
    244 					cur->levelFrom = LEVELFROM_NONE;
    245 				else {
    246 					goto err;
    247 				}
    248 			} else if (!strcasecmp(name, "levelFrom")) {
    249 				if (!strcasecmp(value, "none"))
    250 					cur->levelFrom = LEVELFROM_NONE;
    251 				else if (!strcasecmp(value, "app"))
    252 					cur->levelFrom = LEVELFROM_APP;
    253 				else if (!strcasecmp(value, "user"))
    254 					cur->levelFrom = LEVELFROM_USER;
    255 				else if (!strcasecmp(value, "all"))
    256 					cur->levelFrom = LEVELFROM_ALL;
    257 				else {
    258 					goto err;
    259 				}
    260 			} else if (!strcasecmp(name, "level")) {
    261 				cur->level = strdup(value);
    262 				if (!cur->level)
    263 					goto oom;
    264 			} else if (!strcasecmp(name, "sebool")) {
    265 				cur->sebool = strdup(value);
    266 				if (!cur->sebool)
    267 					goto oom;
    268 			} else
    269 				goto err;
    270 
    271 			token = strtok_r(NULL, " \t", &saveptr);
    272 			if (!token)
    273 				break;
    274 		}
    275 
    276 		seapp_contexts[nspec] = cur;
    277 		nspec++;
    278 		lineno++;
    279 	}
    280 
    281 	qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
    282 	      seapp_context_cmp);
    283 
    284 #if DEBUG
    285 	{
    286 		int i;
    287 		for (i = 0; i < nspec; i++) {
    288 			cur = seapp_contexts[i];
    289 			selinux_log(SELINUX_INFO, "%s:  isSystemServer=%s user=%s seinfo=%s name=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s",
    290 			__FUNCTION__,
    291 			cur->isSystemServer ? "true" : "false", cur->user,
    292 			cur->seinfo, cur->name, cur->sebool, cur->domain,
    293 			cur->type, cur->level,
    294 			levelFromName[cur->levelFrom]);
    295 		}
    296 	}
    297 #endif
    298 
    299 	ret = 0;
    300 
    301 out:
    302 	fclose(fp);
    303 	return ret;
    304 
    305 err:
    306 	selinux_log(SELINUX_ERROR, "%s:  Error reading %s, line %u, name %s, value %s\n",
    307 		    __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
    308 	ret = -1;
    309 	goto out;
    310 oom:
    311 	selinux_log(SELINUX_ERROR,
    312 		    "%s:  Out of memory\n", __FUNCTION__);
    313 	ret = -1;
    314 	goto out;
    315 }
    316 
    317 
    318 static void seapp_context_init(void)
    319 {
    320         selinux_android_seapp_context_reload();
    321 }
    322 
    323 static pthread_once_t once = PTHREAD_ONCE_INIT;
    324 
    325 /*
    326  * Max id that can be mapped to category set uniquely
    327  * using the current scheme.
    328  */
    329 #define CAT_MAPPING_MAX_ID (0x1<<16)
    330 
    331 enum seapp_kind {
    332 	SEAPP_TYPE,
    333 	SEAPP_DOMAIN
    334 };
    335 
    336 static int seapp_context_lookup(enum seapp_kind kind,
    337 				uid_t uid,
    338 				int isSystemServer,
    339 				const char *seinfo,
    340 				const char *pkgname,
    341 				context_t ctx)
    342 {
    343 	const char *username = NULL;
    344 	struct seapp_context *cur = NULL;
    345 	int i;
    346 	size_t n;
    347 	uid_t userid;
    348 	uid_t appid;
    349 
    350 	userid = uid / AID_USER;
    351 	appid = uid % AID_USER;
    352 	if (appid < AID_APP) {
    353 		for (n = 0; n < android_id_count; n++) {
    354 			if (android_ids[n].aid == appid) {
    355 				username = android_ids[n].name;
    356 				break;
    357 			}
    358 		}
    359 		if (!username)
    360 			goto err;
    361 	} else if (appid < AID_ISOLATED_START) {
    362 		username = "_app";
    363 		appid -= AID_APP;
    364 	} else {
    365 		username = "_isolated";
    366 		appid -= AID_ISOLATED_START;
    367 	}
    368 
    369 	if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
    370 		goto err;
    371 
    372 	for (i = 0; i < nspec; i++) {
    373 		cur = seapp_contexts[i];
    374 
    375 		if (cur->isSystemServer != isSystemServer)
    376 			continue;
    377 
    378 		if (cur->user) {
    379 			if (cur->prefix) {
    380 				if (strncasecmp(username, cur->user, cur->len-1))
    381 					continue;
    382 			} else {
    383 				if (strcasecmp(username, cur->user))
    384 					continue;
    385 			}
    386 		}
    387 
    388 		if (cur->seinfo) {
    389 			if (!seinfo || strcasecmp(seinfo, cur->seinfo))
    390 				continue;
    391 		}
    392 
    393 		if (cur->name) {
    394 			if (!pkgname || strcasecmp(pkgname, cur->name))
    395 				continue;
    396 		}
    397 
    398 		if (kind == SEAPP_TYPE && !cur->type)
    399 			continue;
    400 		else if (kind == SEAPP_DOMAIN && !cur->domain)
    401 			continue;
    402 
    403 		if (cur->sebool) {
    404 			int value = security_get_boolean_active(cur->sebool);
    405 			if (value == 0)
    406 				continue;
    407 			else if (value == -1) {
    408 				selinux_log(SELINUX_ERROR, \
    409 				"Could not find boolean: %s ", cur->sebool);
    410 				goto err;
    411 			}
    412 		}
    413 
    414 		if (kind == SEAPP_TYPE) {
    415 			if (context_type_set(ctx, cur->type))
    416 				goto oom;
    417 		} else if (kind == SEAPP_DOMAIN) {
    418 			if (context_type_set(ctx, cur->domain))
    419 				goto oom;
    420 		}
    421 
    422 		if (cur->levelFrom != LEVELFROM_NONE) {
    423 			char level[255];
    424 			switch (cur->levelFrom) {
    425 			case LEVELFROM_APP:
    426 				snprintf(level, sizeof level, "%s:c%u,c%u",
    427 					 context_range_get(ctx), appid & 0xff,
    428 					 256 + (appid>>8 & 0xff));
    429 				break;
    430 			case LEVELFROM_USER:
    431 				snprintf(level, sizeof level, "%s:c%u,c%u",
    432 					 context_range_get(ctx),
    433 					 512 + (userid & 0xff),
    434 					 768 + (userid>>8 & 0xff));
    435 				break;
    436 			case LEVELFROM_ALL:
    437 				snprintf(level, sizeof level, "%s:c%u,c%u,c%u,c%u",
    438 					 context_range_get(ctx), appid & 0xff,
    439 					 256 + (appid>>8 & 0xff),
    440 					 512 + (userid & 0xff),
    441 					 768 + (userid>>8 & 0xff));
    442 				break;
    443 			default:
    444 				goto err;
    445 			}
    446 			if (context_range_set(ctx, level))
    447 				goto oom;
    448 		} else if (cur->level) {
    449 			if (context_range_set(ctx, cur->level))
    450 				goto oom;
    451 		}
    452 
    453 		break;
    454 	}
    455 
    456 	if (kind == SEAPP_DOMAIN && i == nspec) {
    457 		/*
    458 		 * No match.
    459 		 * Fail to prevent staying in the zygote's context.
    460 		 */
    461 		selinux_log(SELINUX_ERROR,
    462 			    "%s:  No match for app with uid %d, seinfo %s, name %s\n",
    463 			    __FUNCTION__, uid, seinfo, pkgname);
    464 
    465 		if (security_getenforce() == 1)
    466 			goto err;
    467 	}
    468 
    469 	return 0;
    470 err:
    471 	return -1;
    472 oom:
    473 	return -2;
    474 }
    475 
    476 int selinux_android_setfilecon2(const char *pkgdir,
    477 				const char *pkgname,
    478 				const char *seinfo,
    479 				uid_t uid)
    480 {
    481 	char *orig_ctx_str = NULL;
    482 	char *ctx_str = NULL;
    483 	context_t ctx = NULL;
    484 	int rc = -1;
    485 
    486 	if (is_selinux_enabled() <= 0)
    487 		return 0;
    488 
    489 	__selinux_once(once, seapp_context_init);
    490 
    491 	rc = getfilecon(pkgdir, &ctx_str);
    492 	if (rc < 0)
    493 		goto err;
    494 
    495 	ctx = context_new(ctx_str);
    496 	orig_ctx_str = ctx_str;
    497 	if (!ctx)
    498 		goto oom;
    499 
    500 	rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
    501 	if (rc == -1)
    502 		goto err;
    503 	else if (rc == -2)
    504 		goto oom;
    505 
    506 	ctx_str = context_str(ctx);
    507 	if (!ctx_str)
    508 		goto oom;
    509 
    510 	rc = security_check_context(ctx_str);
    511 	if (rc < 0)
    512 		goto err;
    513 
    514 	if (strcmp(ctx_str, orig_ctx_str)) {
    515 		rc = setfilecon(pkgdir, ctx_str);
    516 		if (rc < 0)
    517 			goto err;
    518 	}
    519 
    520 	rc = 0;
    521 out:
    522 	freecon(orig_ctx_str);
    523 	context_free(ctx);
    524 	return rc;
    525 err:
    526 	selinux_log(SELINUX_ERROR, "%s:  Error setting context for pkgdir %s, uid %d: %s\n",
    527 		    __FUNCTION__, pkgdir, uid, strerror(errno));
    528 	rc = -1;
    529 	goto out;
    530 oom:
    531 	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
    532 	rc = -1;
    533 	goto out;
    534 }
    535 
    536 int selinux_android_setfilecon(const char *pkgdir,
    537 			       const char *pkgname,
    538 			       uid_t uid)
    539 {
    540 	return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
    541 }
    542 
    543 int selinux_android_setcontext(uid_t uid,
    544 			       int isSystemServer,
    545 			       const char *seinfo,
    546 			       const char *pkgname)
    547 {
    548 	char *orig_ctx_str = NULL, *ctx_str;
    549 	context_t ctx = NULL;
    550 	int rc = -1;
    551 
    552 	if (is_selinux_enabled() <= 0)
    553 		return 0;
    554 
    555 	__selinux_once(once, seapp_context_init);
    556 
    557 	rc = getcon(&ctx_str);
    558 	if (rc)
    559 		goto err;
    560 
    561 	ctx = context_new(ctx_str);
    562 	orig_ctx_str = ctx_str;
    563 	if (!ctx)
    564 		goto oom;
    565 
    566 	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
    567 	if (rc == -1)
    568 		goto err;
    569 	else if (rc == -2)
    570 		goto oom;
    571 
    572 	ctx_str = context_str(ctx);
    573 	if (!ctx_str)
    574 		goto oom;
    575 
    576 	rc = security_check_context(ctx_str);
    577 	if (rc < 0)
    578 		goto err;
    579 
    580 	if (strcmp(ctx_str, orig_ctx_str)) {
    581 		rc = setcon(ctx_str);
    582 		if (rc < 0)
    583 			goto err;
    584 	}
    585 
    586 	rc = 0;
    587 out:
    588 	freecon(orig_ctx_str);
    589 	context_free(ctx);
    590 	avc_netlink_close();
    591 	return rc;
    592 err:
    593 	if (isSystemServer)
    594 		selinux_log(SELINUX_ERROR,
    595 				"%s:  Error setting context for system server: %s\n",
    596 				__FUNCTION__, strerror(errno));
    597 	else
    598 		selinux_log(SELINUX_ERROR,
    599 				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
    600 				__FUNCTION__, uid, seinfo, strerror(errno));
    601 
    602 	rc = -1;
    603 	goto out;
    604 oom:
    605 	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
    606 	rc = -1;
    607 	goto out;
    608 }
    609 
    610 static struct selabel_handle *sehandle = NULL;
    611 
    612 static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
    613 	struct selabel_handle *h;
    614 	int i = 0;
    615 
    616 	h = NULL;
    617 	while ((h == NULL) && opts[i].value) {
    618 		h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
    619 		i++;
    620 	}
    621 
    622 	return h;
    623 }
    624 
    625 static struct selabel_handle *file_context_open(void)
    626 {
    627 	struct selabel_handle *h;
    628 
    629 	h = get_selabel_handle(seopts);
    630 
    631 	if (!h)
    632 		selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
    633 				__FUNCTION__, strerror(errno));
    634 	return h;
    635 }
    636 
    637 static struct selabel_handle *file_context_backup_open(void)
    638 {
    639 	struct selabel_handle *h;
    640 
    641 	h = get_selabel_handle(seopt_backup);
    642 
    643 	if (!h)
    644 		selinux_log(SELINUX_ERROR, "%s: Error getting backup file context handle (%s)\n",
    645 				__FUNCTION__, strerror(errno));
    646 	return h;
    647 }
    648 
    649 static void file_context_init(void)
    650 {
    651 	sehandle = file_context_open();
    652 }
    653 
    654 static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
    655 
    656 int selinux_android_restorecon(const char *pathname)
    657 {
    658 
    659 	char* oldcontext = NULL;
    660 	char* newcontext = NULL;
    661 	struct stat sb;
    662 	int ret = -1;
    663 
    664 	if (is_selinux_enabled() <= 0)
    665 		return 0;
    666 
    667 	__selinux_once(fc_once, file_context_init);
    668 
    669 	if (!sehandle)
    670 		goto bail;
    671 
    672 	if (lstat(pathname, &sb) < 0)
    673 		goto err;
    674 
    675 	if (lgetfilecon(pathname, &oldcontext) < 0)
    676 		goto err;
    677 
    678 	if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
    679 		goto err;
    680 
    681 	if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
    682 		if (lsetfilecon(pathname, newcontext) < 0)
    683 			goto err;
    684 
    685 	ret = 0;
    686 out:
    687 	if (oldcontext)
    688 		freecon(oldcontext);
    689 	if (newcontext)
    690 		freecon(newcontext);
    691 
    692 	return ret;
    693 
    694 err:
    695 	selinux_log(SELINUX_ERROR,
    696 		    "%s:  Error restoring context for %s (%s)\n",
    697 		    __FUNCTION__, pathname, strerror(errno));
    698 
    699 bail:
    700 	ret = -1;
    701 	goto out;
    702 }
    703 
    704 static int file_requires_fixup(const char *pathname,
    705 		struct selabel_handle *sehandle_old,
    706 		struct selabel_handle *sehandle_new)
    707 {
    708 	int ret;
    709 	struct stat sb;
    710 	char *current_context, *old_context, *new_context;
    711 
    712 	ret = 0;
    713 	old_context = NULL;
    714 	new_context = NULL;
    715 	current_context = NULL;
    716 
    717 	if (lstat(pathname, &sb) < 0) {
    718 		ret = -1;
    719 		goto err;
    720 	}
    721 
    722 	if (lgetfilecon(pathname, &current_context) < 0) {
    723 		ret = -1;
    724 		goto err;
    725 	}
    726 
    727 	if (selabel_lookup(sehandle_old, &old_context, pathname, sb.st_mode) < 0) {
    728 		ret = -1;
    729 		goto err;
    730 	}
    731 
    732 	if (selabel_lookup(sehandle_new, &new_context, pathname, sb.st_mode) < 0) {
    733 		ret = -1;
    734 		goto err;
    735 	}
    736 
    737 	if (strstr(current_context, "unlabeled") != NULL) {
    738 		ret = 1;
    739 		goto out;
    740 	}
    741 
    742 	ret = (strcmp(old_context, new_context) && !strcmp(current_context, old_context));
    743 	goto out;
    744 
    745 err:
    746 	selinux_log(SELINUX_ERROR,
    747 		"%s:  Error comparing context for %s (%s)\n",
    748 		__FUNCTION__,
    749 		pathname,
    750 		strerror(errno));
    751 
    752 out:
    753 	if (current_context)
    754 		freecon(current_context);
    755 	if (new_context)
    756 		freecon(new_context);
    757 	if (old_context)
    758 		freecon(old_context);
    759 	return ret;
    760 }
    761 
    762 static int fixcon_file(const char *pathname,
    763 		struct selabel_handle *sehandle_old,
    764 		struct selabel_handle *sehandle_new)
    765 {
    766 	int requires_fixup;
    767 
    768 	requires_fixup = file_requires_fixup(pathname, sehandle_old, sehandle_new);
    769 	if (requires_fixup < 0)
    770 		return -1;
    771 
    772 	if (requires_fixup)
    773 		selinux_android_restorecon(pathname);
    774 
    775 	return 0;
    776 }
    777 
    778 static int fixcon_recursive(const char *pathname,
    779 		struct selabel_handle *sehandle_old,
    780 		struct selabel_handle *sehandle_new)
    781 {
    782 	struct stat statresult;
    783 	if (lstat(pathname, &statresult) < 0)
    784 		return -1;
    785 
    786 	if (!S_ISDIR(statresult.st_mode))
    787 		return fixcon_file(pathname, sehandle_old, sehandle_new);
    788 
    789 	DIR *dir = opendir(pathname);
    790 	if (dir == NULL)
    791 		return -1;
    792 
    793 	struct dirent *entry;
    794 	while ((entry = readdir(dir)) != NULL) {
    795 		char *entryname;
    796 		if (!strcmp(entry->d_name, ".."))
    797 			continue;
    798 		if (!strcmp(entry->d_name, "."))
    799 			continue;
    800 		if (asprintf(&entryname, "%s/%s", pathname, entry->d_name) == -1)
    801 			continue;
    802 		fixcon_recursive(entryname, sehandle_old, sehandle_new);
    803 		free(entryname);
    804 	}
    805 
    806 	if (closedir(dir) < 0)
    807 		return -1;
    808 
    809 	return fixcon_file(pathname, sehandle_old, sehandle_new);
    810 }
    811 
    812 int selinux_android_fixcon(const char *pathname)
    813 {
    814 	struct selabel_handle *sehandle_old, *sehandle_new;
    815 
    816 	sehandle_old = file_context_backup_open();
    817 	if (sehandle_old == NULL)
    818 		return -1;
    819 
    820 	sehandle_new = file_context_open();
    821 	if (sehandle_new == NULL)
    822 		return -1;
    823 
    824 	return fixcon_recursive(pathname, sehandle_old, sehandle_new);
    825 }
    826 
    827 struct selabel_handle* selinux_android_file_context_handle(void)
    828 {
    829 		return file_context_open();
    830 }
    831 
    832 int selinux_android_reload_policy(void)
    833 {
    834 	int fd = -1, rc;
    835 	struct stat sb;
    836 	void *map = NULL;
    837 	int i = 0;
    838 
    839 	while (fd < 0 && sepolicy_file[i]) {
    840 		fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
    841 		i++;
    842 	}
    843 	if (fd < 0) {
    844 		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
    845 				strerror(errno));
    846 		return -1;
    847 	}
    848 	if (fstat(fd, &sb) < 0) {
    849 		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
    850 				sepolicy_file[i-1], strerror(errno));
    851 		close(fd);
    852 		return -1;
    853 	}
    854 	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    855 	if (map == MAP_FAILED) {
    856 		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
    857 			sepolicy_file[i-1], strerror(errno));
    858 		close(fd);
    859 		return -1;
    860 	}
    861 
    862 	rc = security_load_policy(map, sb.st_size);
    863 	if (rc < 0) {
    864 		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
    865 			strerror(errno));
    866 		munmap(map, sb.st_size);
    867 		close(fd);
    868 		return -1;
    869 	}
    870 
    871 	munmap(map, sb.st_size);
    872 	close(fd);
    873 	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i-1]);
    874 
    875 	return 0;
    876 }
    877 
    878 int selinux_android_load_policy(void)
    879 {
    880 	char *mnt = SELINUXMNT;
    881 	int rc;
    882 	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
    883 	if (rc < 0) {
    884 		if (errno == ENODEV) {
    885 			/* SELinux not enabled in kernel */
    886 			return -1;
    887 		}
    888 		if (errno == ENOENT) {
    889 			/* Fall back to legacy mountpoint. */
    890 			mnt = OLDSELINUXMNT;
    891 			rc = mkdir(mnt, 0755);
    892 			if (rc == -1 && errno != EEXIST) {
    893 				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
    894 					strerror(errno));
    895 				return -1;
    896 			}
    897 			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
    898 		}
    899 	}
    900 	if (rc < 0) {
    901 		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
    902 				strerror(errno));
    903 		return -1;
    904 	}
    905 	set_selinuxmnt(mnt);
    906 
    907 	return selinux_android_reload_policy();
    908 }
    909