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