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