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