1#include <sys/types.h>
2#include <unistd.h>
3#include <string.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdbool.h>
7#include <ctype.h>
8#include <errno.h>
9#include <pwd.h>
10#include <grp.h>
11#include <sys/mman.h>
12#include <sys/mount.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <sys/xattr.h>
16#include <fcntl.h>
17#include <fts.h>
18#include <selinux/selinux.h>
19#include <selinux/context.h>
20#include <selinux/android.h>
21#include <selinux/label.h>
22#include <selinux/avc.h>
23#include <openssl/sha.h>
24#include <private/android_filesystem_config.h>
25#include <log/log.h>
26#include "policy.h"
27#include "callbacks.h"
28#include "selinux_internal.h"
29#include "label_internal.h"
30#include <fnmatch.h>
31#include <limits.h>
32#include <sys/vfs.h>
33#include <linux/magic.h>
34#include <libgen.h>
35#include <packagelistparser/packagelistparser.h>
36
37#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
38#include <sys/_system_properties.h>
39
40/*
41 * XXX Where should this configuration file be located?
42 * Needs to be accessible by zygote and installd when
43 * setting credentials for app processes and setting permissions
44 * on app data directories.
45 */
46static char const * const seapp_contexts_file[] = {
47	"/seapp_contexts",
48	"/data/security/current/seapp_contexts",
49	NULL };
50
51static const struct selinux_opt seopts[] = {
52	{ SELABEL_OPT_PATH, "/file_contexts.bin" },
53	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts.bin" },
54	{ 0, NULL } };
55
56static const char *const sepolicy_file[] = {
57	"/sepolicy",
58	"/data/security/current/sepolicy",
59	NULL };
60
61static const struct selinux_opt seopts_prop[] = {
62        { SELABEL_OPT_PATH, "/property_contexts" },
63        { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
64        { 0, NULL }
65};
66
67static const struct selinux_opt seopts_service[] = {
68    { SELABEL_OPT_PATH, "/service_contexts" },
69    { SELABEL_OPT_PATH, "/data/security/current/service_contexts" },
70    { 0, NULL }
71};
72
73enum levelFrom {
74	LEVELFROM_NONE,
75	LEVELFROM_APP,
76	LEVELFROM_USER,
77	LEVELFROM_ALL
78};
79
80#define POLICY_OVERRIDE_VERSION    "/data/security/current/selinux_version"
81#define POLICY_BASE_VERSION        "/selinux_version"
82static int policy_index = 0;
83
84static void set_policy_index(void)
85{
86	int fd_base = -1, fd_override = -1;
87	struct stat sb_base;
88	struct stat sb_override;
89	void *map_base, *map_override;
90
91	policy_index = 0;
92
93	fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW);
94	if (fd_base < 0)
95		return;
96
97	if (fstat(fd_base, &sb_base) < 0)
98		goto close_base;
99
100	fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW);
101	if (fd_override < 0)
102		goto close_base;
103
104	if (fstat(fd_override, &sb_override) < 0)
105		goto close_override;
106
107	if (sb_base.st_size != sb_override.st_size)
108		goto close_override;
109
110	map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0);
111	if (map_base == MAP_FAILED)
112		goto close_override;
113
114	map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0);
115	if (map_override == MAP_FAILED)
116		goto unmap_base;
117
118	if (memcmp(map_base, map_override, sb_base.st_size) != 0)
119		goto unmap_override;
120
121	if (access(sepolicy_file[1], R_OK) != 0)
122		goto unmap_override;
123
124	if (access(seopts[1].value, R_OK) != 0)
125		goto unmap_override;
126
127	if (access(seopts_prop[1].value, R_OK) != 0)
128		goto unmap_override;
129
130	if (access(seopts_service[1].value, R_OK) != 0)
131		goto unmap_override;
132
133	if (access(seapp_contexts_file[1], R_OK) != 0)
134		goto unmap_override;
135
136	policy_index = 1;
137
138unmap_override:
139	munmap(map_override, sb_override.st_size);
140unmap_base:
141	munmap(map_base, sb_base.st_size);
142close_override:
143	close(fd_override);
144close_base:
145	close(fd_base);
146	return;
147}
148
149#if DEBUG
150static char const * const levelFromName[] = {
151	"none",
152	"app",
153	"user",
154	"all"
155};
156#endif
157
158struct prefix_str {
159	size_t len;
160	char *str;
161	char is_prefix;
162};
163
164static void free_prefix_str(struct prefix_str *p)
165{
166	if (!p)
167		return;
168	free(p->str);
169}
170
171struct seapp_context {
172	/* input selectors */
173	bool isSystemServer;
174	bool isAutoPlayAppSet;
175	bool isAutoPlayApp;
176	bool isOwnerSet;
177	bool isOwner;
178	struct prefix_str user;
179	char *seinfo;
180	struct prefix_str name;
181	struct prefix_str path;
182	bool isPrivAppSet;
183	bool isPrivApp;
184	/* outputs */
185	char *domain;
186	char *type;
187	char *level;
188	enum levelFrom levelFrom;
189};
190
191static void free_seapp_context(struct seapp_context *s)
192{
193	if (!s)
194		return;
195
196	free_prefix_str(&s->user);
197	free(s->seinfo);
198	free_prefix_str(&s->name);
199	free_prefix_str(&s->path);
200	free(s->domain);
201	free(s->type);
202	free(s->level);
203}
204
205static bool seapp_contexts_dup = false;
206
207static int seapp_context_cmp(const void *A, const void *B)
208{
209	const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
210	const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
211	const struct seapp_context *s1 = *sp1, *s2 = *sp2;
212	bool dup;
213
214	/* Give precedence to isSystemServer=true. */
215	if (s1->isSystemServer != s2->isSystemServer)
216		return (s1->isSystemServer ? -1 : 1);
217
218	/* Give precedence to a specified isAutoPlayApp= over an
219	 * unspecified isAutoPlayApp=. */
220	if (s1->isAutoPlayAppSet != s2->isAutoPlayAppSet)
221		return (s1->isAutoPlayAppSet ? -1 : 1);
222
223
224	/* Give precedence to a specified isOwner= over an unspecified isOwner=. */
225	if (s1->isOwnerSet != s2->isOwnerSet)
226		return (s1->isOwnerSet ? -1 : 1);
227
228	/* Give precedence to a specified user= over an unspecified user=. */
229	if (s1->user.str && !s2->user.str)
230		return -1;
231	if (!s1->user.str && s2->user.str)
232		return 1;
233
234	if (s1->user.str) {
235		/* Give precedence to a fixed user= string over a prefix. */
236		if (s1->user.is_prefix != s2->user.is_prefix)
237			return (s2->user.is_prefix ? -1 : 1);
238
239		/* Give precedence to a longer prefix over a shorter prefix. */
240		if (s1->user.is_prefix && s1->user.len != s2->user.len)
241			return (s1->user.len > s2->user.len) ? -1 : 1;
242	}
243
244	/* Give precedence to a specified seinfo= over an unspecified seinfo=. */
245	if (s1->seinfo && !s2->seinfo)
246		return -1;
247	if (!s1->seinfo && s2->seinfo)
248		return 1;
249
250	/* Give precedence to a specified name= over an unspecified name=. */
251	if (s1->name.str && !s2->name.str)
252		return -1;
253	if (!s1->name.str && s2->name.str)
254		return 1;
255
256	if (s1->name.str) {
257		/* Give precedence to a fixed name= string over a prefix. */
258		if (s1->name.is_prefix != s2->name.is_prefix)
259			return (s2->name.is_prefix ? -1 : 1);
260
261		/* Give precedence to a longer prefix over a shorter prefix. */
262		if (s1->name.is_prefix && s1->name.len != s2->name.len)
263			return (s1->name.len > s2->name.len) ? -1 : 1;
264	}
265
266	/* Give precedence to a specified path= over an unspecified path=. */
267	if (s1->path.str && !s2->path.str)
268		return -1;
269	if (!s1->path.str && s2->path.str)
270		return 1;
271
272	if (s1->path.str) {
273		/* Give precedence to a fixed path= string over a prefix. */
274		if (s1->path.is_prefix != s2->path.is_prefix)
275			return (s2->path.is_prefix ? -1 : 1);
276
277		/* Give precedence to a longer prefix over a shorter prefix. */
278		if (s1->path.is_prefix && s1->path.len != s2->path.len)
279			return (s1->path.len > s2->path.len) ? -1 : 1;
280	}
281
282	/* Give precedence to a specified isPrivApp= over an unspecified isPrivApp=. */
283	if (s1->isPrivAppSet != s2->isPrivAppSet)
284		return (s1->isPrivAppSet ? -1 : 1);
285
286	/*
287	 * Check for a duplicated entry on the input selectors.
288	 * We already compared isSystemServer, isOwnerSet, and isOwner above.
289	 * We also have already checked that both entries specify the same
290	 * string fields, so if s1 has a non-NULL string, then so does s2.
291	 */
292	dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) &&
293		(!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) &&
294		(!s1->name.str || !strcmp(s1->name.str, s2->name.str)) &&
295		(!s1->path.str || !strcmp(s1->path.str, s2->path.str));
296	if (dup) {
297		seapp_contexts_dup = true;
298		selinux_log(SELINUX_ERROR, "seapp_contexts:  Duplicated entry\n");
299		if (s1->user.str)
300			selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str);
301		if (s1->seinfo)
302			selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo);
303		if (s1->name.str)
304			selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str);
305		if (s1->path.str)
306			selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str);
307	}
308
309	/* Anything else has equal precedence. */
310	return 0;
311}
312
313static struct seapp_context **seapp_contexts = NULL;
314static int nspec = 0;
315
316static void free_seapp_contexts(void)
317{
318	int n;
319
320	if (!seapp_contexts)
321		return;
322
323	for (n = 0; n < nspec; n++)
324		free_seapp_context(seapp_contexts[n]);
325
326	free(seapp_contexts);
327	seapp_contexts = NULL;
328	nspec = 0;
329}
330
331int selinux_android_seapp_context_reload(void)
332{
333	FILE *fp = NULL;
334	char line_buf[BUFSIZ];
335	char *token;
336	unsigned lineno;
337	struct seapp_context *cur;
338	char *p, *name = NULL, *value = NULL, *saveptr;
339	size_t len;
340	int n, ret;
341
342	set_policy_index();
343
344	fp = fopen(seapp_contexts_file[policy_index], "r");
345	if (!fp) {
346		selinux_log(SELINUX_ERROR, "%s:  could not open any seapp_contexts file", __FUNCTION__);
347		return -1;
348	}
349
350	free_seapp_contexts();
351
352	nspec = 0;
353	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
354		p = line_buf;
355		while (isspace(*p))
356			p++;
357		if (*p == '#' || *p == 0)
358			continue;
359		nspec++;
360	}
361
362	seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
363	if (!seapp_contexts)
364		goto oom;
365
366	rewind(fp);
367	nspec = 0;
368	lineno = 1;
369	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
370		len = strlen(line_buf);
371		if (line_buf[len - 1] == '\n')
372			line_buf[len - 1] = 0;
373		p = line_buf;
374		while (isspace(*p))
375			p++;
376		if (*p == '#' || *p == 0)
377			continue;
378
379		cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
380		if (!cur)
381			goto oom;
382
383		token = strtok_r(p, " \t", &saveptr);
384		if (!token) {
385			free_seapp_context(cur);
386			goto err;
387		}
388
389		while (1) {
390			name = token;
391			value = strchr(name, '=');
392			if (!value) {
393				free_seapp_context(cur);
394				goto err;
395			}
396			*value++ = 0;
397
398			if (!strcasecmp(name, "isSystemServer")) {
399				if (!strcasecmp(value, "true"))
400					cur->isSystemServer = true;
401				else if (!strcasecmp(value, "false"))
402					cur->isSystemServer = false;
403				else {
404					free_seapp_context(cur);
405					goto err;
406				}
407			} else if (!strcasecmp(name, "isAutoPlayApp")) {
408				cur->isAutoPlayAppSet = true;
409				if (!strcasecmp(value, "true"))
410					cur->isAutoPlayApp = true;
411				else if (!strcasecmp(value, "false"))
412					cur->isAutoPlayApp = false;
413				else {
414					free_seapp_context(cur);
415					goto err;
416				}
417			} else if (!strcasecmp(name, "isOwner")) {
418				cur->isOwnerSet = true;
419				if (!strcasecmp(value, "true"))
420					cur->isOwner = true;
421				else if (!strcasecmp(value, "false"))
422					cur->isOwner = false;
423				else {
424					free_seapp_context(cur);
425					goto err;
426				}
427			} else if (!strcasecmp(name, "user")) {
428				if (cur->user.str) {
429					free_seapp_context(cur);
430					goto err;
431				}
432				cur->user.str = strdup(value);
433				if (!cur->user.str) {
434					free_seapp_context(cur);
435					goto oom;
436				}
437				cur->user.len = strlen(cur->user.str);
438				if (cur->user.str[cur->user.len-1] == '*')
439					cur->user.is_prefix = 1;
440			} else if (!strcasecmp(name, "seinfo")) {
441				if (cur->seinfo) {
442					free_seapp_context(cur);
443					goto err;
444				}
445				cur->seinfo = strdup(value);
446				if (!cur->seinfo) {
447					free_seapp_context(cur);
448					goto oom;
449				}
450				if (strstr(value, ":")) {
451					free_seapp_context(cur);
452					goto err;
453				}
454			} else if (!strcasecmp(name, "name")) {
455				if (cur->name.str) {
456					free_seapp_context(cur);
457					goto err;
458				}
459				cur->name.str = strdup(value);
460				if (!cur->name.str) {
461					free_seapp_context(cur);
462					goto oom;
463				}
464				cur->name.len = strlen(cur->name.str);
465				if (cur->name.str[cur->name.len-1] == '*')
466					cur->name.is_prefix = 1;
467			} else if (!strcasecmp(name, "domain")) {
468				if (cur->domain) {
469					free_seapp_context(cur);
470					goto err;
471				}
472				cur->domain = strdup(value);
473				if (!cur->domain) {
474					free_seapp_context(cur);
475					goto oom;
476				}
477			} else if (!strcasecmp(name, "type")) {
478				if (cur->type) {
479					free_seapp_context(cur);
480					goto err;
481				}
482				cur->type = strdup(value);
483				if (!cur->type) {
484					free_seapp_context(cur);
485					goto oom;
486				}
487			} else if (!strcasecmp(name, "levelFromUid")) {
488				if (cur->levelFrom) {
489					free_seapp_context(cur);
490					goto err;
491				}
492				if (!strcasecmp(value, "true"))
493					cur->levelFrom = LEVELFROM_APP;
494				else if (!strcasecmp(value, "false"))
495					cur->levelFrom = LEVELFROM_NONE;
496				else {
497					free_seapp_context(cur);
498					goto err;
499				}
500			} else if (!strcasecmp(name, "levelFrom")) {
501				if (cur->levelFrom) {
502					free_seapp_context(cur);
503					goto err;
504				}
505				if (!strcasecmp(value, "none"))
506					cur->levelFrom = LEVELFROM_NONE;
507				else if (!strcasecmp(value, "app"))
508					cur->levelFrom = LEVELFROM_APP;
509				else if (!strcasecmp(value, "user"))
510					cur->levelFrom = LEVELFROM_USER;
511				else if (!strcasecmp(value, "all"))
512					cur->levelFrom = LEVELFROM_ALL;
513				else {
514					free_seapp_context(cur);
515					goto err;
516				}
517			} else if (!strcasecmp(name, "level")) {
518				if (cur->level) {
519					free_seapp_context(cur);
520					goto err;
521				}
522				cur->level = strdup(value);
523				if (!cur->level) {
524					free_seapp_context(cur);
525					goto oom;
526				}
527			} else if (!strcasecmp(name, "path")) {
528				if (cur->path.str) {
529					free_seapp_context(cur);
530					goto err;
531				}
532				cur->path.str = strdup(value);
533				if (!cur->path.str) {
534					free_seapp_context(cur);
535					goto oom;
536				}
537				cur->path.len = strlen(cur->path.str);
538				if (cur->path.str[cur->path.len-1] == '*')
539					cur->path.is_prefix = 1;
540			} else if (!strcasecmp(name, "isPrivApp")) {
541				cur->isPrivAppSet = true;
542				if (!strcasecmp(value, "true"))
543					cur->isPrivApp = true;
544				else if (!strcasecmp(value, "false"))
545					cur->isPrivApp = false;
546				else {
547					free_seapp_context(cur);
548					goto err;
549				}
550			} else {
551				free_seapp_context(cur);
552				goto err;
553			}
554
555			token = strtok_r(NULL, " \t", &saveptr);
556			if (!token)
557				break;
558		}
559
560		if (cur->name.str &&
561		    (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
562			selinux_log(SELINUX_ERROR, "%s:  No specific seinfo value specified with name=\"%s\", on line %u:  insecure configuration!\n",
563				    seapp_contexts_file[policy_index], cur->name.str, lineno);
564			free_seapp_context(cur);
565			goto err;
566		}
567
568		seapp_contexts[nspec] = cur;
569		nspec++;
570		lineno++;
571	}
572
573	qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
574	      seapp_context_cmp);
575
576	if (seapp_contexts_dup)
577		goto err;
578
579#if DEBUG
580	{
581		int i;
582		for (i = 0; i < nspec; i++) {
583			cur = seapp_contexts[i];
584			selinux_log(SELINUX_INFO, "%s:  isSystemServer=%s  isAutoPlayApp=%s isOwner=%s user=%s seinfo=%s "
585					"name=%s path=%s isPrivApp=%s -> domain=%s type=%s level=%s levelFrom=%s",
586				__FUNCTION__,
587				cur->isSystemServer ? "true" : "false",
588				cur->isAutoPlayAppSet ? (cur->isAutoPlayApp ? "true" : "false") : "null",
589				cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null",
590				cur->user.str,
591				cur->seinfo, cur->name.str, cur->path.str,
592				cur->isPrivAppSet ? (cur->isPrivApp ? "true" : "false") : "null",
593				cur->domain, cur->type, cur->level,
594				levelFromName[cur->levelFrom]);
595		}
596	}
597#endif
598
599	ret = 0;
600
601out:
602	fclose(fp);
603	return ret;
604
605err:
606	selinux_log(SELINUX_ERROR, "%s:  Invalid entry on line %u\n",
607		    seapp_contexts_file[policy_index], lineno);
608	free_seapp_contexts();
609	ret = -1;
610	goto out;
611oom:
612	selinux_log(SELINUX_ERROR,
613		    "%s:  Out of memory\n", __FUNCTION__);
614	free_seapp_contexts();
615	ret = -1;
616	goto out;
617}
618
619
620static void seapp_context_init(void)
621{
622        selinux_android_seapp_context_reload();
623}
624
625static pthread_once_t once = PTHREAD_ONCE_INIT;
626
627/*
628 * Max id that can be mapped to category set uniquely
629 * using the current scheme.
630 */
631#define CAT_MAPPING_MAX_ID (0x1<<16)
632
633enum seapp_kind {
634	SEAPP_TYPE,
635	SEAPP_DOMAIN
636};
637
638#define PRIVILEGED_APP_STR ":privapp"
639#define AUTOPLAY_APP_STR ":autoplayapp"
640
641static int seinfo_parse(char *dest, const char *src, size_t size)
642{
643	size_t len;
644	char *p;
645
646	if ((p = strchr(src, ':')) != NULL)
647		len = p - src;
648	else
649		len = strlen(src);
650
651	if (len > size - 1)
652		return -1;
653
654	strncpy(dest, src, len);
655	dest[len] = '\0';
656
657	return 0;
658}
659
660static int seapp_context_lookup(enum seapp_kind kind,
661				uid_t uid,
662				bool isSystemServer,
663				const char *seinfo,
664				const char *pkgname,
665				const char *path,
666				context_t ctx)
667{
668	bool isOwner;
669	const char *username = NULL;
670	struct seapp_context *cur = NULL;
671	int i;
672	size_t n;
673	uid_t userid;
674	uid_t appid;
675	bool isPrivApp = false;
676	bool isAutoPlayApp = false;
677	char parsedseinfo[BUFSIZ];
678
679	__selinux_once(once, seapp_context_init);
680
681	if (seinfo) {
682		if (seinfo_parse(parsedseinfo, seinfo, BUFSIZ))
683			goto err;
684		isPrivApp = strstr(seinfo, PRIVILEGED_APP_STR) ? true : false;
685		isAutoPlayApp = strstr(seinfo, AUTOPLAY_APP_STR) ? true : false;
686		seinfo = parsedseinfo;
687	}
688
689	userid = uid / AID_USER;
690	isOwner = (userid == 0);
691	appid = uid % AID_USER;
692	if (appid < AID_APP) {
693		for (n = 0; n < android_id_count; n++) {
694			if (android_ids[n].aid == appid) {
695				username = android_ids[n].name;
696				break;
697			}
698		}
699		if (!username)
700			goto err;
701	} else if (appid < AID_ISOLATED_START) {
702		username = "_app";
703		appid -= AID_APP;
704	} else {
705		username = "_isolated";
706		appid -= AID_ISOLATED_START;
707	}
708
709	if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
710		goto err;
711
712	for (i = 0; i < nspec; i++) {
713		cur = seapp_contexts[i];
714
715		if (cur->isSystemServer != isSystemServer)
716			continue;
717
718		if (cur->isAutoPlayAppSet && cur->isAutoPlayApp != isAutoPlayApp)
719			continue;
720
721		if (cur->isOwnerSet && cur->isOwner != isOwner)
722			continue;
723
724		if (cur->user.str) {
725			if (cur->user.is_prefix) {
726				if (strncasecmp(username, cur->user.str, cur->user.len-1))
727					continue;
728			} else {
729				if (strcasecmp(username, cur->user.str))
730					continue;
731			}
732		}
733
734		if (cur->seinfo) {
735			if (!seinfo || strcasecmp(seinfo, cur->seinfo))
736				continue;
737		}
738
739		if (cur->name.str) {
740			if(!pkgname)
741				continue;
742
743			if (cur->name.is_prefix) {
744				if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
745					continue;
746			} else {
747				if (strcasecmp(pkgname, cur->name.str))
748					continue;
749			}
750		}
751
752		if (cur->isPrivAppSet && cur->isPrivApp != isPrivApp)
753			continue;
754
755		if (cur->path.str) {
756			if (!path)
757				continue;
758
759			if (cur->path.is_prefix) {
760				if (strncmp(path, cur->path.str, cur->path.len-1))
761					continue;
762			} else {
763				if (strcmp(path, cur->path.str))
764					continue;
765			}
766		}
767
768		if (kind == SEAPP_TYPE && !cur->type)
769			continue;
770		else if (kind == SEAPP_DOMAIN && !cur->domain)
771			continue;
772
773		if (kind == SEAPP_TYPE) {
774			if (context_type_set(ctx, cur->type))
775				goto oom;
776		} else if (kind == SEAPP_DOMAIN) {
777			if (context_type_set(ctx, cur->domain))
778				goto oom;
779		}
780
781		if (cur->levelFrom != LEVELFROM_NONE) {
782			char level[255];
783			switch (cur->levelFrom) {
784			case LEVELFROM_APP:
785				snprintf(level, sizeof level, "s0:c%u,c%u",
786					 appid & 0xff,
787					 256 + (appid>>8 & 0xff));
788				break;
789			case LEVELFROM_USER:
790				snprintf(level, sizeof level, "s0:c%u,c%u",
791					 512 + (userid & 0xff),
792					 768 + (userid>>8 & 0xff));
793				break;
794			case LEVELFROM_ALL:
795				snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
796					 appid & 0xff,
797					 256 + (appid>>8 & 0xff),
798					 512 + (userid & 0xff),
799					 768 + (userid>>8 & 0xff));
800				break;
801			default:
802				goto err;
803			}
804			if (context_range_set(ctx, level))
805				goto oom;
806		} else if (cur->level) {
807			if (context_range_set(ctx, cur->level))
808				goto oom;
809		}
810
811		break;
812	}
813
814	if (kind == SEAPP_DOMAIN && i == nspec) {
815		/*
816		 * No match.
817		 * Fail to prevent staying in the zygote's context.
818		 */
819		selinux_log(SELINUX_ERROR,
820			    "%s:  No match for app with uid %d, seinfo %s, name %s\n",
821			    __FUNCTION__, uid, seinfo, pkgname);
822
823		if (security_getenforce() == 1)
824			goto err;
825	}
826
827	return 0;
828err:
829	return -1;
830oom:
831	return -2;
832}
833
834int selinux_android_setfilecon(const char *pkgdir,
835				const char *pkgname,
836				const char *seinfo,
837				uid_t uid)
838{
839	char *orig_ctx_str = NULL;
840	char *ctx_str = NULL;
841	context_t ctx = NULL;
842	int rc = -1;
843
844	if (is_selinux_enabled() <= 0)
845		return 0;
846
847	rc = getfilecon(pkgdir, &ctx_str);
848	if (rc < 0)
849		goto err;
850
851	ctx = context_new(ctx_str);
852	orig_ctx_str = ctx_str;
853	if (!ctx)
854		goto oom;
855
856	rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
857	if (rc == -1)
858		goto err;
859	else if (rc == -2)
860		goto oom;
861
862	ctx_str = context_str(ctx);
863	if (!ctx_str)
864		goto oom;
865
866	rc = security_check_context(ctx_str);
867	if (rc < 0)
868		goto err;
869
870	if (strcmp(ctx_str, orig_ctx_str)) {
871		rc = setfilecon(pkgdir, ctx_str);
872		if (rc < 0)
873			goto err;
874	}
875
876	rc = 0;
877out:
878	freecon(orig_ctx_str);
879	context_free(ctx);
880	return rc;
881err:
882	selinux_log(SELINUX_ERROR, "%s:  Error setting context for pkgdir %s, uid %d: %s\n",
883		    __FUNCTION__, pkgdir, uid, strerror(errno));
884	rc = -1;
885	goto out;
886oom:
887	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
888	rc = -1;
889	goto out;
890}
891
892int selinux_android_setcon(const char *con)
893{
894	int ret = setcon(con);
895	if (ret)
896		return ret;
897	/*
898	  System properties must be reinitialized after setcon() otherwise the
899	  previous property files will be leaked since mmap()'ed regions are not
900	  closed as a result of setcon().
901	*/
902	return __system_properties_init();
903}
904
905int selinux_android_setcontext(uid_t uid,
906			       bool isSystemServer,
907			       const char *seinfo,
908			       const char *pkgname)
909{
910	char *orig_ctx_str = NULL, *ctx_str;
911	context_t ctx = NULL;
912	int rc = -1;
913
914	if (is_selinux_enabled() <= 0)
915		return 0;
916
917	rc = getcon(&ctx_str);
918	if (rc)
919		goto err;
920
921	ctx = context_new(ctx_str);
922	orig_ctx_str = ctx_str;
923	if (!ctx)
924		goto oom;
925
926	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
927	if (rc == -1)
928		goto err;
929	else if (rc == -2)
930		goto oom;
931
932	ctx_str = context_str(ctx);
933	if (!ctx_str)
934		goto oom;
935
936	rc = security_check_context(ctx_str);
937	if (rc < 0)
938		goto err;
939
940	if (strcmp(ctx_str, orig_ctx_str)) {
941		rc = selinux_android_setcon(ctx_str);
942		if (rc < 0)
943			goto err;
944	}
945
946	rc = 0;
947out:
948	freecon(orig_ctx_str);
949	context_free(ctx);
950	avc_netlink_close();
951	return rc;
952err:
953	if (isSystemServer)
954		selinux_log(SELINUX_ERROR,
955				"%s:  Error setting context for system server: %s\n",
956				__FUNCTION__, strerror(errno));
957	else
958		selinux_log(SELINUX_ERROR,
959				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
960				__FUNCTION__, uid, seinfo, strerror(errno));
961
962	rc = -1;
963	goto out;
964oom:
965	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
966	rc = -1;
967	goto out;
968}
969
970static struct selabel_handle *fc_sehandle = NULL;
971#define FC_DIGEST_SIZE SHA_DIGEST_LENGTH
972static uint8_t fc_digest[FC_DIGEST_SIZE];
973
974static bool compute_contexts_hash(const struct selinux_opt opts[], uint8_t c_digest[])
975{
976    int fd;
977    struct stat sb;
978    void *map;
979
980    fd = open(opts[policy_index].value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW);
981    if (fd < 0) {
982        selinux_log(SELINUX_ERROR, "SELinux:  Could not open %s:  %s\n",
983                    opts[policy_index].value, strerror(errno));
984        return false;
985    }
986    if (fstat(fd, &sb) < 0) {
987        selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
988                    opts[policy_index].value, strerror(errno));
989        close(fd);
990        return false;
991    }
992    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
993    if (map == MAP_FAILED) {
994        selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
995                    opts[policy_index].value, strerror(errno));
996        close(fd);
997        return false;
998    }
999    SHA1(map, sb.st_size, c_digest);
1000    munmap(map, sb.st_size);
1001    close(fd);
1002
1003    return true;
1004}
1005
1006static void file_context_init(void)
1007{
1008    if (!fc_sehandle)
1009        fc_sehandle = selinux_android_file_context_handle();
1010}
1011
1012
1013
1014static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
1015
1016#define PKGTAB_SIZE 256
1017static struct pkg_info *pkgTab[PKGTAB_SIZE];
1018
1019static unsigned int pkghash(const char *pkgname)
1020{
1021    unsigned int h = 7;
1022    for (; *pkgname; pkgname++) {
1023        h = h * 31 + *pkgname;
1024    }
1025    return h & (PKGTAB_SIZE - 1);
1026}
1027
1028static bool pkg_parse_callback(pkg_info *info, void *userdata) {
1029
1030    (void) userdata;
1031
1032    unsigned int hash = pkghash(info->name);
1033    if (pkgTab[hash])
1034        info->private_data = pkgTab[hash];
1035    pkgTab[hash] = info;
1036    return true;
1037}
1038
1039static void package_info_init(void)
1040{
1041
1042    bool rc = packagelist_parse(pkg_parse_callback, NULL);
1043    if (!rc) {
1044        selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n");
1045        return;
1046    }
1047
1048#if DEBUG
1049    {
1050        unsigned int hash, buckets, entries, chainlen, longestchain;
1051        struct pkg_info *info = NULL;
1052
1053        buckets = entries = longestchain = 0;
1054        for (hash = 0; hash < PKGTAB_SIZE; hash++) {
1055            if (pkgTab[hash]) {
1056                buckets++;
1057                chainlen = 0;
1058                for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
1059                    chainlen++;
1060                    selinux_log(SELINUX_INFO, "%s:  name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
1061                                __FUNCTION__,
1062                                info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo);
1063                }
1064                entries += chainlen;
1065                if (longestchain < chainlen)
1066                    longestchain = chainlen;
1067            }
1068        }
1069        selinux_log(SELINUX_INFO, "SELinux:  %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
1070    }
1071#endif
1072
1073}
1074
1075static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
1076
1077struct pkg_info *package_info_lookup(const char *name)
1078{
1079    struct pkg_info *info;
1080    unsigned int hash;
1081
1082    __selinux_once(pkg_once, package_info_init);
1083
1084    hash = pkghash(name);
1085    for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
1086        if (!strcmp(name, info->name))
1087            return info;
1088    }
1089    return NULL;
1090}
1091
1092/* The contents of these paths are encrypted on FBE devices until user
1093 * credentials are presented (filenames inside are mangled), so we need
1094 * to delay restorecon of those until vold explicitly requests it. */
1095// NOTE: these paths need to be kept in sync with vold
1096#define DATA_SYSTEM_CE_PREFIX "/data/system_ce/"
1097#define DATA_MISC_CE_PREFIX "/data/misc_ce/"
1098
1099/* The path prefixes of package data directories. */
1100#define DATA_DATA_PATH "/data/data"
1101#define DATA_USER_PATH "/data/user"
1102#define DATA_USER_DE_PATH "/data/user_de"
1103#define EXPAND_USER_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user"
1104#define EXPAND_USER_DE_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user_de"
1105#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
1106#define DATA_USER_PREFIX DATA_USER_PATH "/"
1107#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
1108
1109static int pkgdir_selabel_lookup(const char *pathname,
1110                                 const char *seinfo,
1111                                 uid_t uid,
1112                                 char **secontextp)
1113{
1114    char *pkgname = NULL, *end = NULL;
1115    struct pkg_info *info = NULL;
1116    char *secontext = *secontextp;
1117    context_t ctx = NULL;
1118    int rc = 0;
1119
1120    /* Skip directory prefix before package name. */
1121    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
1122        pathname += sizeof(DATA_DATA_PREFIX) - 1;
1123    } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1124        pathname += sizeof(DATA_USER_PREFIX) - 1;
1125        while (isdigit(*pathname))
1126            pathname++;
1127        if (*pathname == '/')
1128            pathname++;
1129        else
1130            return 0;
1131    } else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) {
1132        pathname += sizeof(DATA_USER_DE_PREFIX) - 1;
1133        while (isdigit(*pathname))
1134            pathname++;
1135        if (*pathname == '/')
1136            pathname++;
1137        else
1138            return 0;
1139    } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
1140        pathname += sizeof(EXPAND_USER_PATH);
1141        while (isdigit(*pathname))
1142            pathname++;
1143        if (*pathname == '/')
1144            pathname++;
1145        else
1146            return 0;
1147    } else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
1148        pathname += sizeof(EXPAND_USER_DE_PATH);
1149        while (isdigit(*pathname))
1150            pathname++;
1151        if (*pathname == '/')
1152            pathname++;
1153        else
1154            return 0;
1155    } else
1156        return 0;
1157
1158    if (!(*pathname))
1159        return 0;
1160
1161    pkgname = strdup(pathname);
1162    if (!pkgname)
1163        return -1;
1164
1165    for (end = pkgname; *end && *end != '/'; end++)
1166        ;
1167    pathname = end;
1168    if (*end)
1169        pathname++;
1170    *end = '\0';
1171
1172    if (!seinfo) {
1173        info = package_info_lookup(pkgname);
1174        if (!info) {
1175            selinux_log(SELINUX_WARNING, "SELinux:  Could not look up information for package %s, cannot restorecon %s.\n",
1176                        pkgname, pathname);
1177            free(pkgname);
1178            return -1;
1179        }
1180    }
1181
1182    ctx = context_new(secontext);
1183    if (!ctx)
1184        goto err;
1185
1186    rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0,
1187                              info ? info->seinfo : seinfo, info ? info->name : pkgname, pathname, ctx);
1188    if (rc < 0)
1189        goto err;
1190
1191    secontext = context_str(ctx);
1192    if (!secontext)
1193        goto err;
1194
1195    if (!strcmp(secontext, *secontextp))
1196        goto out;
1197
1198    rc = security_check_context(secontext);
1199    if (rc < 0)
1200        goto err;
1201
1202    freecon(*secontextp);
1203    *secontextp = strdup(secontext);
1204    if (!(*secontextp))
1205        goto err;
1206
1207    rc = 0;
1208
1209out:
1210    free(pkgname);
1211    context_free(ctx);
1212    return rc;
1213err:
1214    selinux_log(SELINUX_ERROR, "%s:  Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
1215                __FUNCTION__, pathname, pkgname, info->seinfo, info->uid, strerror(errno));
1216    rc = -1;
1217    goto out;
1218}
1219
1220#define RESTORECON_LAST "security.restorecon_last"
1221
1222static int restorecon_sb(const char *pathname, const struct stat *sb,
1223                         bool nochange, bool verbose,
1224                         const char *seinfo, uid_t uid)
1225{
1226    char *secontext = NULL;
1227    char *oldsecontext = NULL;
1228    int rc = 0;
1229
1230    if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
1231        return 0;  /* no match, but not an error */
1232
1233    if (lgetfilecon(pathname, &oldsecontext) < 0)
1234        goto err;
1235
1236    /*
1237     * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
1238     * and use pkgdir_selabel_lookup() instead. Files within those directories
1239     * have different labeling rules, based off of /seapp_contexts, and
1240     * installd is responsible for managing these labels instead of init.
1241     */
1242    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1243        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
1244        !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1245        !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
1246        !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
1247        if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
1248            goto err;
1249    }
1250
1251    if (strcmp(oldsecontext, secontext) != 0) {
1252        if (verbose)
1253            selinux_log(SELINUX_INFO,
1254                        "SELinux:  Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1255        if (!nochange) {
1256            if (lsetfilecon(pathname, secontext) < 0)
1257                goto err;
1258        }
1259    }
1260
1261    rc = 0;
1262
1263out:
1264    freecon(oldsecontext);
1265    freecon(secontext);
1266    return rc;
1267
1268err:
1269    selinux_log(SELINUX_ERROR,
1270                "SELinux: Could not set context for %s:  %s\n",
1271                pathname, strerror(errno));
1272    rc = -1;
1273    goto out;
1274}
1275
1276#define SYS_PATH "/sys"
1277#define SYS_PREFIX SYS_PATH "/"
1278
1279static int selinux_android_restorecon_common(const char* pathname_orig,
1280                                             const char *seinfo,
1281                                             uid_t uid,
1282                                             unsigned int flags)
1283{
1284    bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1285    bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1286    bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1287    bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
1288    bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
1289    bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false;
1290    bool issys;
1291    bool setrestoreconlast = true;
1292    struct stat sb;
1293    struct statfs sfsb;
1294    FTS *fts;
1295    FTSENT *ftsent;
1296    char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
1297    char * paths[2] = { NULL , NULL };
1298    int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
1299    int error, sverrno;
1300    char xattr_value[FC_DIGEST_SIZE];
1301    ssize_t size;
1302
1303    if (is_selinux_enabled() <= 0)
1304        return 0;
1305
1306    __selinux_once(fc_once, file_context_init);
1307
1308    if (!fc_sehandle)
1309        return 0;
1310
1311    /*
1312     * Convert passed-in pathname to canonical pathname by resolving realpath of
1313     * containing dir, then appending last component name.
1314     */
1315    pathbname = basename(pathname_orig);
1316    if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) {
1317        pathname = realpath(pathname_orig, NULL);
1318        if (!pathname)
1319            goto realpatherr;
1320    } else {
1321        pathdname = dirname(pathname_orig);
1322        pathdnamer = realpath(pathdname, NULL);
1323        if (!pathdnamer)
1324            goto realpatherr;
1325        if (!strcmp(pathdnamer, "/"))
1326            error = asprintf(&pathname, "/%s", pathbname);
1327        else
1328            error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname);
1329        if (error < 0)
1330            goto oom;
1331    }
1332
1333    paths[0] = pathname;
1334    issys = (!strcmp(pathname, SYS_PATH)
1335            || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
1336
1337    if (!recurse) {
1338        if (lstat(pathname, &sb) < 0) {
1339            error = -1;
1340            goto cleanup;
1341        }
1342
1343        error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
1344        goto cleanup;
1345    }
1346
1347    /*
1348     * Ignore restorecon_last on /data/data or /data/user
1349     * since their labeling is based on seapp_contexts and seinfo
1350     * assignments rather than file_contexts and is managed by
1351     * installd rather than init.
1352     */
1353    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1354        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
1355        !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1356        !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
1357        !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME))
1358        setrestoreconlast = false;
1359
1360    /* Also ignore on /sys since it is regenerated on each boot regardless. */
1361    if (issys)
1362        setrestoreconlast = false;
1363
1364    /* Ignore files on in-memory filesystems */
1365    if (statfs(pathname, &sfsb) == 0) {
1366        if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
1367            setrestoreconlast = false;
1368    }
1369
1370    if (setrestoreconlast) {
1371        size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
1372        if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
1373            selinux_log(SELINUX_INFO,
1374                        "SELinux: Skipping restorecon_recursive(%s)\n",
1375                        pathname);
1376            error = 0;
1377            goto cleanup;
1378        }
1379    }
1380
1381    fts = fts_open(paths, ftsflags, NULL);
1382    if (!fts) {
1383        error = -1;
1384        goto cleanup;
1385    }
1386
1387    error = 0;
1388    while ((ftsent = fts_read(fts)) != NULL) {
1389        switch (ftsent->fts_info) {
1390        case FTS_DC:
1391            selinux_log(SELINUX_ERROR,
1392                        "SELinux:  Directory cycle on %s.\n", ftsent->fts_path);
1393            errno = ELOOP;
1394            error = -1;
1395            goto out;
1396        case FTS_DP:
1397            continue;
1398        case FTS_DNR:
1399            selinux_log(SELINUX_ERROR,
1400                        "SELinux:  Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1401            fts_set(fts, ftsent, FTS_SKIP);
1402            continue;
1403        case FTS_NS:
1404            selinux_log(SELINUX_ERROR,
1405                        "SELinux:  Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1406            fts_set(fts, ftsent, FTS_SKIP);
1407            continue;
1408        case FTS_ERR:
1409            selinux_log(SELINUX_ERROR,
1410                        "SELinux:  Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1411            fts_set(fts, ftsent, FTS_SKIP);
1412            continue;
1413        case FTS_D:
1414            if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
1415                fts_set(fts, ftsent, FTS_SKIP);
1416                continue;
1417            }
1418
1419            if (skipce &&
1420                (!strncmp(ftsent->fts_path, DATA_SYSTEM_CE_PREFIX, sizeof(DATA_SYSTEM_CE_PREFIX)-1) ||
1421                 !strncmp(ftsent->fts_path, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1))) {
1422                // Don't label anything below this directory.
1423                fts_set(fts, ftsent, FTS_SKIP);
1424                // but fall through and make sure we label the directory itself
1425            }
1426
1427            if (!datadata &&
1428                (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
1429                 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
1430                 !strncmp(ftsent->fts_path, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1431                 !fnmatch(EXPAND_USER_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME) ||
1432                 !fnmatch(EXPAND_USER_DE_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME))) {
1433                // Don't label anything below this directory.
1434                fts_set(fts, ftsent, FTS_SKIP);
1435                // but fall through and make sure we label the directory itself
1436            }
1437            /* fall through */
1438        default:
1439            error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
1440            break;
1441        }
1442    }
1443
1444    // Labeling successful. Mark the top level directory as completed.
1445    if (setrestoreconlast && !nochange && !error)
1446        setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1447
1448out:
1449    sverrno = errno;
1450    (void) fts_close(fts);
1451    errno = sverrno;
1452cleanup:
1453    free(pathdnamer);
1454    free(pathname);
1455    return error;
1456oom:
1457    sverrno = errno;
1458    selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
1459    errno = sverrno;
1460    error = -1;
1461    goto cleanup;
1462realpatherr:
1463    sverrno = errno;
1464    selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n",
1465            pathname_orig, strerror(errno));
1466    errno = sverrno;
1467    error = -1;
1468    goto cleanup;
1469}
1470
1471int selinux_android_restorecon(const char *file, unsigned int flags)
1472{
1473    return selinux_android_restorecon_common(file, NULL, -1, flags);
1474}
1475
1476int selinux_android_restorecon_pkgdir(const char *pkgdir,
1477                                      const char *seinfo,
1478                                      uid_t uid,
1479                                      unsigned int flags)
1480{
1481    return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1482}
1483
1484struct selabel_handle* selinux_android_file_context_handle(void)
1485{
1486    char *path = NULL;
1487    struct selabel_handle *sehandle;
1488    struct selinux_opt fc_opts[] = {
1489        { SELABEL_OPT_PATH, path },
1490        { SELABEL_OPT_BASEONLY, (char *)1 }
1491    };
1492
1493    set_policy_index();
1494    fc_opts[0].value = seopts[policy_index].value;
1495
1496    sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 2);
1497
1498    if (!sehandle) {
1499        selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
1500                __FUNCTION__, strerror(errno));
1501        return NULL;
1502    }
1503    if (!compute_contexts_hash(seopts, fc_digest)) {
1504        selabel_close(sehandle);
1505        return NULL;
1506    }
1507    selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n",
1508            fc_opts[0].value);
1509
1510    return sehandle;
1511}
1512
1513struct selabel_handle* selinux_android_prop_context_handle(void)
1514{
1515    struct selabel_handle* sehandle;
1516
1517    set_policy_index();
1518    sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1519            &seopts_prop[policy_index], 1);
1520    if (!sehandle) {
1521        selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n",
1522                __FUNCTION__, strerror(errno));
1523        return NULL;
1524    }
1525    selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n",
1526            seopts_prop[policy_index].value);
1527
1528    return sehandle;
1529}
1530
1531struct selabel_handle* selinux_android_service_context_handle(void)
1532{
1533    struct selabel_handle* sehandle;
1534
1535    set_policy_index();
1536    sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1537            &seopts_service[policy_index], 1);
1538
1539    if (!sehandle) {
1540        selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
1541                __FUNCTION__, strerror(errno));
1542        return NULL;
1543    }
1544    selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n",
1545            seopts_service[policy_index].value);
1546
1547    return sehandle;
1548}
1549
1550void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1551{
1552    fc_sehandle = (struct selabel_handle *) hndl;
1553}
1554
1555static int selinux_android_load_policy_helper(bool reload)
1556{
1557	int fd = -1, rc;
1558	struct stat sb;
1559	void *map = NULL;
1560	int old_policy_index = policy_index;
1561
1562	/*
1563	 * If reloading policy and there is no /data policy or
1564	 * that /data policy has the wrong version and our prior
1565	 * load was from the / policy, then just return.
1566	 * There is no point in reloading policy from / a second time.
1567	 */
1568	set_policy_index();
1569	if (reload && !policy_index && !old_policy_index)
1570		return 0;
1571
1572	fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
1573	if (fd < 0) {
1574		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
1575				strerror(errno));
1576		return -1;
1577	}
1578	if (fstat(fd, &sb) < 0) {
1579		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
1580				sepolicy_file[policy_index], strerror(errno));
1581		close(fd);
1582		return -1;
1583	}
1584	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1585	if (map == MAP_FAILED) {
1586		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
1587				sepolicy_file[policy_index], strerror(errno));
1588		close(fd);
1589		return -1;
1590	}
1591
1592	rc = security_load_policy(map, sb.st_size);
1593	if (rc < 0) {
1594		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
1595				strerror(errno));
1596		munmap(map, sb.st_size);
1597		close(fd);
1598		return -1;
1599	}
1600
1601	munmap(map, sb.st_size);
1602	close(fd);
1603	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
1604
1605	return 0;
1606}
1607
1608int selinux_android_reload_policy(void)
1609{
1610    return selinux_android_load_policy_helper(true);
1611}
1612
1613int selinux_android_load_policy(void)
1614{
1615	const char *mnt = SELINUXMNT;
1616	int rc;
1617	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1618	if (rc < 0) {
1619		if (errno == ENODEV) {
1620			/* SELinux not enabled in kernel */
1621			return -1;
1622		}
1623		if (errno == ENOENT) {
1624			/* Fall back to legacy mountpoint. */
1625			mnt = OLDSELINUXMNT;
1626			rc = mkdir(mnt, 0755);
1627			if (rc == -1 && errno != EEXIST) {
1628				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
1629					strerror(errno));
1630				return -1;
1631			}
1632			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1633		}
1634	}
1635	if (rc < 0) {
1636		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
1637				strerror(errno));
1638		return -1;
1639	}
1640	set_selinuxmnt(mnt);
1641
1642    return selinux_android_load_policy_helper(false);
1643}
1644
1645int selinux_log_callback(int type, const char *fmt, ...)
1646{
1647    va_list ap;
1648    int priority;
1649    char *strp;
1650
1651    switch(type) {
1652    case SELINUX_WARNING:
1653        priority = ANDROID_LOG_WARN;
1654        break;
1655    case SELINUX_INFO:
1656        priority = ANDROID_LOG_INFO;
1657        break;
1658    default:
1659        priority = ANDROID_LOG_ERROR;
1660        break;
1661    }
1662
1663    va_start(ap, fmt);
1664    if (vasprintf(&strp, fmt, ap) != -1) {
1665        LOG_PRI(priority, "SELinux", "%s", strp);
1666        LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
1667        free(strp);
1668    }
1669    va_end(ap);
1670    return 0;
1671}
1672