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