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