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 <mincrypt/sha.h>
24#include <private/android_filesystem_config.h>
25#include "policy.h"
26#include "callbacks.h"
27#include "selinux_internal.h"
28#include "label_internal.h"
29
30/*
31 * XXX Where should this configuration file be located?
32 * Needs to be accessible by zygote and installd when
33 * setting credentials for app processes and setting permissions
34 * on app data directories.
35 */
36static char const * const seapp_contexts_file[] = {
37	"/seapp_contexts",
38	"/data/security/current/seapp_contexts",
39	NULL };
40
41static const struct selinux_opt seopts[] = {
42	{ SELABEL_OPT_PATH, "/file_contexts" },
43	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
44	{ 0, NULL } };
45
46static const char *const sepolicy_file[] = {
47	"/sepolicy",
48	"/data/security/current/sepolicy",
49	NULL };
50
51enum levelFrom {
52	LEVELFROM_NONE,
53	LEVELFROM_APP,
54	LEVELFROM_USER,
55	LEVELFROM_ALL
56};
57
58#define POLICY_OVERRIDE_VERSION    "/data/security/current/selinux_version"
59#define POLICY_BASE_VERSION        "/selinux_version"
60static int policy_index = 0;
61
62static void set_policy_index(void)
63{
64	int fd_base = -1, fd_override = -1;
65	struct stat sb_base;
66	struct stat sb_override;
67	void *map_base, *map_override;
68
69	policy_index = 0;
70
71	fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW);
72	if (fd_base < 0)
73		return;
74
75	if (fstat(fd_base, &sb_base) < 0) {
76		close(fd_base);
77		return;
78	}
79
80	fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW);
81	if (fd_override < 0) {
82		close(fd_base);
83		return;
84	}
85
86	if (fstat(fd_override, &sb_override) < 0) {
87		close(fd_base);
88		close(fd_override);
89		return;
90	}
91
92	if (sb_base.st_size != sb_override.st_size) {
93		close(fd_base);
94		close(fd_override);
95		return;
96	}
97
98	map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0);
99	if (map_base == MAP_FAILED) {
100		close(fd_base);
101		close(fd_override);
102		return;
103	}
104
105	map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0);
106	if (map_override == MAP_FAILED) {
107		munmap(map_base, sb_base.st_size);
108		close(fd_base);
109		close(fd_override);
110		return;
111	}
112
113	if (memcmp(map_base, map_override, sb_base.st_size) == 0)
114		policy_index = 1;
115
116
117	close(fd_base);
118	close(fd_override);
119	munmap(map_base, sb_base.st_size);
120	munmap(map_override, sb_override.st_size);
121}
122
123bool selinux_android_use_data_policy(void)
124{
125	set_policy_index();
126	return (policy_index == 1);
127}
128
129#if DEBUG
130static char const * const levelFromName[] = {
131	"none",
132	"app",
133	"user",
134	"all"
135};
136#endif
137
138struct prefix_str {
139	size_t len;
140	char *str;
141	char is_prefix;
142};
143
144static void free_prefix_str(struct prefix_str *p)
145{
146	if (!p)
147		return;
148	free(p->str);
149}
150
151struct seapp_context {
152	/* input selectors */
153	char isSystemServer;
154	struct prefix_str user;
155	char *seinfo;
156	struct prefix_str name;
157	struct prefix_str path;
158	/* outputs */
159	char *domain;
160	char *type;
161	char *level;
162	char *sebool;
163	enum levelFrom levelFrom;
164};
165
166static void free_seapp_context(struct seapp_context *s)
167{
168	if (!s)
169		return;
170
171	free_prefix_str(&s->user);
172	free(s->seinfo);
173	free_prefix_str(&s->name);
174	free_prefix_str(&s->path);
175	free(s->domain);
176	free(s->type);
177	free(s->level);
178	free(s->sebool);
179}
180
181static int seapp_context_cmp(const void *A, const void *B)
182{
183	const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
184	const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
185	const struct seapp_context *s1 = *sp1, *s2 = *sp2;
186
187	/* Give precedence to isSystemServer=true. */
188	if (s1->isSystemServer != s2->isSystemServer)
189		return (s1->isSystemServer ? -1 : 1);
190
191	/* Give precedence to a specified user= over an unspecified user=. */
192	if (s1->user.str && !s2->user.str)
193		return -1;
194	if (!s1->user.str && s2->user.str)
195		return 1;
196
197	if (s1->user.str) {
198		/* Give precedence to a fixed user= string over a prefix. */
199		if (s1->user.is_prefix != s2->user.is_prefix)
200			return (s2->user.is_prefix ? -1 : 1);
201
202		/* Give precedence to a longer prefix over a shorter prefix. */
203		if (s1->user.is_prefix && s1->user.len != s2->user.len)
204			return (s1->user.len > s2->user.len) ? -1 : 1;
205	}
206
207	/* Give precedence to a specified seinfo= over an unspecified seinfo=. */
208	if (s1->seinfo && !s2->seinfo)
209		return -1;
210	if (!s1->seinfo && s2->seinfo)
211		return 1;
212
213	/* Give precedence to a specified name= over an unspecified name=. */
214	if (s1->name.str && !s2->name.str)
215		return -1;
216	if (!s1->name.str && s2->name.str)
217		return 1;
218
219	if (s1->name.str) {
220		/* Give precedence to a fixed name= string over a prefix. */
221		if (s1->name.is_prefix != s2->name.is_prefix)
222			return (s2->name.is_prefix ? -1 : 1);
223
224		/* Give precedence to a longer prefix over a shorter prefix. */
225		if (s1->name.is_prefix && s1->name.len != s2->name.len)
226			return (s1->name.len > s2->name.len) ? -1 : 1;
227	}
228
229	/* Give precedence to a specified path= over an unspecified path=. */
230	if (s1->path.str && !s2->path.str)
231		return -1;
232	if (!s1->path.str && s2->path.str)
233		return 1;
234
235	if (s1->path.str) {
236		/* Give precedence to a fixed path= string over a prefix. */
237		if (s1->path.is_prefix != s2->path.is_prefix)
238			return (s2->path.is_prefix ? -1 : 1);
239
240		/* Give precedence to a longer prefix over a shorter prefix. */
241		if (s1->path.is_prefix && s1->path.len != s2->path.len)
242			return (s1->path.len > s2->path.len) ? -1 : 1;
243	}
244
245        /* Give precedence to a specified sebool= over an unspecified sebool=. */
246        if (s1->sebool && !s2->sebool)
247                return -1;
248        if (!s1->sebool && s2->sebool)
249                return 1;
250
251	/* Anything else has equal precedence. */
252	return 0;
253}
254
255static struct seapp_context **seapp_contexts = NULL;
256static int nspec = 0;
257
258static void free_seapp_contexts(void)
259{
260	int n;
261
262	if (!seapp_contexts)
263		return;
264
265	for (n = 0; n < nspec; n++)
266		free_seapp_context(seapp_contexts[n]);
267
268	free(seapp_contexts);
269	seapp_contexts = NULL;
270	nspec = 0;
271}
272
273int selinux_android_seapp_context_reload(void)
274{
275	FILE *fp = NULL;
276	char line_buf[BUFSIZ];
277	char *token;
278	unsigned lineno;
279	struct seapp_context *cur;
280	char *p, *name = NULL, *value = NULL, *saveptr;
281	size_t len;
282	int n, ret;
283
284	set_policy_index();
285
286	fp = fopen(seapp_contexts_file[policy_index], "r");
287	if (!fp) {
288		selinux_log(SELINUX_ERROR, "%s:  could not open any seapp_contexts file", __FUNCTION__);
289		return -1;
290	}
291
292	free_seapp_contexts();
293
294	nspec = 0;
295	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
296		p = line_buf;
297		while (isspace(*p))
298			p++;
299		if (*p == '#' || *p == 0)
300			continue;
301		nspec++;
302	}
303
304	seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
305	if (!seapp_contexts)
306		goto oom;
307
308	rewind(fp);
309	nspec = 0;
310	lineno = 1;
311	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
312		len = strlen(line_buf);
313		if (line_buf[len - 1] == '\n')
314			line_buf[len - 1] = 0;
315		p = line_buf;
316		while (isspace(*p))
317			p++;
318		if (*p == '#' || *p == 0)
319			continue;
320
321		cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
322		if (!cur)
323			goto oom;
324
325		token = strtok_r(p, " \t", &saveptr);
326		if (!token) {
327			free_seapp_context(cur);
328			goto err;
329		}
330
331		while (1) {
332			name = token;
333			value = strchr(name, '=');
334			if (!value) {
335				free_seapp_context(cur);
336				goto err;
337			}
338			*value++ = 0;
339
340			if (!strcasecmp(name, "isSystemServer")) {
341				if (!strcasecmp(value, "true"))
342					cur->isSystemServer = 1;
343				else if (!strcasecmp(value, "false"))
344					cur->isSystemServer = 0;
345				else {
346					free_seapp_context(cur);
347					goto err;
348				}
349			} else if (!strcasecmp(name, "user")) {
350				cur->user.str = strdup(value);
351				if (!cur->user.str) {
352					free_seapp_context(cur);
353					goto oom;
354				}
355				cur->user.len = strlen(cur->user.str);
356				if (cur->user.str[cur->user.len-1] == '*')
357					cur->user.is_prefix = 1;
358			} else if (!strcasecmp(name, "seinfo")) {
359				cur->seinfo = strdup(value);
360				if (!cur->seinfo) {
361					free_seapp_context(cur);
362					goto oom;
363				}
364			} else if (!strcasecmp(name, "name")) {
365				cur->name.str = strdup(value);
366				if (!cur->name.str) {
367					free_seapp_context(cur);
368					goto oom;
369				}
370				cur->name.len = strlen(cur->name.str);
371				if (cur->name.str[cur->name.len-1] == '*')
372					cur->name.is_prefix = 1;
373			} else if (!strcasecmp(name, "domain")) {
374				cur->domain = strdup(value);
375				if (!cur->domain) {
376					free_seapp_context(cur);
377					goto oom;
378				}
379			} else if (!strcasecmp(name, "type")) {
380				cur->type = strdup(value);
381				if (!cur->type) {
382					free_seapp_context(cur);
383					goto oom;
384				}
385			} else if (!strcasecmp(name, "levelFromUid")) {
386				if (!strcasecmp(value, "true"))
387					cur->levelFrom = LEVELFROM_APP;
388				else if (!strcasecmp(value, "false"))
389					cur->levelFrom = LEVELFROM_NONE;
390				else {
391					free_seapp_context(cur);
392					goto err;
393				}
394			} else if (!strcasecmp(name, "levelFrom")) {
395				if (!strcasecmp(value, "none"))
396					cur->levelFrom = LEVELFROM_NONE;
397				else if (!strcasecmp(value, "app"))
398					cur->levelFrom = LEVELFROM_APP;
399				else if (!strcasecmp(value, "user"))
400					cur->levelFrom = LEVELFROM_USER;
401				else if (!strcasecmp(value, "all"))
402					cur->levelFrom = LEVELFROM_ALL;
403				else {
404					free_seapp_context(cur);
405					goto err;
406				}
407			} else if (!strcasecmp(name, "level")) {
408				cur->level = strdup(value);
409				if (!cur->level) {
410					free_seapp_context(cur);
411					goto oom;
412				}
413			} else if (!strcasecmp(name, "path")) {
414				cur->path.str = strdup(value);
415				if (!cur->path.str) {
416					free_seapp_context(cur);
417					goto oom;
418				}
419				cur->path.len = strlen(cur->path.str);
420				if (cur->path.str[cur->path.len-1] == '*')
421					cur->path.is_prefix = 1;
422			} else if (!strcasecmp(name, "sebool")) {
423				cur->sebool = strdup(value);
424				if (!cur->sebool) {
425					free_seapp_context(cur);
426					goto oom;
427				}
428			} else {
429				free_seapp_context(cur);
430				goto err;
431			}
432
433			token = strtok_r(NULL, " \t", &saveptr);
434			if (!token)
435				break;
436		}
437
438		if (cur->name.str &&
439		    (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
440			selinux_log(SELINUX_ERROR, "%s:  No specific seinfo value specified with name=\"%s\", on line %u:  insecure configuration!\n",
441				    seapp_contexts_file[policy_index], cur->name.str, lineno);
442			free_seapp_context(cur);
443			goto err;
444		}
445
446		seapp_contexts[nspec] = cur;
447		nspec++;
448		lineno++;
449	}
450
451	qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
452	      seapp_context_cmp);
453
454#if DEBUG
455	{
456		int i;
457		for (i = 0; i < nspec; i++) {
458			cur = seapp_contexts[i];
459			selinux_log(SELINUX_INFO, "%s:  isSystemServer=%s user=%s seinfo=%s name=%s path=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s",
460			__FUNCTION__,
461			cur->isSystemServer ? "true" : "false", cur->user.str,
462			cur->seinfo, cur->name.str, cur->path.str, cur->sebool, cur->domain,
463			cur->type, cur->level,
464			levelFromName[cur->levelFrom]);
465		}
466	}
467#endif
468
469	ret = 0;
470
471out:
472	fclose(fp);
473	return ret;
474
475err:
476	selinux_log(SELINUX_ERROR, "%s:  Invalid entry on line %u\n",
477		    seapp_contexts_file[policy_index], lineno);
478	free_seapp_contexts();
479	ret = -1;
480	goto out;
481oom:
482	selinux_log(SELINUX_ERROR,
483		    "%s:  Out of memory\n", __FUNCTION__);
484	free_seapp_contexts();
485	ret = -1;
486	goto out;
487}
488
489
490static void seapp_context_init(void)
491{
492        selinux_android_seapp_context_reload();
493}
494
495static pthread_once_t once = PTHREAD_ONCE_INIT;
496
497/*
498 * Max id that can be mapped to category set uniquely
499 * using the current scheme.
500 */
501#define CAT_MAPPING_MAX_ID (0x1<<16)
502
503enum seapp_kind {
504	SEAPP_TYPE,
505	SEAPP_DOMAIN
506};
507
508static int seapp_context_lookup(enum seapp_kind kind,
509				uid_t uid,
510				int isSystemServer,
511				const char *seinfo,
512				const char *pkgname,
513				const char *path,
514				context_t ctx)
515{
516	const char *username = NULL;
517	struct seapp_context *cur = NULL;
518	int i;
519	size_t n;
520	uid_t userid;
521	uid_t appid;
522
523	__selinux_once(once, seapp_context_init);
524
525	userid = uid / AID_USER;
526	appid = uid % AID_USER;
527	if (appid < AID_APP) {
528		for (n = 0; n < android_id_count; n++) {
529			if (android_ids[n].aid == appid) {
530				username = android_ids[n].name;
531				break;
532			}
533		}
534		if (!username)
535			goto err;
536	} else if (appid < AID_ISOLATED_START) {
537		username = "_app";
538		appid -= AID_APP;
539	} else {
540		username = "_isolated";
541		appid -= AID_ISOLATED_START;
542	}
543
544	if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
545		goto err;
546
547	for (i = 0; i < nspec; i++) {
548		cur = seapp_contexts[i];
549
550		if (cur->isSystemServer != isSystemServer)
551			continue;
552
553		if (cur->user.str) {
554			if (cur->user.is_prefix) {
555				if (strncasecmp(username, cur->user.str, cur->user.len-1))
556					continue;
557			} else {
558				if (strcasecmp(username, cur->user.str))
559					continue;
560			}
561		}
562
563		if (cur->seinfo) {
564			if (!seinfo || strcasecmp(seinfo, cur->seinfo))
565				continue;
566		}
567
568		if (cur->name.str) {
569			if(!pkgname)
570				continue;
571
572			if (cur->name.is_prefix) {
573				if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
574					continue;
575			} else {
576				if (strcasecmp(pkgname, cur->name.str))
577					continue;
578			}
579		}
580
581		if (cur->path.str) {
582			if (!path)
583				continue;
584
585			if (cur->path.is_prefix) {
586				if (strncmp(path, cur->path.str, cur->path.len-1))
587					continue;
588			} else {
589				if (strcmp(path, cur->path.str))
590					continue;
591			}
592		}
593
594		if (kind == SEAPP_TYPE && !cur->type)
595			continue;
596		else if (kind == SEAPP_DOMAIN && !cur->domain)
597			continue;
598
599		if (cur->sebool) {
600			int value = security_get_boolean_active(cur->sebool);
601			if (value == 0)
602				continue;
603			else if (value == -1) {
604				selinux_log(SELINUX_ERROR, \
605				"Could not find boolean: %s ", cur->sebool);
606				goto err;
607			}
608		}
609
610		if (kind == SEAPP_TYPE) {
611			if (context_type_set(ctx, cur->type))
612				goto oom;
613		} else if (kind == SEAPP_DOMAIN) {
614			if (context_type_set(ctx, cur->domain))
615				goto oom;
616		}
617
618		if (cur->levelFrom != LEVELFROM_NONE) {
619			char level[255];
620			switch (cur->levelFrom) {
621			case LEVELFROM_APP:
622				snprintf(level, sizeof level, "s0:c%u,c%u",
623					 appid & 0xff,
624					 256 + (appid>>8 & 0xff));
625				break;
626			case LEVELFROM_USER:
627				snprintf(level, sizeof level, "s0:c%u,c%u",
628					 512 + (userid & 0xff),
629					 768 + (userid>>8 & 0xff));
630				break;
631			case LEVELFROM_ALL:
632				snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
633					 appid & 0xff,
634					 256 + (appid>>8 & 0xff),
635					 512 + (userid & 0xff),
636					 768 + (userid>>8 & 0xff));
637				break;
638			default:
639				goto err;
640			}
641			if (context_range_set(ctx, level))
642				goto oom;
643		} else if (cur->level) {
644			if (context_range_set(ctx, cur->level))
645				goto oom;
646		}
647
648		break;
649	}
650
651	if (kind == SEAPP_DOMAIN && i == nspec) {
652		/*
653		 * No match.
654		 * Fail to prevent staying in the zygote's context.
655		 */
656		selinux_log(SELINUX_ERROR,
657			    "%s:  No match for app with uid %d, seinfo %s, name %s\n",
658			    __FUNCTION__, uid, seinfo, pkgname);
659
660		if (security_getenforce() == 1)
661			goto err;
662	}
663
664	return 0;
665err:
666	return -1;
667oom:
668	return -2;
669}
670
671int selinux_android_setfilecon(const char *pkgdir,
672				const char *pkgname,
673				const char *seinfo,
674				uid_t uid)
675{
676	char *orig_ctx_str = NULL;
677	char *ctx_str = NULL;
678	context_t ctx = NULL;
679	int rc = -1;
680
681	if (is_selinux_enabled() <= 0)
682		return 0;
683
684	rc = getfilecon(pkgdir, &ctx_str);
685	if (rc < 0)
686		goto err;
687
688	ctx = context_new(ctx_str);
689	orig_ctx_str = ctx_str;
690	if (!ctx)
691		goto oom;
692
693	rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
694	if (rc == -1)
695		goto err;
696	else if (rc == -2)
697		goto oom;
698
699	ctx_str = context_str(ctx);
700	if (!ctx_str)
701		goto oom;
702
703	rc = security_check_context(ctx_str);
704	if (rc < 0)
705		goto err;
706
707	if (strcmp(ctx_str, orig_ctx_str)) {
708		rc = setfilecon(pkgdir, ctx_str);
709		if (rc < 0)
710			goto err;
711	}
712
713	rc = 0;
714out:
715	freecon(orig_ctx_str);
716	context_free(ctx);
717	return rc;
718err:
719	selinux_log(SELINUX_ERROR, "%s:  Error setting context for pkgdir %s, uid %d: %s\n",
720		    __FUNCTION__, pkgdir, uid, strerror(errno));
721	rc = -1;
722	goto out;
723oom:
724	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
725	rc = -1;
726	goto out;
727}
728
729int selinux_android_setcontext(uid_t uid,
730			       int isSystemServer,
731			       const char *seinfo,
732			       const char *pkgname)
733{
734	char *orig_ctx_str = NULL, *ctx_str;
735	context_t ctx = NULL;
736	int rc = -1;
737
738	if (is_selinux_enabled() <= 0)
739		return 0;
740
741	rc = getcon(&ctx_str);
742	if (rc)
743		goto err;
744
745	ctx = context_new(ctx_str);
746	orig_ctx_str = ctx_str;
747	if (!ctx)
748		goto oom;
749
750	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
751	if (rc == -1)
752		goto err;
753	else if (rc == -2)
754		goto oom;
755
756	ctx_str = context_str(ctx);
757	if (!ctx_str)
758		goto oom;
759
760	rc = security_check_context(ctx_str);
761	if (rc < 0)
762		goto err;
763
764	if (strcmp(ctx_str, orig_ctx_str)) {
765		rc = setcon(ctx_str);
766		if (rc < 0)
767			goto err;
768	}
769
770	rc = 0;
771out:
772	freecon(orig_ctx_str);
773	context_free(ctx);
774	avc_netlink_close();
775	return rc;
776err:
777	if (isSystemServer)
778		selinux_log(SELINUX_ERROR,
779				"%s:  Error setting context for system server: %s\n",
780				__FUNCTION__, strerror(errno));
781	else
782		selinux_log(SELINUX_ERROR,
783				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
784				__FUNCTION__, uid, seinfo, strerror(errno));
785
786	rc = -1;
787	goto out;
788oom:
789	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
790	rc = -1;
791	goto out;
792}
793
794static struct selabel_handle *sehandle = NULL;
795#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
796static uint8_t fc_digest[FC_DIGEST_SIZE];
797
798static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[])
799{
800    struct selabel_handle *h;
801    int fd;
802    struct stat sb;
803    void *map;
804
805    set_policy_index();
806
807    h = selabel_open(SELABEL_CTX_FILE, &opts[policy_index], 1);
808    if (!h)
809        return NULL;
810
811    fd = open(opts[policy_index].value, O_RDONLY | O_NOFOLLOW);
812    if (fd < 0) {
813        selinux_log(SELINUX_ERROR, "SELinux:  Could not open %s:  %s\n",
814                    opts[policy_index].value, strerror(errno));
815        goto err;
816    }
817    if (fstat(fd, &sb) < 0) {
818        selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
819                    opts[policy_index].value, strerror(errno));
820        close(fd);
821        goto err;
822    }
823    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
824    if (map == MAP_FAILED) {
825        selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
826                    opts[policy_index].value, strerror(errno));
827        close(fd);
828        goto err;
829    }
830    SHA_hash(map, sb.st_size, fc_digest);
831    munmap(map, sb.st_size);
832    close(fd);
833
834    selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts from %s\n",
835                opts[policy_index].value);
836
837    return h;
838
839err:
840    selabel_close(h);
841    return NULL;
842}
843
844static struct selabel_handle *file_context_open(void)
845{
846	struct selabel_handle *h;
847
848	h = get_selabel_handle(seopts);
849
850	if (!h)
851		selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
852				__FUNCTION__, strerror(errno));
853	return h;
854}
855
856static void file_context_init(void)
857{
858    if (!sehandle)
859        sehandle = file_context_open();
860}
861
862static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
863
864struct pkgInfo {
865    char *name;
866    uid_t uid;
867    bool debuggable;
868    char *dataDir;
869    char *seinfo;
870    struct pkgInfo *next;
871};
872
873#define PKGTAB_SIZE 256
874static struct pkgInfo *pkgTab[PKGTAB_SIZE];
875
876static unsigned int pkghash(const char *pkgname)
877{
878    unsigned int h = 7;
879    for (; *pkgname; pkgname++) {
880        h = h * 31 + *pkgname;
881    }
882    return h & (PKGTAB_SIZE - 1);
883}
884
885/* The file containing the list of installed packages on the system */
886#define PACKAGES_LIST_FILE  "/data/system/packages.list"
887
888static void package_info_init(void)
889{
890    char *buf = NULL;
891    size_t buflen = 0;
892    ssize_t bytesread;
893    FILE *fp;
894    char *cur, *next;
895    struct pkgInfo *pkgInfo = NULL;
896    unsigned int hash;
897    unsigned long lineno = 1;
898
899    fp = fopen(PACKAGES_LIST_FILE, "r");
900    if (!fp) {
901        selinux_log(SELINUX_ERROR, "SELinux:  Could not open %s:  %s.\n",
902                    PACKAGES_LIST_FILE, strerror(errno));
903        return;
904    }
905    while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
906        pkgInfo = calloc(1, sizeof(*pkgInfo));
907        if (!pkgInfo)
908            goto err;
909        next = buf;
910        cur = strsep(&next, " \t\n");
911        if (!cur)
912            goto err;
913        pkgInfo->name = strdup(cur);
914        if (!pkgInfo->name)
915            goto err;
916        cur = strsep(&next, " \t\n");
917        if (!cur)
918            goto err;
919        pkgInfo->uid = atoi(cur);
920        if (!pkgInfo->uid)
921            goto err;
922        cur = strsep(&next, " \t\n");
923        if (!cur)
924            goto err;
925        pkgInfo->debuggable = atoi(cur);
926        cur = strsep(&next, " \t\n");
927        if (!cur)
928            goto err;
929        pkgInfo->dataDir = strdup(cur);
930        if (!pkgInfo->dataDir)
931            goto err;
932        cur = strsep(&next, " \t\n");
933        if (!cur)
934            goto err;
935        pkgInfo->seinfo = strdup(cur);
936        if (!pkgInfo->seinfo)
937            goto err;
938
939        hash = pkghash(pkgInfo->name);
940        if (pkgTab[hash])
941            pkgInfo->next = pkgTab[hash];
942        pkgTab[hash] = pkgInfo;
943
944        lineno++;
945    }
946
947#if DEBUG
948    {
949        unsigned int buckets, entries, chainlen, longestchain;
950
951        buckets = entries = longestchain = 0;
952        for (hash = 0; hash < PKGTAB_SIZE; hash++) {
953            if (pkgTab[hash]) {
954                buckets++;
955                chainlen = 0;
956                for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
957                    chainlen++;
958                    selinux_log(SELINUX_INFO, "%s:  name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
959                                __FUNCTION__,
960                                pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo);
961                }
962                entries += chainlen;
963                if (longestchain < chainlen)
964                    longestchain = chainlen;
965            }
966        }
967        selinux_log(SELINUX_INFO, "SELinux:  %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
968    }
969#endif
970
971out:
972    free(buf);
973    fclose(fp);
974    return;
975
976err:
977    selinux_log(SELINUX_ERROR, "SELinux:  Error reading %s on line %lu.\n",
978                PACKAGES_LIST_FILE, lineno);
979    if (pkgInfo) {
980        free(pkgInfo->name);
981        free(pkgInfo->dataDir);
982        free(pkgInfo->seinfo);
983        free(pkgInfo);
984    }
985    goto out;
986}
987
988static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
989
990struct pkgInfo *package_info_lookup(const char *name)
991{
992    struct pkgInfo *pkgInfo;
993    unsigned int hash;
994
995    __selinux_once(pkg_once, package_info_init);
996
997    hash = pkghash(name);
998    for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
999        if (!strcmp(name, pkgInfo->name))
1000            return pkgInfo;
1001    }
1002    return NULL;
1003}
1004
1005/* The path prefixes of package data directories. */
1006#define DATA_DATA_PATH "/data/data"
1007#define DATA_USER_PATH "/data/user"
1008#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
1009#define DATA_USER_PREFIX DATA_USER_PATH "/"
1010
1011static int pkgdir_selabel_lookup(const char *pathname,
1012                                 const char *seinfo,
1013                                 uid_t uid,
1014                                 char **secontextp)
1015{
1016    char *pkgname = NULL, *end = NULL;
1017    struct pkgInfo *pkgInfo = NULL;
1018    char *secontext = *secontextp;
1019    context_t ctx = NULL;
1020    int rc = 0;
1021
1022    /* Skip directory prefix before package name. */
1023    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
1024        pathname += sizeof(DATA_DATA_PREFIX) - 1;
1025    } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1026        pathname += sizeof(DATA_USER_PREFIX) - 1;
1027        while (isdigit(*pathname))
1028            pathname++;
1029        if (*pathname == '/')
1030            pathname++;
1031        else
1032            return 0;
1033    } else
1034        return 0;
1035
1036    if (!(*pathname))
1037        return 0;
1038
1039    pkgname = strdup(pathname);
1040    if (!pkgname)
1041        return -1;
1042
1043    for (end = pkgname; *end && *end != '/'; end++)
1044        ;
1045    pathname = end;
1046    if (*end)
1047        pathname++;
1048    *end = '\0';
1049
1050    if (!seinfo) {
1051        pkgInfo = package_info_lookup(pkgname);
1052        if (!pkgInfo) {
1053            selinux_log(SELINUX_WARNING, "SELinux:  Could not look up information for package %s, cannot restorecon %s.\n",
1054                        pkgname, pathname);
1055            free(pkgname);
1056            return -1;
1057        }
1058    }
1059
1060    ctx = context_new(secontext);
1061    if (!ctx)
1062        goto err;
1063
1064    rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0,
1065                              pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx);
1066    if (rc < 0)
1067        goto err;
1068
1069    secontext = context_str(ctx);
1070    if (!secontext)
1071        goto err;
1072
1073    if (!strcmp(secontext, *secontextp))
1074        goto out;
1075
1076    rc = security_check_context(secontext);
1077    if (rc < 0)
1078        goto err;
1079
1080    freecon(*secontextp);
1081    *secontextp = strdup(secontext);
1082    if (!(*secontextp))
1083        goto err;
1084
1085    rc = 0;
1086
1087out:
1088    free(pkgname);
1089    context_free(ctx);
1090    return rc;
1091err:
1092    selinux_log(SELINUX_ERROR, "%s:  Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
1093                __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno));
1094    rc = -1;
1095    goto out;
1096}
1097
1098#define RESTORECON_LAST "security.restorecon_last"
1099
1100static int restorecon_sb(const char *pathname, const struct stat *sb,
1101                         bool nochange, bool verbose,
1102                         const char *seinfo, uid_t uid)
1103{
1104    char *secontext = NULL;
1105    char *oldsecontext = NULL;
1106    int rc = 0;
1107
1108    if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
1109        return 0;  /* no match, but not an error */
1110
1111    if (lgetfilecon(pathname, &oldsecontext) < 0)
1112        goto err;
1113
1114    /*
1115     * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
1116     * and use pkgdir_selabel_lookup() instead. Files within those directories
1117     * have different labeling rules, based off of /seapp_contexts, and
1118     * installd is responsible for managing these labels instead of init.
1119     */
1120    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1121        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1122        if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
1123            goto err;
1124    }
1125
1126    if (strcmp(oldsecontext, secontext) != 0) {
1127        if (verbose)
1128            selinux_log(SELINUX_INFO,
1129                        "SELinux:  Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1130        if (!nochange) {
1131            if (lsetfilecon(pathname, secontext) < 0)
1132                goto err;
1133        }
1134    }
1135
1136    rc = 0;
1137
1138out:
1139    freecon(oldsecontext);
1140    freecon(secontext);
1141    return rc;
1142
1143err:
1144    selinux_log(SELINUX_ERROR,
1145                "SELinux: Could not set context for %s:  %s\n",
1146                pathname, strerror(errno));
1147    rc = -1;
1148    goto out;
1149}
1150
1151static int selinux_android_restorecon_common(const char* pathname,
1152                                             const char *seinfo,
1153                                             uid_t uid,
1154                                             unsigned int flags)
1155{
1156    bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1157    bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1158    bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1159    bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
1160    bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
1161    bool issys = strcmp(pathname, "/sys") == 0 ? true : false;
1162    bool setrestoreconlast = true;
1163    struct stat sb;
1164    FTS *fts;
1165    FTSENT *ftsent;
1166    char *const paths[2] = { __UNCONST(pathname), NULL };
1167    int ftsflags = FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
1168    int error, sverrno;
1169    char xattr_value[FC_DIGEST_SIZE];
1170    ssize_t size;
1171
1172    if (is_selinux_enabled() <= 0)
1173        return 0;
1174
1175    __selinux_once(fc_once, file_context_init);
1176
1177    if (!sehandle)
1178        return 0;
1179
1180    if (!recurse) {
1181        if (lstat(pathname, &sb) < 0)
1182            return -1;
1183
1184        return restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
1185    }
1186
1187    /*
1188     * Ignore restorecon_last on /data/data or /data/user
1189     * since their labeling is based on seapp_contexts and seinfo
1190     * assignments rather than file_contexts and is managed by
1191     * installd rather than init.
1192     */
1193    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1194        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))
1195        setrestoreconlast = false;
1196
1197    if (setrestoreconlast) {
1198        size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
1199        if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
1200            selinux_log(SELINUX_INFO,
1201                        "SELinux: Skipping restorecon_recursive(%s)\n",
1202                        pathname);
1203            return 0;
1204        }
1205    }
1206
1207    fts = fts_open(paths, ftsflags, NULL);
1208    if (!fts)
1209        return -1;
1210
1211    error = 0;
1212    while ((ftsent = fts_read(fts)) != NULL) {
1213        switch (ftsent->fts_info) {
1214        case FTS_DC:
1215            selinux_log(SELINUX_ERROR,
1216                        "SELinux:  Directory cycle on %s.\n", ftsent->fts_path);
1217            errno = ELOOP;
1218            error = -1;
1219            goto out;
1220        case FTS_DP:
1221            continue;
1222        case FTS_DNR:
1223            selinux_log(SELINUX_ERROR,
1224                        "SELinux:  Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1225            fts_set(fts, ftsent, FTS_SKIP);
1226            continue;
1227        case FTS_NS:
1228            selinux_log(SELINUX_ERROR,
1229                        "SELinux:  Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1230            fts_set(fts, ftsent, FTS_SKIP);
1231            continue;
1232        case FTS_ERR:
1233            selinux_log(SELINUX_ERROR,
1234                        "SELinux:  Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1235            fts_set(fts, ftsent, FTS_SKIP);
1236            continue;
1237        case FTS_D:
1238            if (issys && !selabel_partial_match(sehandle, ftsent->fts_path)) {
1239                fts_set(fts, ftsent, FTS_SKIP);
1240                continue;
1241            }
1242            if (!datadata &&
1243                (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
1244                 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))) {
1245                // Don't label anything below this directory.
1246                fts_set(fts, ftsent, FTS_SKIP);
1247                // but fall through and make sure we label the directory itself
1248            }
1249            /* fall through */
1250        default:
1251            error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
1252            break;
1253        }
1254    }
1255
1256    // Labeling successful. Mark the top level directory as completed.
1257    if (setrestoreconlast && !nochange && !error)
1258        setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1259
1260out:
1261    sverrno = errno;
1262    (void) fts_close(fts);
1263    errno = sverrno;
1264    return error;
1265}
1266
1267int selinux_android_restorecon(const char *file, unsigned int flags)
1268{
1269    return selinux_android_restorecon_common(file, NULL, -1, flags);
1270}
1271
1272int selinux_android_restorecon_pkgdir(const char *pkgdir,
1273                                      const char *seinfo,
1274                                      uid_t uid,
1275                                      unsigned int flags)
1276{
1277    return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1278}
1279
1280struct selabel_handle* selinux_android_file_context_handle(void)
1281{
1282    return file_context_open();
1283}
1284
1285void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1286{
1287    sehandle = (struct selabel_handle *) hndl;
1288}
1289
1290static int selinux_android_load_policy_helper(bool reload)
1291{
1292	int fd = -1, rc;
1293	struct stat sb;
1294	void *map = NULL;
1295
1296	/*
1297	 * If reloading policy and there is no /data policy or
1298	 * that /data policy has the wrong version or the /data
1299	 * policy is disabled via safe mode, then just return.
1300	 * There is no point in reloading policy from / a second time.
1301	 */
1302	if (reload && !selinux_android_use_data_policy())
1303		return 0;
1304
1305	fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
1306	if (fd < 0) {
1307		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
1308				strerror(errno));
1309		return -1;
1310	}
1311	if (fstat(fd, &sb) < 0) {
1312		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
1313				sepolicy_file[policy_index], strerror(errno));
1314		close(fd);
1315		return -1;
1316	}
1317	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1318	if (map == MAP_FAILED) {
1319		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
1320			sepolicy_file[policy_index], strerror(errno));
1321		close(fd);
1322		return -1;
1323	}
1324
1325	rc = security_load_policy(map, sb.st_size);
1326	if (rc < 0) {
1327		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
1328			strerror(errno));
1329		munmap(map, sb.st_size);
1330		close(fd);
1331		return -1;
1332	}
1333
1334	munmap(map, sb.st_size);
1335	close(fd);
1336	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
1337
1338	return 0;
1339}
1340
1341int selinux_android_reload_policy(void)
1342{
1343    return selinux_android_load_policy_helper(true);
1344}
1345
1346int selinux_android_load_policy(void)
1347{
1348	const char *mnt = SELINUXMNT;
1349	int rc;
1350	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1351	if (rc < 0) {
1352		if (errno == ENODEV) {
1353			/* SELinux not enabled in kernel */
1354			return -1;
1355		}
1356		if (errno == ENOENT) {
1357			/* Fall back to legacy mountpoint. */
1358			mnt = OLDSELINUXMNT;
1359			rc = mkdir(mnt, 0755);
1360			if (rc == -1 && errno != EEXIST) {
1361				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
1362					strerror(errno));
1363				return -1;
1364			}
1365			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1366		}
1367	}
1368	if (rc < 0) {
1369		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
1370				strerror(errno));
1371		return -1;
1372	}
1373	set_selinuxmnt(mnt);
1374
1375    return selinux_android_load_policy_helper(false);
1376}
1377