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