• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
seapp_context_cmp(const void * A,const void * B)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 
selinux_android_seapp_context_reload(void)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 
seapp_context_init(void)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 
seapp_context_lookup(enum seapp_kind kind,uid_t uid,int isSystemServer,const char * seinfo,const char * pkgname,context_t ctx)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 
selinux_android_setfilecon2(const char * pkgdir,const char * pkgname,const char * seinfo,uid_t uid)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 
selinux_android_setfilecon(const char * pkgdir,const char * pkgname,uid_t uid)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 
selinux_android_setcontext(uid_t uid,int isSystemServer,const char * seinfo,const char * pkgname)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 
get_selabel_handle(const struct selinux_opt opts[])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 
file_context_open(void)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 
file_context_backup_open(void)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 
file_context_init(void)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 
selinux_android_restorecon(const char * pathname)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 
file_requires_fixup(const char * pathname,struct selabel_handle * sehandle_old,struct selabel_handle * sehandle_new)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 
fixcon_file(const char * pathname,struct selabel_handle * sehandle_old,struct selabel_handle * sehandle_new)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 
fixcon_recursive(const char * pathname,struct selabel_handle * sehandle_old,struct selabel_handle * sehandle_new)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 
selinux_android_fixcon(const char * pathname)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 
selinux_android_file_context_handle(void)815 struct selabel_handle* selinux_android_file_context_handle(void)
816 {
817 		return file_context_open();
818 }
819 
selinux_android_reload_policy(void)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 
selinux_android_load_policy(void)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