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