android.c revision 6064643a2dbfa9649894f64d9457a0b6ee103113
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/seapp_contexts",
34	"/seapp_contexts",
35	0 };
36
37static const struct selinux_opt seopts[] = {
38	{ SELABEL_OPT_PATH, "/data/security/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/file_contexts_backup" },
44	{ SELABEL_OPT_PATH, "/file_contexts" },
45	{ 0, NULL } };
46
47static const char *const sepolicy_file[] = {
48        "/data/security/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, 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
287out:
288	fclose(fp);
289	return ret;
290
291err:
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;
296oom:
297	selinux_log(SELINUX_ERROR,
298		    "%s:  Out of memory\n", __FUNCTION__);
299	ret = -1;
300	goto out;
301}
302
303
304static void seapp_context_init(void)
305{
306        selinux_android_seapp_context_reload();
307}
308
309static 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
317enum seapp_kind {
318	SEAPP_TYPE,
319	SEAPP_DOMAIN
320};
321
322static 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;
458err:
459	return -1;
460oom:
461	return -2;
462}
463
464int 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;
508out:
509	freecon(orig_ctx_str);
510	context_free(ctx);
511	return rc;
512err:
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;
517oom:
518	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
519	rc = -1;
520	goto out;
521}
522
523int 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
530int 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;
574out:
575	freecon(orig_ctx_str);
576	context_free(ctx);
577	avc_netlink_close();
578	return rc;
579err:
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;
591oom:
592	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
593	rc = -1;
594	goto out;
595}
596
597static struct selabel_handle *sehandle = NULL;
598
599static 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
612static 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
624static 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
636static void file_context_init(void)
637{
638	sehandle = file_context_open();
639}
640
641static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
642
643int 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;
674out:
675	if (oldcontext)
676		freecon(oldcontext);
677	if (newcontext)
678		freecon(newcontext);
679
680	return ret;
681
682err:
683	selinux_log(SELINUX_ERROR,
684		    "%s:  Error restoring context for %s (%s)\n",
685		    __FUNCTION__, pathname, strerror(errno));
686
687bail:
688	ret = -1;
689	goto out;
690}
691
692static 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	ret = (strcmp(old_context, new_context) && !strcmp(current_context, old_context));
726	goto out;
727
728err:
729	selinux_log(SELINUX_ERROR,
730		"%s:  Error comparing context for %s (%s)\n",
731		__FUNCTION__,
732		pathname,
733		strerror(errno));
734
735out:
736	if (current_context)
737		freecon(current_context);
738	if (new_context)
739		freecon(new_context);
740	if (old_context)
741		freecon(old_context);
742	return ret;
743}
744
745static int fixcon_file(const char *pathname,
746		struct selabel_handle *sehandle_old,
747		struct selabel_handle *sehandle_new)
748{
749	int requires_fixup;
750
751	requires_fixup = file_requires_fixup(pathname, sehandle_old, sehandle_new);
752	if (requires_fixup < 0)
753		return -1;
754
755	if (requires_fixup)
756		selinux_android_restorecon(pathname);
757
758	return 0;
759}
760
761static int fixcon_recursive(const char *pathname,
762		struct selabel_handle *sehandle_old,
763		struct selabel_handle *sehandle_new)
764{
765	struct stat statresult;
766	if (lstat(pathname, &statresult) < 0)
767		return -1;
768
769	if (!S_ISDIR(statresult.st_mode))
770		return fixcon_file(pathname, sehandle_old, sehandle_new);
771
772	DIR *dir = opendir(pathname);
773	if (dir == NULL)
774		return -1;
775
776	struct dirent *entry;
777	while ((entry = readdir(dir)) != NULL) {
778		char entryname[PATH_MAX];
779		if (!strcmp(entry->d_name, ".."))
780			continue;
781		if (!strcmp(entry->d_name, "."))
782			continue;
783		sprintf(entryname, "%s/%s", pathname, entry->d_name);
784		fixcon_recursive(entryname, sehandle_old, sehandle_new);
785	}
786
787	if (closedir(dir) < 0)
788		return -1;
789
790	return fixcon_file(pathname, sehandle_old, sehandle_new);
791}
792
793int selinux_android_fixcon(const char *pathname)
794{
795	struct selabel_handle *sehandle_old, *sehandle_new;
796
797	sehandle_old = file_context_backup_open();
798	if (sehandle_old == NULL)
799		return -1;
800
801	sehandle_new = file_context_open();
802	if (sehandle_new == NULL)
803		return -1;
804
805	return fixcon_recursive(pathname, sehandle_old, sehandle_new);
806}
807
808struct selabel_handle* selinux_android_file_context_handle(void)
809{
810		return file_context_open();
811}
812
813int selinux_android_reload_policy(void)
814{
815	char path[PATH_MAX];
816	int fd = -1, rc;
817	struct stat sb;
818	void *map = NULL;
819	int i = 0;
820
821	while (fd < 0 && sepolicy_file[i]) {
822		snprintf(path, sizeof(path), "%s",
823			sepolicy_file[i]);
824		fd = open(path, O_RDONLY);
825		i++;
826	}
827	if (fd < 0) {
828		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
829				strerror(errno));
830		return -1;
831	}
832	if (fstat(fd, &sb) < 0) {
833		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
834				path, strerror(errno));
835		close(fd);
836		return -1;
837	}
838	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
839	if (map == MAP_FAILED) {
840		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
841			path, strerror(errno));
842		close(fd);
843		return -1;
844	}
845
846	rc = security_load_policy(map, sb.st_size);
847	if (rc < 0) {
848		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
849			strerror(errno));
850		munmap(map, sb.st_size);
851		close(fd);
852		return -1;
853	}
854
855	munmap(map, sb.st_size);
856	close(fd);
857	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", path);
858
859	return 0;
860}
861
862int selinux_android_load_policy(void)
863{
864	char *mnt = SELINUXMNT;
865	int rc;
866	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
867	if (rc < 0) {
868		if (errno == ENODEV) {
869			/* SELinux not enabled in kernel */
870			return -1;
871		}
872		if (errno == ENOENT) {
873			/* Fall back to legacy mountpoint. */
874			mnt = OLDSELINUXMNT;
875			rc = mkdir(mnt, 0755);
876			if (rc == -1 && errno != EEXIST) {
877				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
878					strerror(errno));
879				return -1;
880			}
881			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
882		}
883	}
884	if (rc < 0) {
885		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
886				strerror(errno));
887		return -1;
888	}
889	set_selinuxmnt(mnt);
890
891	return selinux_android_reload_policy();
892}
893