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