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