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