blob: 8027cd4454944b796d05f3d36296ca077e9f7f56 [file] [log] [blame]
Stephen Smalleyf0740362012-01-04 12:30:47 -05001#include <sys/types.h>
2#include <unistd.h>
3#include <string.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <ctype.h>
7#include <errno.h>
8#include <pwd.h>
9#include <grp.h>
rpcraigf1724a32012-08-01 15:35:37 -040010#include <sys/mman.h>
11#include <sys/mount.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050012#include <sys/types.h>
13#include <sys/stat.h>
14#include <fcntl.h>
15#include <selinux/selinux.h>
16#include <selinux/context.h>
17#include <selinux/android.h>
Stephen Smalley0ca91b32012-03-19 10:25:53 -040018#include <selinux/label.h>
Stephen Smalleye8b0fd82012-07-31 09:12:53 -040019#include <selinux/avc.h>
Stephen Smalley895b4462012-09-19 16:27:36 -040020#include <private/android_filesystem_config.h>
Stephen Smalleyd10c3432012-11-05 11:49:35 -050021#include "policy.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050022#include "callbacks.h"
23#include "selinux_internal.h"
24
25/*
26 * XXX Where should this configuration file be located?
27 * Needs to be accessible by zygote and installd when
28 * setting credentials for app processes and setting permissions
29 * on app data directories.
30 */
Stephen Smalley7446c912012-03-19 10:37:05 -040031static char const * const seapp_contexts_file[] = {
William Roberts77e151b2013-01-23 14:01:14 -080032 "/data/security/seapp_contexts",
Stephen Smalley7446c912012-03-19 10:37:05 -040033 "/data/system/seapp_contexts",
34 "/seapp_contexts",
35 0 };
Stephen Smalleyf0740362012-01-04 12:30:47 -050036
Stephen Smalley32ebfe82012-03-20 13:05:37 -040037static const struct selinux_opt seopts[] = {
William Roberts77e151b2013-01-23 14:01:14 -080038 { SELABEL_OPT_PATH, "/data/security/file_contexts" },
Stephen Smalley32ebfe82012-03-20 13:05:37 -040039 { SELABEL_OPT_PATH, "/data/system/file_contexts" },
40 { SELABEL_OPT_PATH, "/file_contexts" },
41 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040042
Stephen Smalley4a655ec2012-09-18 15:08:32 -040043static const char *const sepolicy_file[] = {
William Roberts77e151b2013-01-23 14:01:14 -080044 "/data/security/sepolicy",
rpcraigf1724a32012-08-01 15:35:37 -040045 "/data/system/sepolicy",
46 "/sepolicy",
47 0 };
48
Stephen Smalleya8795982012-11-28 10:42:46 -050049enum levelFrom {
50 LEVELFROM_NONE,
51 LEVELFROM_APP,
52 LEVELFROM_USER,
53 LEVELFROM_ALL
54};
55
56#if DEBUG
57static char const * const levelFromName[] = {
58 "none",
59 "app",
60 "user",
61 "all"
62};
63#endif
64
Stephen Smalleyf0740362012-01-04 12:30:47 -050065struct seapp_context {
66 /* input selectors */
67 char isSystemServer;
68 char *user;
69 size_t len;
70 char prefix;
71 char *seinfo;
72 char *name;
73 /* outputs */
74 char *domain;
75 char *type;
76 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070077 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050078 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050079};
80
81static int seapp_context_cmp(const void *A, const void *B)
82{
Stephen Smalleyd23b9e02012-09-21 10:45:39 -040083 const struct seapp_context *const *sp1 = A, *const *sp2 = B;
Stephen Smalleyf0740362012-01-04 12:30:47 -050084 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
85
86 /* Give precedence to isSystemServer=true. */
87 if (s1->isSystemServer != s2->isSystemServer)
88 return (s1->isSystemServer ? -1 : 1);
89
90 /* Give precedence to a specified user= over an unspecified user=. */
91 if (s1->user && !s2->user)
92 return -1;
93 if (!s1->user && s2->user)
94 return 1;
95
96 if (s1->user) {
97 /* Give precedence to a fixed user= string over a prefix. */
98 if (s1->prefix != s2->prefix)
99 return (s2->prefix ? -1 : 1);
100
101 /* Give precedence to a longer prefix over a shorter prefix. */
102 if (s1->prefix && s1->len != s2->len)
103 return (s1->len > s2->len) ? -1 : 1;
104 }
105
106 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
107 if (s1->seinfo && !s2->seinfo)
108 return -1;
109 if (!s1->seinfo && s2->seinfo)
110 return 1;
111
112 /* Give precedence to a specified name= over an unspecified name=. */
113 if (s1->name && !s2->name)
114 return -1;
115 if (!s1->name && s2->name)
116 return 1;
117
William Roberts1b36ad02012-07-27 13:52:33 -0700118 /* Give precedence to a specified sebool= over an unspecified sebool=. */
119 if (s1->sebool && !s2->sebool)
120 return -1;
121 if (!s1->sebool && s2->sebool)
122 return 1;
123
Stephen Smalleyf0740362012-01-04 12:30:47 -0500124 /* Anything else has equal precedence. */
125 return 0;
126}
127
128static struct seapp_context **seapp_contexts = NULL;
129static int nspec = 0;
130
Stephen Smalley7446c912012-03-19 10:37:05 -0400131int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500132{
Stephen Smalley7446c912012-03-19 10:37:05 -0400133 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500134 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500135 char *token;
136 unsigned lineno;
137 struct seapp_context *cur;
138 char *p, *name = NULL, *value = NULL, *saveptr;
139 size_t len;
Stephen Smalley7446c912012-03-19 10:37:05 -0400140 int i = 0, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500141
Stephen Smalley7446c912012-03-19 10:37:05 -0400142 while ((fp==NULL) && seapp_contexts_file[i])
143 fp = fopen(seapp_contexts_file[i++], "r");
144
Stephen Smalleyf0740362012-01-04 12:30:47 -0500145 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400146 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
147 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500148 }
149
150 nspec = 0;
151 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
152 p = line_buf;
153 while (isspace(*p))
154 p++;
155 if (*p == '#' || *p == 0)
156 continue;
157 nspec++;
158 }
159
160 seapp_contexts = calloc(nspec, sizeof(struct seapp_context *));
161 if (!seapp_contexts)
162 goto oom;
163
164 rewind(fp);
165 nspec = 0;
166 lineno = 1;
167 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
168 len = strlen(line_buf);
169 if (line_buf[len - 1] == '\n')
170 line_buf[len - 1] = 0;
171 p = line_buf;
172 while (isspace(*p))
173 p++;
174 if (*p == '#' || *p == 0)
175 continue;
176
177 cur = calloc(1, sizeof(struct seapp_context));
178 if (!cur)
179 goto oom;
180
181 token = strtok_r(p, " \t", &saveptr);
182 if (!token)
183 goto err;
184
185 while (1) {
186 name = token;
187 value = strchr(name, '=');
188 if (!value)
189 goto err;
190 *value++ = 0;
191
192 if (!strcasecmp(name, "isSystemServer")) {
193 if (!strcasecmp(value, "true"))
194 cur->isSystemServer = 1;
195 else if (!strcasecmp(value, "false"))
196 cur->isSystemServer = 0;
197 else {
198 goto err;
199 }
200 } else if (!strcasecmp(name, "user")) {
201 cur->user = strdup(value);
202 if (!cur->user)
203 goto oom;
204 cur->len = strlen(cur->user);
205 if (cur->user[cur->len-1] == '*')
206 cur->prefix = 1;
207 } else if (!strcasecmp(name, "seinfo")) {
208 cur->seinfo = strdup(value);
209 if (!cur->seinfo)
210 goto oom;
211 } else if (!strcasecmp(name, "name")) {
212 cur->name = strdup(value);
213 if (!cur->name)
214 goto oom;
215 } else if (!strcasecmp(name, "domain")) {
216 cur->domain = strdup(value);
217 if (!cur->domain)
218 goto oom;
219 } else if (!strcasecmp(name, "type")) {
220 cur->type = strdup(value);
221 if (!cur->type)
222 goto oom;
223 } else if (!strcasecmp(name, "levelFromUid")) {
224 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500225 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500226 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500227 cur->levelFrom = LEVELFROM_NONE;
228 else {
229 goto err;
230 }
231 } else if (!strcasecmp(name, "levelFrom")) {
232 if (!strcasecmp(value, "none"))
233 cur->levelFrom = LEVELFROM_NONE;
234 else if (!strcasecmp(value, "app"))
235 cur->levelFrom = LEVELFROM_APP;
236 else if (!strcasecmp(value, "user"))
237 cur->levelFrom = LEVELFROM_USER;
238 else if (!strcasecmp(value, "all"))
239 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500240 else {
241 goto err;
242 }
243 } else if (!strcasecmp(name, "level")) {
244 cur->level = strdup(value);
245 if (!cur->level)
246 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700247 } else if (!strcasecmp(name, "sebool")) {
248 cur->sebool = strdup(value);
249 if (!cur->sebool)
250 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500251 } else
252 goto err;
253
254 token = strtok_r(NULL, " \t", &saveptr);
255 if (!token)
256 break;
257 }
258
259 seapp_contexts[nspec] = cur;
260 nspec++;
261 lineno++;
262 }
263
264 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
265 seapp_context_cmp);
266
267#if DEBUG
268 {
269 int i;
270 for (i = 0; i < nspec; i++) {
271 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500272 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s user=%s seinfo=%s name=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s",
William Roberts1b36ad02012-07-27 13:52:33 -0700273 __FUNCTION__,
274 cur->isSystemServer ? "true" : "false", cur->user,
275 cur->seinfo, cur->name, cur->sebool, cur->domain,
276 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500277 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500278 }
279 }
280#endif
281
Stephen Smalley7446c912012-03-19 10:37:05 -0400282 ret = 0;
283
Stephen Smalleyf0740362012-01-04 12:30:47 -0500284out:
285 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400286 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500287
288err:
289 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400290 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
291 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500292 goto out;
293oom:
294 selinux_log(SELINUX_ERROR,
295 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400296 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500297 goto out;
298}
299
Stephen Smalley7446c912012-03-19 10:37:05 -0400300
301static void seapp_context_init(void)
302{
303 selinux_android_seapp_context_reload();
304}
305
Stephen Smalleyf0740362012-01-04 12:30:47 -0500306static pthread_once_t once = PTHREAD_ONCE_INIT;
307
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400308/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500309 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400310 * using the current scheme.
311 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500312#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400313
314enum seapp_kind {
315 SEAPP_TYPE,
316 SEAPP_DOMAIN
317};
318
319static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400320 uid_t uid,
321 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400322 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400323 const char *pkgname,
324 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500325{
Stephen Smalley895b4462012-09-19 16:27:36 -0400326 const char *username = NULL;
327 char *end = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500328 struct passwd *pw;
329 struct seapp_context *cur;
Stephen Smalley895b4462012-09-19 16:27:36 -0400330 int i;
331 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500332 uid_t userid;
333 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500334
Stephen Smalleya8795982012-11-28 10:42:46 -0500335 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400336 appid = uid % AID_USER;
337 if (appid < AID_APP) {
338 for (n = 0; n < android_id_count; n++) {
339 if (android_ids[n].aid == appid) {
340 username = android_ids[n].name;
341 break;
342 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400343 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400344 if (!username)
345 goto err;
346 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400347 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400348 appid -= AID_APP;
349 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400350 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400351 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400352 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500353
Stephen Smalleya8795982012-11-28 10:42:46 -0500354 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400355 goto err;
356
Stephen Smalleyf0740362012-01-04 12:30:47 -0500357 for (i = 0; i < nspec; i++) {
358 cur = seapp_contexts[i];
359
Stephen Smalley895b4462012-09-19 16:27:36 -0400360 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500361 continue;
362
363 if (cur->user) {
364 if (cur->prefix) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400365 if (strncasecmp(username, cur->user, cur->len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500366 continue;
367 } else {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400368 if (strcasecmp(username, cur->user))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500369 continue;
370 }
371 }
372
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400373 if (cur->seinfo) {
374 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
375 continue;
376 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500377
378 if (cur->name) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400379 if (!pkgname || strcasecmp(pkgname, cur->name))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500380 continue;
381 }
382
Stephen Smalley895b4462012-09-19 16:27:36 -0400383 if (kind == SEAPP_TYPE && !cur->type)
384 continue;
385 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500386 continue;
387
William Roberts1b36ad02012-07-27 13:52:33 -0700388 if (cur->sebool) {
389 int value = security_get_boolean_active(cur->sebool);
390 if (value == 0)
391 continue;
392 else if (value == -1) {
393 selinux_log(SELINUX_ERROR, \
394 "Could not find boolean: %s ", cur->sebool);
395 goto err;
396 }
397 }
398
Stephen Smalley895b4462012-09-19 16:27:36 -0400399 if (kind == SEAPP_TYPE) {
400 if (context_type_set(ctx, cur->type))
401 goto oom;
402 } else if (kind == SEAPP_DOMAIN) {
403 if (context_type_set(ctx, cur->domain))
404 goto oom;
405 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500406
Stephen Smalleya8795982012-11-28 10:42:46 -0500407 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500408 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500409 switch (cur->levelFrom) {
410 case LEVELFROM_APP:
411 snprintf(level, sizeof level, "%s:c%u,c%u",
412 context_range_get(ctx), appid & 0xff,
413 256 + (appid>>8 & 0xff));
414 break;
415 case LEVELFROM_USER:
416 snprintf(level, sizeof level, "%s:c%u,c%u",
417 context_range_get(ctx),
418 512 + (userid & 0xff),
419 768 + (userid>>8 & 0xff));
420 break;
421 case LEVELFROM_ALL:
422 snprintf(level, sizeof level, "%s:c%u,c%u,c%u,c%u",
423 context_range_get(ctx), appid & 0xff,
424 256 + (appid>>8 & 0xff),
425 512 + (userid & 0xff),
426 768 + (userid>>8 & 0xff));
427 break;
428 default:
429 goto err;
430 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500431 if (context_range_set(ctx, level))
432 goto oom;
433 } else if (cur->level) {
434 if (context_range_set(ctx, cur->level))
435 goto oom;
436 }
William Roberts1b36ad02012-07-27 13:52:33 -0700437
Stephen Smalleyf0740362012-01-04 12:30:47 -0500438 break;
439 }
440
Stephen Smalley895b4462012-09-19 16:27:36 -0400441 if (kind == SEAPP_DOMAIN && i == nspec) {
442 /*
443 * No match.
444 * Fail to prevent staying in the zygote's context.
445 */
446 selinux_log(SELINUX_ERROR,
447 "%s: No match for app with uid %d, seinfo %s, name %s\n",
448 __FUNCTION__, uid, seinfo, pkgname);
449
450 if (security_getenforce() == 1)
451 goto err;
452 }
453
454 return 0;
455err:
456 return -1;
457oom:
458 return -2;
459}
460
461int selinux_android_setfilecon2(const char *pkgdir,
462 const char *pkgname,
463 const char *seinfo,
464 uid_t uid)
465{
466 char *orig_ctx_str = NULL, *ctx_str;
467 context_t ctx = NULL;
468 int rc;
469
470 if (is_selinux_enabled() <= 0)
471 return 0;
472
473 __selinux_once(once, seapp_context_init);
474
475 rc = getfilecon(pkgdir, &ctx_str);
476 if (rc < 0)
477 goto err;
478
479 ctx = context_new(ctx_str);
480 orig_ctx_str = ctx_str;
481 if (!ctx)
482 goto oom;
483
484 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
485 if (rc == -1)
486 goto err;
487 else if (rc == -2)
488 goto oom;
489
Stephen Smalleyf0740362012-01-04 12:30:47 -0500490 ctx_str = context_str(ctx);
491 if (!ctx_str)
492 goto oom;
493
494 rc = security_check_context(ctx_str);
495 if (rc < 0)
496 goto err;
497
498 if (strcmp(ctx_str, orig_ctx_str)) {
499 rc = setfilecon(pkgdir, ctx_str);
500 if (rc < 0)
501 goto err;
502 }
503
504 rc = 0;
505out:
506 freecon(orig_ctx_str);
507 context_free(ctx);
508 return rc;
509err:
510 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
511 __FUNCTION__, pkgdir, uid, strerror(errno));
512 rc = -1;
513 goto out;
514oom:
515 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
516 rc = -1;
517 goto out;
518}
519
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400520int selinux_android_setfilecon(const char *pkgdir,
521 const char *pkgname,
522 uid_t uid)
523{
524 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
525}
526
Stephen Smalleyf0740362012-01-04 12:30:47 -0500527int selinux_android_setcontext(uid_t uid,
528 int isSystemServer,
529 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400530 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500531{
Stephen Smalley895b4462012-09-19 16:27:36 -0400532 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500533 context_t ctx = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400534 int rc;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500535
536 if (is_selinux_enabled() <= 0)
537 return 0;
538
539 __selinux_once(once, seapp_context_init);
540
541 rc = getcon(&ctx_str);
542 if (rc)
543 goto err;
544
545 ctx = context_new(ctx_str);
546 orig_ctx_str = ctx_str;
547 if (!ctx)
548 goto oom;
549
Stephen Smalley895b4462012-09-19 16:27:36 -0400550 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
551 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500552 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400553 else if (rc == -2)
554 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500555
556 ctx_str = context_str(ctx);
557 if (!ctx_str)
558 goto oom;
559
560 rc = security_check_context(ctx_str);
561 if (rc < 0)
562 goto err;
563
564 if (strcmp(ctx_str, orig_ctx_str)) {
565 rc = setcon(ctx_str);
566 if (rc < 0)
567 goto err;
568 }
569
570 rc = 0;
571out:
572 freecon(orig_ctx_str);
573 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400574 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500575 return rc;
576err:
577 if (isSystemServer)
578 selinux_log(SELINUX_ERROR,
579 "%s: Error setting context for system server: %s\n",
580 __FUNCTION__, strerror(errno));
581 else
582 selinux_log(SELINUX_ERROR,
583 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
584 __FUNCTION__, uid, seinfo, strerror(errno));
585
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400586 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500587 goto out;
588oom:
589 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
590 rc = -1;
591 goto out;
592}
593
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400594static struct selabel_handle *sehandle = NULL;
595
Stephen Smalley906742d2012-08-23 16:04:59 -0400596static struct selabel_handle *file_context_open(void)
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400597{
Stephen Smalley906742d2012-08-23 16:04:59 -0400598 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400599 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400600
Stephen Smalley906742d2012-08-23 16:04:59 -0400601 h = NULL;
602 while ((h == NULL) && seopts[i].value) {
603 h = selabel_open(SELABEL_CTX_FILE, &seopts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400604 i++;
605 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400606
Stephen Smalley906742d2012-08-23 16:04:59 -0400607 if (!h)
rpcraigf1724a32012-08-01 15:35:37 -0400608 selinux_log(SELINUX_ERROR, "%s: Error getting sehandle label (%s)\n",
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400609 __FUNCTION__, strerror(errno));
Stephen Smalley906742d2012-08-23 16:04:59 -0400610 return h;
611}
612
613static void file_context_init(void)
614{
615 sehandle = file_context_open();
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400616}
617
618static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
619
620int selinux_android_restorecon(const char *pathname)
621{
622
Kenny Root20f62f32012-10-22 17:09:23 -0700623 if (is_selinux_enabled() <= 0)
624 return 0;
625
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400626 __selinux_once(fc_once, file_context_init);
627
628 int ret;
629
630 if (!sehandle)
631 goto bail;
632
633 struct stat sb;
634
635 if (lstat(pathname, &sb) < 0)
636 goto err;
637
638 char *oldcontext, *newcontext;
639
640 if (lgetfilecon(pathname, &oldcontext) < 0)
641 goto err;
642
643 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
644 goto err;
645
646 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
647 if (lsetfilecon(pathname, newcontext) < 0)
648 goto err;
649
650 ret = 0;
651out:
652 if (oldcontext)
653 freecon(oldcontext);
654 if (newcontext)
655 freecon(newcontext);
656
657 return ret;
658
659err:
660 selinux_log(SELINUX_ERROR,
661 "%s: Error restoring context for %s (%s)\n",
662 __FUNCTION__, pathname, strerror(errno));
663
664bail:
665 ret = -1;
666 goto out;
667}
rpcraig9b100832012-07-27 06:36:59 -0400668
669
rpcraigf1724a32012-08-01 15:35:37 -0400670struct selabel_handle* selinux_android_file_context_handle(void)
671{
Stephen Smalley906742d2012-08-23 16:04:59 -0400672 return file_context_open();
rpcraigf1724a32012-08-01 15:35:37 -0400673}
rpcraig9b100832012-07-27 06:36:59 -0400674
rpcraigf1724a32012-08-01 15:35:37 -0400675int selinux_android_reload_policy(void)
676{
677 char path[PATH_MAX];
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400678 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400679 struct stat sb;
680 void *map = NULL;
681 int i = 0;
682
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400683 while (fd < 0 && sepolicy_file[i]) {
684 snprintf(path, sizeof(path), "%s",
685 sepolicy_file[i]);
rpcraigf1724a32012-08-01 15:35:37 -0400686 fd = open(path, O_RDONLY);
rpcraigf1724a32012-08-01 15:35:37 -0400687 i++;
688 }
689 if (fd < 0) {
690 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
691 strerror(errno));
692 return -1;
693 }
694 if (fstat(fd, &sb) < 0) {
695 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
696 path, strerror(errno));
697 close(fd);
698 return -1;
699 }
700 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
701 if (map == MAP_FAILED) {
702 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
703 path, strerror(errno));
704 close(fd);
705 return -1;
706 }
707
708 rc = security_load_policy(map, sb.st_size);
709 if (rc < 0) {
710 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
711 strerror(errno));
712 munmap(map, sb.st_size);
713 close(fd);
714 return -1;
715 }
716
717 munmap(map, sb.st_size);
718 close(fd);
719 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", path);
720
721 return 0;
722}
723
724int selinux_android_load_policy(void)
725{
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500726 char *mnt = SELINUXMNT;
727 int rc;
728 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
729 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400730 if (errno == ENODEV) {
731 /* SELinux not enabled in kernel */
732 return -1;
733 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500734 if (errno == ENOENT) {
735 /* Fall back to legacy mountpoint. */
736 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800737 rc = mkdir(mnt, 0755);
738 if (rc == -1 && errno != EEXIST) {
739 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
740 strerror(errno));
741 return -1;
742 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500743 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
744 }
745 }
746 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400747 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
748 strerror(errno));
749 return -1;
750 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500751 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400752
753 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400754}