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