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