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