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