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