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