blob: 578fa9e44b0d48fcfc5af6563945c6aa85869196 [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>
Geremy Condra60646432013-04-10 17:58:48 -070010#include <dirent.h>
rpcraigf1724a32012-08-01 15:35:37 -040011#include <sys/mman.h>
12#include <sys/mount.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050013#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <selinux/selinux.h>
17#include <selinux/context.h>
18#include <selinux/android.h>
Stephen Smalley0ca91b32012-03-19 10:25:53 -040019#include <selinux/label.h>
Stephen Smalleye8b0fd82012-07-31 09:12:53 -040020#include <selinux/avc.h>
Stephen Smalley895b4462012-09-19 16:27:36 -040021#include <private/android_filesystem_config.h>
Stephen Smalleyd10c3432012-11-05 11:49:35 -050022#include "policy.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050023#include "callbacks.h"
24#include "selinux_internal.h"
25
26/*
27 * XXX Where should this configuration file be located?
28 * Needs to be accessible by zygote and installd when
29 * setting credentials for app processes and setting permissions
30 * on app data directories.
31 */
Stephen Smalley7446c912012-03-19 10:37:05 -040032static char const * const seapp_contexts_file[] = {
repo sync67507802013-04-26 15:49:39 -070033 "/data/security/current/seapp_contexts",
Stephen Smalley7446c912012-03-19 10:37:05 -040034 "/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[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070038 { SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
Stephen Smalley32ebfe82012-03-20 13:05:37 -040039 { SELABEL_OPT_PATH, "/file_contexts" },
40 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040041
Geremy Condra60646432013-04-10 17:58:48 -070042static const struct selinux_opt seopt_backup[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070043 { SELABEL_OPT_PATH, "/data/security/current/file_contexts_backup" },
Geremy Condra60646432013-04-10 17:58:48 -070044 { SELABEL_OPT_PATH, "/file_contexts" },
45 { 0, NULL } };
46
Stephen Smalley4a655ec2012-09-18 15:08:32 -040047static const char *const sepolicy_file[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070048 "/data/security/current/sepolicy",
rpcraigf1724a32012-08-01 15:35:37 -040049 "/sepolicy",
50 0 };
51
Stephen Smalleya8795982012-11-28 10:42:46 -050052enum levelFrom {
53 LEVELFROM_NONE,
54 LEVELFROM_APP,
55 LEVELFROM_USER,
56 LEVELFROM_ALL
57};
58
59#if DEBUG
60static char const * const levelFromName[] = {
61 "none",
62 "app",
63 "user",
64 "all"
65};
66#endif
67
Stephen Smalleyf0740362012-01-04 12:30:47 -050068struct seapp_context {
69 /* input selectors */
70 char isSystemServer;
71 char *user;
72 size_t len;
73 char prefix;
74 char *seinfo;
75 char *name;
76 /* outputs */
77 char *domain;
78 char *type;
79 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070080 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050081 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050082};
83
84static int seapp_context_cmp(const void *A, const void *B)
85{
Stephen Smalleyd23b9e02012-09-21 10:45:39 -040086 const struct seapp_context *const *sp1 = A, *const *sp2 = B;
Stephen Smalleyf0740362012-01-04 12:30:47 -050087 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
88
89 /* Give precedence to isSystemServer=true. */
90 if (s1->isSystemServer != s2->isSystemServer)
91 return (s1->isSystemServer ? -1 : 1);
92
93 /* Give precedence to a specified user= over an unspecified user=. */
94 if (s1->user && !s2->user)
95 return -1;
96 if (!s1->user && s2->user)
97 return 1;
98
99 if (s1->user) {
100 /* Give precedence to a fixed user= string over a prefix. */
101 if (s1->prefix != s2->prefix)
102 return (s2->prefix ? -1 : 1);
103
104 /* Give precedence to a longer prefix over a shorter prefix. */
105 if (s1->prefix && s1->len != s2->len)
106 return (s1->len > s2->len) ? -1 : 1;
107 }
108
109 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
110 if (s1->seinfo && !s2->seinfo)
111 return -1;
112 if (!s1->seinfo && s2->seinfo)
113 return 1;
114
115 /* Give precedence to a specified name= over an unspecified name=. */
116 if (s1->name && !s2->name)
117 return -1;
118 if (!s1->name && s2->name)
119 return 1;
120
William Roberts1b36ad02012-07-27 13:52:33 -0700121 /* Give precedence to a specified sebool= over an unspecified sebool=. */
122 if (s1->sebool && !s2->sebool)
123 return -1;
124 if (!s1->sebool && s2->sebool)
125 return 1;
126
Stephen Smalleyf0740362012-01-04 12:30:47 -0500127 /* Anything else has equal precedence. */
128 return 0;
129}
130
131static struct seapp_context **seapp_contexts = NULL;
132static int nspec = 0;
133
Stephen Smalley7446c912012-03-19 10:37:05 -0400134int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500135{
Stephen Smalley7446c912012-03-19 10:37:05 -0400136 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500137 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500138 char *token;
139 unsigned lineno;
140 struct seapp_context *cur;
141 char *p, *name = NULL, *value = NULL, *saveptr;
142 size_t len;
Stephen Smalley300bebb2013-04-16 15:33:16 -0400143 int i = 0, n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500144
Stephen Smalley7446c912012-03-19 10:37:05 -0400145 while ((fp==NULL) && seapp_contexts_file[i])
146 fp = fopen(seapp_contexts_file[i++], "r");
147
Stephen Smalleyf0740362012-01-04 12:30:47 -0500148 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400149 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
150 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500151 }
152
Stephen Smalley300bebb2013-04-16 15:33:16 -0400153 if (seapp_contexts) {
154 for (n = 0; n < nspec; n++) {
155 cur = seapp_contexts[n];
156 free(cur->user);
157 free(cur->seinfo);
158 free(cur->name);
159 free(cur->domain);
160 free(cur->type);
161 free(cur->level);
162 free(cur->sebool);
163 }
164 free(seapp_contexts);
165 }
166
Stephen Smalleyf0740362012-01-04 12:30:47 -0500167 nspec = 0;
168 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
169 p = line_buf;
170 while (isspace(*p))
171 p++;
172 if (*p == '#' || *p == 0)
173 continue;
174 nspec++;
175 }
176
177 seapp_contexts = calloc(nspec, sizeof(struct seapp_context *));
178 if (!seapp_contexts)
179 goto oom;
180
181 rewind(fp);
182 nspec = 0;
183 lineno = 1;
184 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
185 len = strlen(line_buf);
186 if (line_buf[len - 1] == '\n')
187 line_buf[len - 1] = 0;
188 p = line_buf;
189 while (isspace(*p))
190 p++;
191 if (*p == '#' || *p == 0)
192 continue;
193
194 cur = calloc(1, sizeof(struct seapp_context));
195 if (!cur)
196 goto oom;
197
198 token = strtok_r(p, " \t", &saveptr);
199 if (!token)
200 goto err;
201
202 while (1) {
203 name = token;
204 value = strchr(name, '=');
205 if (!value)
206 goto err;
207 *value++ = 0;
208
209 if (!strcasecmp(name, "isSystemServer")) {
210 if (!strcasecmp(value, "true"))
211 cur->isSystemServer = 1;
212 else if (!strcasecmp(value, "false"))
213 cur->isSystemServer = 0;
214 else {
215 goto err;
216 }
217 } else if (!strcasecmp(name, "user")) {
218 cur->user = strdup(value);
219 if (!cur->user)
220 goto oom;
221 cur->len = strlen(cur->user);
222 if (cur->user[cur->len-1] == '*')
223 cur->prefix = 1;
224 } else if (!strcasecmp(name, "seinfo")) {
225 cur->seinfo = strdup(value);
226 if (!cur->seinfo)
227 goto oom;
228 } else if (!strcasecmp(name, "name")) {
229 cur->name = strdup(value);
230 if (!cur->name)
231 goto oom;
232 } else if (!strcasecmp(name, "domain")) {
233 cur->domain = strdup(value);
234 if (!cur->domain)
235 goto oom;
236 } else if (!strcasecmp(name, "type")) {
237 cur->type = strdup(value);
238 if (!cur->type)
239 goto oom;
240 } else if (!strcasecmp(name, "levelFromUid")) {
241 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500242 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500243 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500244 cur->levelFrom = LEVELFROM_NONE;
245 else {
246 goto err;
247 }
248 } else if (!strcasecmp(name, "levelFrom")) {
249 if (!strcasecmp(value, "none"))
250 cur->levelFrom = LEVELFROM_NONE;
251 else if (!strcasecmp(value, "app"))
252 cur->levelFrom = LEVELFROM_APP;
253 else if (!strcasecmp(value, "user"))
254 cur->levelFrom = LEVELFROM_USER;
255 else if (!strcasecmp(value, "all"))
256 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500257 else {
258 goto err;
259 }
260 } else if (!strcasecmp(name, "level")) {
261 cur->level = strdup(value);
262 if (!cur->level)
263 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700264 } else if (!strcasecmp(name, "sebool")) {
265 cur->sebool = strdup(value);
266 if (!cur->sebool)
267 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500268 } else
269 goto err;
270
271 token = strtok_r(NULL, " \t", &saveptr);
272 if (!token)
273 break;
274 }
275
276 seapp_contexts[nspec] = cur;
277 nspec++;
278 lineno++;
279 }
280
281 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
282 seapp_context_cmp);
283
284#if DEBUG
285 {
286 int i;
287 for (i = 0; i < nspec; i++) {
288 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500289 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 -0700290 __FUNCTION__,
291 cur->isSystemServer ? "true" : "false", cur->user,
292 cur->seinfo, cur->name, cur->sebool, cur->domain,
293 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500294 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500295 }
296 }
297#endif
298
Stephen Smalley7446c912012-03-19 10:37:05 -0400299 ret = 0;
300
Stephen Smalleyf0740362012-01-04 12:30:47 -0500301out:
302 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400303 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500304
305err:
306 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400307 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
308 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500309 goto out;
310oom:
311 selinux_log(SELINUX_ERROR,
312 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400313 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500314 goto out;
315}
316
Stephen Smalley7446c912012-03-19 10:37:05 -0400317
318static void seapp_context_init(void)
319{
320 selinux_android_seapp_context_reload();
321}
322
Stephen Smalleyf0740362012-01-04 12:30:47 -0500323static pthread_once_t once = PTHREAD_ONCE_INIT;
324
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400325/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500326 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400327 * using the current scheme.
328 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500329#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400330
331enum seapp_kind {
332 SEAPP_TYPE,
333 SEAPP_DOMAIN
334};
335
336static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400337 uid_t uid,
338 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400339 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400340 const char *pkgname,
341 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500342{
Stephen Smalley895b4462012-09-19 16:27:36 -0400343 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700344 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400345 int i;
346 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500347 uid_t userid;
348 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500349
Stephen Smalleya8795982012-11-28 10:42:46 -0500350 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400351 appid = uid % AID_USER;
352 if (appid < AID_APP) {
353 for (n = 0; n < android_id_count; n++) {
354 if (android_ids[n].aid == appid) {
355 username = android_ids[n].name;
356 break;
357 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400358 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400359 if (!username)
360 goto err;
361 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400362 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400363 appid -= AID_APP;
364 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400365 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400366 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400367 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500368
Stephen Smalleya8795982012-11-28 10:42:46 -0500369 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400370 goto err;
371
Stephen Smalleyf0740362012-01-04 12:30:47 -0500372 for (i = 0; i < nspec; i++) {
373 cur = seapp_contexts[i];
374
Stephen Smalley895b4462012-09-19 16:27:36 -0400375 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500376 continue;
377
378 if (cur->user) {
379 if (cur->prefix) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400380 if (strncasecmp(username, cur->user, cur->len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500381 continue;
382 } else {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400383 if (strcasecmp(username, cur->user))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500384 continue;
385 }
386 }
387
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400388 if (cur->seinfo) {
389 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
390 continue;
391 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500392
393 if (cur->name) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400394 if (!pkgname || strcasecmp(pkgname, cur->name))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500395 continue;
396 }
397
Stephen Smalley895b4462012-09-19 16:27:36 -0400398 if (kind == SEAPP_TYPE && !cur->type)
399 continue;
400 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500401 continue;
402
William Roberts1b36ad02012-07-27 13:52:33 -0700403 if (cur->sebool) {
404 int value = security_get_boolean_active(cur->sebool);
405 if (value == 0)
406 continue;
407 else if (value == -1) {
408 selinux_log(SELINUX_ERROR, \
409 "Could not find boolean: %s ", cur->sebool);
410 goto err;
411 }
412 }
413
Stephen Smalley895b4462012-09-19 16:27:36 -0400414 if (kind == SEAPP_TYPE) {
415 if (context_type_set(ctx, cur->type))
416 goto oom;
417 } else if (kind == SEAPP_DOMAIN) {
418 if (context_type_set(ctx, cur->domain))
419 goto oom;
420 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500421
Stephen Smalleya8795982012-11-28 10:42:46 -0500422 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500423 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500424 switch (cur->levelFrom) {
425 case LEVELFROM_APP:
426 snprintf(level, sizeof level, "%s:c%u,c%u",
427 context_range_get(ctx), appid & 0xff,
428 256 + (appid>>8 & 0xff));
429 break;
430 case LEVELFROM_USER:
431 snprintf(level, sizeof level, "%s:c%u,c%u",
432 context_range_get(ctx),
433 512 + (userid & 0xff),
434 768 + (userid>>8 & 0xff));
435 break;
436 case LEVELFROM_ALL:
437 snprintf(level, sizeof level, "%s:c%u,c%u,c%u,c%u",
438 context_range_get(ctx), appid & 0xff,
439 256 + (appid>>8 & 0xff),
440 512 + (userid & 0xff),
441 768 + (userid>>8 & 0xff));
442 break;
443 default:
444 goto err;
445 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500446 if (context_range_set(ctx, level))
447 goto oom;
448 } else if (cur->level) {
449 if (context_range_set(ctx, cur->level))
450 goto oom;
451 }
William Roberts1b36ad02012-07-27 13:52:33 -0700452
Stephen Smalleyf0740362012-01-04 12:30:47 -0500453 break;
454 }
455
Stephen Smalley895b4462012-09-19 16:27:36 -0400456 if (kind == SEAPP_DOMAIN && i == nspec) {
457 /*
458 * No match.
459 * Fail to prevent staying in the zygote's context.
460 */
461 selinux_log(SELINUX_ERROR,
462 "%s: No match for app with uid %d, seinfo %s, name %s\n",
463 __FUNCTION__, uid, seinfo, pkgname);
464
465 if (security_getenforce() == 1)
466 goto err;
467 }
468
469 return 0;
470err:
471 return -1;
472oom:
473 return -2;
474}
475
476int selinux_android_setfilecon2(const char *pkgdir,
477 const char *pkgname,
478 const char *seinfo,
479 uid_t uid)
480{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700481 char *orig_ctx_str = NULL;
482 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400483 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700484 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400485
486 if (is_selinux_enabled() <= 0)
487 return 0;
488
489 __selinux_once(once, seapp_context_init);
490
491 rc = getfilecon(pkgdir, &ctx_str);
492 if (rc < 0)
493 goto err;
494
495 ctx = context_new(ctx_str);
496 orig_ctx_str = ctx_str;
497 if (!ctx)
498 goto oom;
499
500 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
501 if (rc == -1)
502 goto err;
503 else if (rc == -2)
504 goto oom;
505
Stephen Smalleyf0740362012-01-04 12:30:47 -0500506 ctx_str = context_str(ctx);
507 if (!ctx_str)
508 goto oom;
509
510 rc = security_check_context(ctx_str);
511 if (rc < 0)
512 goto err;
513
514 if (strcmp(ctx_str, orig_ctx_str)) {
515 rc = setfilecon(pkgdir, ctx_str);
516 if (rc < 0)
517 goto err;
518 }
519
520 rc = 0;
521out:
522 freecon(orig_ctx_str);
523 context_free(ctx);
524 return rc;
525err:
526 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
527 __FUNCTION__, pkgdir, uid, strerror(errno));
528 rc = -1;
529 goto out;
530oom:
531 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
532 rc = -1;
533 goto out;
534}
535
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400536int selinux_android_setfilecon(const char *pkgdir,
537 const char *pkgname,
538 uid_t uid)
539{
540 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
541}
542
Stephen Smalleyf0740362012-01-04 12:30:47 -0500543int selinux_android_setcontext(uid_t uid,
544 int isSystemServer,
545 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400546 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500547{
Stephen Smalley895b4462012-09-19 16:27:36 -0400548 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500549 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700550 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500551
552 if (is_selinux_enabled() <= 0)
553 return 0;
554
555 __selinux_once(once, seapp_context_init);
556
557 rc = getcon(&ctx_str);
558 if (rc)
559 goto err;
560
561 ctx = context_new(ctx_str);
562 orig_ctx_str = ctx_str;
563 if (!ctx)
564 goto oom;
565
Stephen Smalley895b4462012-09-19 16:27:36 -0400566 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
567 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500568 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400569 else if (rc == -2)
570 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500571
572 ctx_str = context_str(ctx);
573 if (!ctx_str)
574 goto oom;
575
576 rc = security_check_context(ctx_str);
577 if (rc < 0)
578 goto err;
579
580 if (strcmp(ctx_str, orig_ctx_str)) {
581 rc = setcon(ctx_str);
582 if (rc < 0)
583 goto err;
584 }
585
586 rc = 0;
587out:
588 freecon(orig_ctx_str);
589 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400590 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500591 return rc;
592err:
593 if (isSystemServer)
594 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700595 "%s: Error setting context for system server: %s\n",
596 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500597 else
598 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700599 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
600 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500601
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400602 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500603 goto out;
604oom:
605 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
606 rc = -1;
607 goto out;
608}
609
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400610static struct selabel_handle *sehandle = NULL;
611
Geremy Condra60646432013-04-10 17:58:48 -0700612static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
Stephen Smalley906742d2012-08-23 16:04:59 -0400613 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400614 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400615
Stephen Smalley906742d2012-08-23 16:04:59 -0400616 h = NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700617 while ((h == NULL) && opts[i].value) {
618 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400619 i++;
620 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400621
Geremy Condra60646432013-04-10 17:58:48 -0700622 return h;
623}
624
625static struct selabel_handle *file_context_open(void)
626{
627 struct selabel_handle *h;
628
629 h = get_selabel_handle(seopts);
630
Stephen Smalley906742d2012-08-23 16:04:59 -0400631 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700632 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
633 __FUNCTION__, strerror(errno));
634 return h;
635}
636
637static struct selabel_handle *file_context_backup_open(void)
638{
639 struct selabel_handle *h;
640
641 h = get_selabel_handle(seopt_backup);
642
643 if (!h)
644 selinux_log(SELINUX_ERROR, "%s: Error getting backup file context handle (%s)\n",
645 __FUNCTION__, strerror(errno));
Stephen Smalley906742d2012-08-23 16:04:59 -0400646 return h;
647}
648
649static void file_context_init(void)
650{
651 sehandle = file_context_open();
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400652}
653
654static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
655
656int selinux_android_restorecon(const char *pathname)
657{
658
Nick Kralevich9ca40882013-07-11 16:58:44 -0700659 char* oldcontext = NULL;
660 char* newcontext = NULL;
661 struct stat sb;
662 int ret = -1;
663
Kenny Root20f62f32012-10-22 17:09:23 -0700664 if (is_selinux_enabled() <= 0)
665 return 0;
666
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400667 __selinux_once(fc_once, file_context_init);
668
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400669 if (!sehandle)
670 goto bail;
671
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400672 if (lstat(pathname, &sb) < 0)
673 goto err;
674
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400675 if (lgetfilecon(pathname, &oldcontext) < 0)
676 goto err;
677
678 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
679 goto err;
680
681 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
682 if (lsetfilecon(pathname, newcontext) < 0)
683 goto err;
684
685 ret = 0;
686out:
687 if (oldcontext)
688 freecon(oldcontext);
689 if (newcontext)
690 freecon(newcontext);
691
692 return ret;
693
694err:
695 selinux_log(SELINUX_ERROR,
696 "%s: Error restoring context for %s (%s)\n",
697 __FUNCTION__, pathname, strerror(errno));
698
699bail:
700 ret = -1;
701 goto out;
702}
rpcraig9b100832012-07-27 06:36:59 -0400703
Geremy Condra60646432013-04-10 17:58:48 -0700704static int file_requires_fixup(const char *pathname,
Geremy Condra01cccbf2013-04-15 12:26:44 -0700705 struct selabel_handle *sehandle_old,
repo sync8c6e5f82013-05-17 12:43:53 -0700706 struct selabel_handle *sehandle_new)
Geremy Condra60646432013-04-10 17:58:48 -0700707{
708 int ret;
709 struct stat sb;
710 char *current_context, *old_context, *new_context;
711
712 ret = 0;
713 old_context = NULL;
714 new_context = NULL;
715 current_context = NULL;
716
717 if (lstat(pathname, &sb) < 0) {
718 ret = -1;
719 goto err;
720 }
721
722 if (lgetfilecon(pathname, &current_context) < 0) {
723 ret = -1;
724 goto err;
725 }
726
727 if (selabel_lookup(sehandle_old, &old_context, pathname, sb.st_mode) < 0) {
728 ret = -1;
729 goto err;
730 }
731
732 if (selabel_lookup(sehandle_new, &new_context, pathname, sb.st_mode) < 0) {
733 ret = -1;
734 goto err;
735 }
736
Geremy Condra01cccbf2013-04-15 12:26:44 -0700737 if (strstr(current_context, "unlabeled") != NULL) {
738 ret = 1;
739 goto out;
740 }
741
Geremy Condra60646432013-04-10 17:58:48 -0700742 ret = (strcmp(old_context, new_context) && !strcmp(current_context, old_context));
743 goto out;
744
745err:
746 selinux_log(SELINUX_ERROR,
747 "%s: Error comparing context for %s (%s)\n",
748 __FUNCTION__,
749 pathname,
750 strerror(errno));
751
752out:
753 if (current_context)
754 freecon(current_context);
repo sync8c6e5f82013-05-17 12:43:53 -0700755 if (new_context)
756 freecon(new_context);
Geremy Condra60646432013-04-10 17:58:48 -0700757 if (old_context)
758 freecon(old_context);
759 return ret;
760}
761
762static int fixcon_file(const char *pathname,
763 struct selabel_handle *sehandle_old,
764 struct selabel_handle *sehandle_new)
765{
766 int requires_fixup;
767
repo sync8c6e5f82013-05-17 12:43:53 -0700768 requires_fixup = file_requires_fixup(pathname, sehandle_old, sehandle_new);
Geremy Condra60646432013-04-10 17:58:48 -0700769 if (requires_fixup < 0)
770 return -1;
771
repo sync8c6e5f82013-05-17 12:43:53 -0700772 if (requires_fixup)
773 selinux_android_restorecon(pathname);
774
Geremy Condra60646432013-04-10 17:58:48 -0700775 return 0;
776}
777
778static int fixcon_recursive(const char *pathname,
779 struct selabel_handle *sehandle_old,
780 struct selabel_handle *sehandle_new)
781{
782 struct stat statresult;
783 if (lstat(pathname, &statresult) < 0)
784 return -1;
785
repo syncdae85f92013-05-17 12:44:08 -0700786 if (!S_ISDIR(statresult.st_mode))
Geremy Condra60646432013-04-10 17:58:48 -0700787 return fixcon_file(pathname, sehandle_old, sehandle_new);
788
789 DIR *dir = opendir(pathname);
790 if (dir == NULL)
791 return -1;
792
793 struct dirent *entry;
794 while ((entry = readdir(dir)) != NULL) {
Nick Kralevich397359d2013-05-06 11:48:18 -0700795 char *entryname;
Geremy Condra60646432013-04-10 17:58:48 -0700796 if (!strcmp(entry->d_name, ".."))
797 continue;
798 if (!strcmp(entry->d_name, "."))
799 continue;
Nick Kralevich397359d2013-05-06 11:48:18 -0700800 if (asprintf(&entryname, "%s/%s", pathname, entry->d_name) == -1)
801 continue;
Geremy Condra60646432013-04-10 17:58:48 -0700802 fixcon_recursive(entryname, sehandle_old, sehandle_new);
Nick Kralevich397359d2013-05-06 11:48:18 -0700803 free(entryname);
Geremy Condra60646432013-04-10 17:58:48 -0700804 }
805
806 if (closedir(dir) < 0)
807 return -1;
808
809 return fixcon_file(pathname, sehandle_old, sehandle_new);
810}
811
812int selinux_android_fixcon(const char *pathname)
813{
814 struct selabel_handle *sehandle_old, *sehandle_new;
815
816 sehandle_old = file_context_backup_open();
817 if (sehandle_old == NULL)
818 return -1;
819
820 sehandle_new = file_context_open();
821 if (sehandle_new == NULL)
822 return -1;
823
824 return fixcon_recursive(pathname, sehandle_old, sehandle_new);
825}
rpcraig9b100832012-07-27 06:36:59 -0400826
rpcraigf1724a32012-08-01 15:35:37 -0400827struct selabel_handle* selinux_android_file_context_handle(void)
828{
Geremy Condra60646432013-04-10 17:58:48 -0700829 return file_context_open();
rpcraigf1724a32012-08-01 15:35:37 -0400830}
rpcraig9b100832012-07-27 06:36:59 -0400831
rpcraigf1724a32012-08-01 15:35:37 -0400832int selinux_android_reload_policy(void)
833{
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400834 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400835 struct stat sb;
836 void *map = NULL;
837 int i = 0;
838
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400839 while (fd < 0 && sepolicy_file[i]) {
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700840 fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -0400841 i++;
842 }
843 if (fd < 0) {
844 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
845 strerror(errno));
846 return -1;
847 }
848 if (fstat(fd, &sb) < 0) {
849 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700850 sepolicy_file[i], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400851 close(fd);
852 return -1;
853 }
854 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
855 if (map == MAP_FAILED) {
856 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700857 sepolicy_file[i], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400858 close(fd);
859 return -1;
860 }
861
862 rc = security_load_policy(map, sb.st_size);
863 if (rc < 0) {
864 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
865 strerror(errno));
866 munmap(map, sb.st_size);
867 close(fd);
868 return -1;
869 }
870
871 munmap(map, sb.st_size);
872 close(fd);
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700873 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i]);
rpcraigf1724a32012-08-01 15:35:37 -0400874
875 return 0;
876}
877
878int selinux_android_load_policy(void)
879{
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500880 char *mnt = SELINUXMNT;
881 int rc;
882 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
883 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400884 if (errno == ENODEV) {
885 /* SELinux not enabled in kernel */
886 return -1;
887 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500888 if (errno == ENOENT) {
889 /* Fall back to legacy mountpoint. */
890 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800891 rc = mkdir(mnt, 0755);
892 if (rc == -1 && errno != EEXIST) {
893 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
894 strerror(errno));
895 return -1;
896 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500897 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
898 }
899 }
900 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400901 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
902 strerror(errno));
903 return -1;
904 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500905 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400906
907 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400908}