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