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