android.c revision 0daa62c1dd9bd27f0f955f4bdebf3c537e6232eb
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 */
32static char const * const seapp_contexts_file[] = {
33	"/data/security/current/seapp_contexts",
34	"/seapp_contexts",
35	0 };
36
37static const struct selinux_opt seopts[] = {
38	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
39	{ SELABEL_OPT_PATH, "/file_contexts" },
40	{ 0, NULL } };
41
42static 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
47static const char *const sepolicy_file[] = {
48        "/data/security/current/sepolicy",
49        "/sepolicy",
50        0 };
51
52enum levelFrom {
53	LEVELFROM_NONE,
54	LEVELFROM_APP,
55	LEVELFROM_USER,
56	LEVELFROM_ALL
57};
58
59#if DEBUG
60static char const * const levelFromName[] = {
61	"none",
62	"app",
63	"user",
64	"all"
65};
66#endif
67
68struct 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
84static 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
131static struct seapp_context **seapp_contexts = NULL;
132static int nspec = 0;
133
134int 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
301out:
302	fclose(fp);
303	return ret;
304
305err:
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;
310oom:
311	selinux_log(SELINUX_ERROR,
312		    "%s:  Out of memory\n", __FUNCTION__);
313	ret = -1;
314	goto out;
315}
316
317
318static void seapp_context_init(void)
319{
320        selinux_android_seapp_context_reload();
321}
322
323static 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
331enum seapp_kind {
332	SEAPP_TYPE,
333	SEAPP_DOMAIN
334};
335
336static 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	char *end = NULL;
345	struct passwd *pw;
346	struct seapp_context *cur;
347	int i;
348	size_t n;
349	uid_t userid;
350	uid_t appid;
351
352	userid = uid / AID_USER;
353	appid = uid % AID_USER;
354	if (appid < AID_APP) {
355		for (n = 0; n < android_id_count; n++) {
356			if (android_ids[n].aid == appid) {
357				username = android_ids[n].name;
358				break;
359			}
360		}
361		if (!username)
362			goto err;
363	} else if (appid < AID_ISOLATED_START) {
364		username = "_app";
365		appid -= AID_APP;
366	} else {
367		username = "_isolated";
368		appid -= AID_ISOLATED_START;
369	}
370
371	if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
372		goto err;
373
374	for (i = 0; i < nspec; i++) {
375		cur = seapp_contexts[i];
376
377		if (cur->isSystemServer != isSystemServer)
378			continue;
379
380		if (cur->user) {
381			if (cur->prefix) {
382				if (strncasecmp(username, cur->user, cur->len-1))
383					continue;
384			} else {
385				if (strcasecmp(username, cur->user))
386					continue;
387			}
388		}
389
390		if (cur->seinfo) {
391			if (!seinfo || strcasecmp(seinfo, cur->seinfo))
392				continue;
393		}
394
395		if (cur->name) {
396			if (!pkgname || strcasecmp(pkgname, cur->name))
397				continue;
398		}
399
400		if (kind == SEAPP_TYPE && !cur->type)
401			continue;
402		else if (kind == SEAPP_DOMAIN && !cur->domain)
403			continue;
404
405		if (cur->sebool) {
406			int value = security_get_boolean_active(cur->sebool);
407			if (value == 0)
408				continue;
409			else if (value == -1) {
410				selinux_log(SELINUX_ERROR, \
411				"Could not find boolean: %s ", cur->sebool);
412				goto err;
413			}
414		}
415
416		if (kind == SEAPP_TYPE) {
417			if (context_type_set(ctx, cur->type))
418				goto oom;
419		} else if (kind == SEAPP_DOMAIN) {
420			if (context_type_set(ctx, cur->domain))
421				goto oom;
422		}
423
424		if (cur->levelFrom != LEVELFROM_NONE) {
425			char level[255];
426			switch (cur->levelFrom) {
427			case LEVELFROM_APP:
428				snprintf(level, sizeof level, "%s:c%u,c%u",
429					 context_range_get(ctx), appid & 0xff,
430					 256 + (appid>>8 & 0xff));
431				break;
432			case LEVELFROM_USER:
433				snprintf(level, sizeof level, "%s:c%u,c%u",
434					 context_range_get(ctx),
435					 512 + (userid & 0xff),
436					 768 + (userid>>8 & 0xff));
437				break;
438			case LEVELFROM_ALL:
439				snprintf(level, sizeof level, "%s:c%u,c%u,c%u,c%u",
440					 context_range_get(ctx), appid & 0xff,
441					 256 + (appid>>8 & 0xff),
442					 512 + (userid & 0xff),
443					 768 + (userid>>8 & 0xff));
444				break;
445			default:
446				goto err;
447			}
448			if (context_range_set(ctx, level))
449				goto oom;
450		} else if (cur->level) {
451			if (context_range_set(ctx, cur->level))
452				goto oom;
453		}
454
455		break;
456	}
457
458	if (kind == SEAPP_DOMAIN && i == nspec) {
459		/*
460		 * No match.
461		 * Fail to prevent staying in the zygote's context.
462		 */
463		selinux_log(SELINUX_ERROR,
464			    "%s:  No match for app with uid %d, seinfo %s, name %s\n",
465			    __FUNCTION__, uid, seinfo, pkgname);
466
467		if (security_getenforce() == 1)
468			goto err;
469	}
470
471	return 0;
472err:
473	return -1;
474oom:
475	return -2;
476}
477
478int selinux_android_setfilecon2(const char *pkgdir,
479				const char *pkgname,
480				const char *seinfo,
481				uid_t uid)
482{
483	char *orig_ctx_str = NULL, *ctx_str;
484	context_t ctx = NULL;
485	int rc;
486
487	if (is_selinux_enabled() <= 0)
488		return 0;
489
490	__selinux_once(once, seapp_context_init);
491
492	rc = getfilecon(pkgdir, &ctx_str);
493	if (rc < 0)
494		goto err;
495
496	ctx = context_new(ctx_str);
497	orig_ctx_str = ctx_str;
498	if (!ctx)
499		goto oom;
500
501	rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
502	if (rc == -1)
503		goto err;
504	else if (rc == -2)
505		goto oom;
506
507	ctx_str = context_str(ctx);
508	if (!ctx_str)
509		goto oom;
510
511	rc = security_check_context(ctx_str);
512	if (rc < 0)
513		goto err;
514
515	if (strcmp(ctx_str, orig_ctx_str)) {
516		rc = setfilecon(pkgdir, ctx_str);
517		if (rc < 0)
518			goto err;
519	}
520
521	rc = 0;
522out:
523	freecon(orig_ctx_str);
524	context_free(ctx);
525	return rc;
526err:
527	selinux_log(SELINUX_ERROR, "%s:  Error setting context for pkgdir %s, uid %d: %s\n",
528		    __FUNCTION__, pkgdir, uid, strerror(errno));
529	rc = -1;
530	goto out;
531oom:
532	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
533	rc = -1;
534	goto out;
535}
536
537int selinux_android_setfilecon(const char *pkgdir,
538			       const char *pkgname,
539			       uid_t uid)
540{
541	return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
542}
543
544int selinux_android_setcontext(uid_t uid,
545			       int isSystemServer,
546			       const char *seinfo,
547			       const char *pkgname)
548{
549	char *orig_ctx_str = NULL, *ctx_str;
550	context_t ctx = NULL;
551	int rc;
552
553	if (is_selinux_enabled() <= 0)
554		return 0;
555
556	__selinux_once(once, seapp_context_init);
557
558	rc = getcon(&ctx_str);
559	if (rc)
560		goto err;
561
562	ctx = context_new(ctx_str);
563	orig_ctx_str = ctx_str;
564	if (!ctx)
565		goto oom;
566
567	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
568	if (rc == -1)
569		goto err;
570	else if (rc == -2)
571		goto oom;
572
573	ctx_str = context_str(ctx);
574	if (!ctx_str)
575		goto oom;
576
577	rc = security_check_context(ctx_str);
578	if (rc < 0)
579		goto err;
580
581	if (strcmp(ctx_str, orig_ctx_str)) {
582		rc = setcon(ctx_str);
583		if (rc < 0)
584			goto err;
585	}
586
587	rc = 0;
588out:
589	freecon(orig_ctx_str);
590	context_free(ctx);
591	avc_netlink_close();
592	return rc;
593err:
594	if (isSystemServer)
595		selinux_log(SELINUX_ERROR,
596				"%s:  Error setting context for system server: %s\n",
597				__FUNCTION__, strerror(errno));
598	else
599		selinux_log(SELINUX_ERROR,
600				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
601				__FUNCTION__, uid, seinfo, strerror(errno));
602
603	rc = -1;
604	goto out;
605oom:
606	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
607	rc = -1;
608	goto out;
609}
610
611static struct selabel_handle *sehandle = NULL;
612
613static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
614	struct selabel_handle *h;
615	int i = 0;
616
617	h = NULL;
618	while ((h == NULL) && opts[i].value) {
619		h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
620		i++;
621	}
622
623	return h;
624}
625
626static struct selabel_handle *file_context_open(void)
627{
628	struct selabel_handle *h;
629
630	h = get_selabel_handle(seopts);
631
632	if (!h)
633		selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
634				__FUNCTION__, strerror(errno));
635	return h;
636}
637
638static struct selabel_handle *file_context_backup_open(void)
639{
640	struct selabel_handle *h;
641
642	h = get_selabel_handle(seopt_backup);
643
644	if (!h)
645		selinux_log(SELINUX_ERROR, "%s: Error getting backup file context handle (%s)\n",
646				__FUNCTION__, strerror(errno));
647	return h;
648}
649
650static void file_context_init(void)
651{
652	sehandle = file_context_open();
653}
654
655static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
656
657int selinux_android_restorecon(const char *pathname)
658{
659
660	if (is_selinux_enabled() <= 0)
661		return 0;
662
663	__selinux_once(fc_once, file_context_init);
664
665	int ret;
666
667	if (!sehandle)
668		goto bail;
669
670	struct stat sb;
671
672	if (lstat(pathname, &sb) < 0)
673		goto err;
674
675	char *oldcontext, *newcontext;
676
677	if (lgetfilecon(pathname, &oldcontext) < 0)
678		goto err;
679
680	if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
681		goto err;
682
683	if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
684		if (lsetfilecon(pathname, newcontext) < 0)
685			goto err;
686
687	ret = 0;
688out:
689	if (oldcontext)
690		freecon(oldcontext);
691	if (newcontext)
692		freecon(newcontext);
693
694	return ret;
695
696err:
697	selinux_log(SELINUX_ERROR,
698		    "%s:  Error restoring context for %s (%s)\n",
699		    __FUNCTION__, pathname, strerror(errno));
700
701bail:
702	ret = -1;
703	goto out;
704}
705
706static int file_requires_fixup(const char *pathname,
707		struct selabel_handle *sehandle_old,
708		struct selabel_handle *sehandle_new)
709{
710	int ret;
711	struct stat sb;
712	char *current_context, *old_context, *new_context;
713
714	ret = 0;
715	old_context = NULL;
716	new_context = NULL;
717	current_context = NULL;
718
719	if (lstat(pathname, &sb) < 0) {
720		ret = -1;
721		goto err;
722	}
723
724	if (lgetfilecon(pathname, &current_context) < 0) {
725		ret = -1;
726		goto err;
727	}
728
729	if (selabel_lookup(sehandle_old, &old_context, pathname, sb.st_mode) < 0) {
730		ret = -1;
731		goto err;
732	}
733
734	if (selabel_lookup(sehandle_new, &new_context, pathname, sb.st_mode) < 0) {
735		ret = -1;
736		goto err;
737	}
738
739	if (strstr(current_context, "unlabeled") != NULL) {
740		ret = 1;
741		goto out;
742	}
743
744	ret = (strcmp(old_context, new_context) && !strcmp(current_context, old_context));
745	goto out;
746
747err:
748	selinux_log(SELINUX_ERROR,
749		"%s:  Error comparing context for %s (%s)\n",
750		__FUNCTION__,
751		pathname,
752		strerror(errno));
753
754out:
755	if (current_context)
756		freecon(current_context);
757	if (new_context)
758		freecon(new_context);
759	if (old_context)
760		freecon(old_context);
761	return ret;
762}
763
764static int fixcon_file(const char *pathname,
765		struct selabel_handle *sehandle_old,
766		struct selabel_handle *sehandle_new)
767{
768	int requires_fixup;
769
770	requires_fixup = file_requires_fixup(pathname, sehandle_old, sehandle_new);
771	if (requires_fixup < 0)
772		return -1;
773
774	if (requires_fixup)
775		selinux_android_restorecon(pathname);
776
777	return 0;
778}
779
780static int fixcon_recursive(const char *pathname,
781		struct selabel_handle *sehandle_old,
782		struct selabel_handle *sehandle_new)
783{
784	struct stat statresult;
785	if (lstat(pathname, &statresult) < 0)
786		return -1;
787
788	if (!S_ISDIR(statresult.st_mode))
789		return fixcon_file(pathname, sehandle_old, sehandle_new);
790
791	DIR *dir = opendir(pathname);
792	if (dir == NULL)
793		return -1;
794
795	struct dirent *entry;
796	while ((entry = readdir(dir)) != NULL) {
797		char *entryname;
798		if (!strcmp(entry->d_name, ".."))
799			continue;
800		if (!strcmp(entry->d_name, "."))
801			continue;
802		if (asprintf(&entryname, "%s/%s", pathname, entry->d_name) == -1)
803			continue;
804		fixcon_recursive(entryname, sehandle_old, sehandle_new);
805		free(entryname);
806	}
807
808	if (closedir(dir) < 0)
809		return -1;
810
811	return fixcon_file(pathname, sehandle_old, sehandle_new);
812}
813
814int selinux_android_fixcon(const char *pathname)
815{
816	struct selabel_handle *sehandle_old, *sehandle_new;
817
818	sehandle_old = file_context_backup_open();
819	if (sehandle_old == NULL)
820		return -1;
821
822	sehandle_new = file_context_open();
823	if (sehandle_new == NULL)
824		return -1;
825
826	return fixcon_recursive(pathname, sehandle_old, sehandle_new);
827}
828
829struct selabel_handle* selinux_android_file_context_handle(void)
830{
831		return file_context_open();
832}
833
834int selinux_android_reload_policy(void)
835{
836	int fd = -1, rc;
837	struct stat sb;
838	void *map = NULL;
839	int i = 0;
840
841	while (fd < 0 && sepolicy_file[i]) {
842		fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
843		i++;
844	}
845	if (fd < 0) {
846		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
847				strerror(errno));
848		return -1;
849	}
850	if (fstat(fd, &sb) < 0) {
851		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
852				sepolicy_file[i], strerror(errno));
853		close(fd);
854		return -1;
855	}
856	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
857	if (map == MAP_FAILED) {
858		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
859			sepolicy_file[i], strerror(errno));
860		close(fd);
861		return -1;
862	}
863
864	rc = security_load_policy(map, sb.st_size);
865	if (rc < 0) {
866		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
867			strerror(errno));
868		munmap(map, sb.st_size);
869		close(fd);
870		return -1;
871	}
872
873	munmap(map, sb.st_size);
874	close(fd);
875	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i]);
876
877	return 0;
878}
879
880int selinux_android_load_policy(void)
881{
882	char *mnt = SELINUXMNT;
883	int rc;
884	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
885	if (rc < 0) {
886		if (errno == ENODEV) {
887			/* SELinux not enabled in kernel */
888			return -1;
889		}
890		if (errno == ENOENT) {
891			/* Fall back to legacy mountpoint. */
892			mnt = OLDSELINUXMNT;
893			rc = mkdir(mnt, 0755);
894			if (rc == -1 && errno != EEXIST) {
895				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
896					strerror(errno));
897				return -1;
898			}
899			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
900		}
901	}
902	if (rc < 0) {
903		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
904				strerror(errno));
905		return -1;
906	}
907	set_selinuxmnt(mnt);
908
909	return selinux_android_reload_policy();
910}
911