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