blob: 22edc285fb3df85434abdbd255d76881c98d2245 [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 Smalley7446c912012-03-19 10:37:05 -0400143 int i = 0, 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
153 nspec = 0;
154 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
155 p = line_buf;
156 while (isspace(*p))
157 p++;
158 if (*p == '#' || *p == 0)
159 continue;
160 nspec++;
161 }
162
163 seapp_contexts = calloc(nspec, sizeof(struct seapp_context *));
164 if (!seapp_contexts)
165 goto oom;
166
167 rewind(fp);
168 nspec = 0;
169 lineno = 1;
170 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
171 len = strlen(line_buf);
172 if (line_buf[len - 1] == '\n')
173 line_buf[len - 1] = 0;
174 p = line_buf;
175 while (isspace(*p))
176 p++;
177 if (*p == '#' || *p == 0)
178 continue;
179
180 cur = calloc(1, sizeof(struct seapp_context));
181 if (!cur)
182 goto oom;
183
184 token = strtok_r(p, " \t", &saveptr);
185 if (!token)
186 goto err;
187
188 while (1) {
189 name = token;
190 value = strchr(name, '=');
191 if (!value)
192 goto err;
193 *value++ = 0;
194
195 if (!strcasecmp(name, "isSystemServer")) {
196 if (!strcasecmp(value, "true"))
197 cur->isSystemServer = 1;
198 else if (!strcasecmp(value, "false"))
199 cur->isSystemServer = 0;
200 else {
201 goto err;
202 }
203 } else if (!strcasecmp(name, "user")) {
204 cur->user = strdup(value);
205 if (!cur->user)
206 goto oom;
207 cur->len = strlen(cur->user);
208 if (cur->user[cur->len-1] == '*')
209 cur->prefix = 1;
210 } else if (!strcasecmp(name, "seinfo")) {
211 cur->seinfo = strdup(value);
212 if (!cur->seinfo)
213 goto oom;
214 } else if (!strcasecmp(name, "name")) {
215 cur->name = strdup(value);
216 if (!cur->name)
217 goto oom;
218 } else if (!strcasecmp(name, "domain")) {
219 cur->domain = strdup(value);
220 if (!cur->domain)
221 goto oom;
222 } else if (!strcasecmp(name, "type")) {
223 cur->type = strdup(value);
224 if (!cur->type)
225 goto oom;
226 } else if (!strcasecmp(name, "levelFromUid")) {
227 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500228 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500229 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500230 cur->levelFrom = LEVELFROM_NONE;
231 else {
232 goto err;
233 }
234 } else if (!strcasecmp(name, "levelFrom")) {
235 if (!strcasecmp(value, "none"))
236 cur->levelFrom = LEVELFROM_NONE;
237 else if (!strcasecmp(value, "app"))
238 cur->levelFrom = LEVELFROM_APP;
239 else if (!strcasecmp(value, "user"))
240 cur->levelFrom = LEVELFROM_USER;
241 else if (!strcasecmp(value, "all"))
242 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500243 else {
244 goto err;
245 }
246 } else if (!strcasecmp(name, "level")) {
247 cur->level = strdup(value);
248 if (!cur->level)
249 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700250 } else if (!strcasecmp(name, "sebool")) {
251 cur->sebool = strdup(value);
252 if (!cur->sebool)
253 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500254 } else
255 goto err;
256
257 token = strtok_r(NULL, " \t", &saveptr);
258 if (!token)
259 break;
260 }
261
262 seapp_contexts[nspec] = cur;
263 nspec++;
264 lineno++;
265 }
266
267 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
268 seapp_context_cmp);
269
270#if DEBUG
271 {
272 int i;
273 for (i = 0; i < nspec; i++) {
274 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500275 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 -0700276 __FUNCTION__,
277 cur->isSystemServer ? "true" : "false", cur->user,
278 cur->seinfo, cur->name, cur->sebool, cur->domain,
279 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500280 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500281 }
282 }
283#endif
284
Stephen Smalley7446c912012-03-19 10:37:05 -0400285 ret = 0;
286
Stephen Smalleyf0740362012-01-04 12:30:47 -0500287out:
288 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400289 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500290
291err:
292 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400293 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
294 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500295 goto out;
296oom:
297 selinux_log(SELINUX_ERROR,
298 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400299 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500300 goto out;
301}
302
Stephen Smalley7446c912012-03-19 10:37:05 -0400303
304static void seapp_context_init(void)
305{
306 selinux_android_seapp_context_reload();
307}
308
Stephen Smalleyf0740362012-01-04 12:30:47 -0500309static pthread_once_t once = PTHREAD_ONCE_INIT;
310
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400311/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500312 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400313 * using the current scheme.
314 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500315#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400316
317enum seapp_kind {
318 SEAPP_TYPE,
319 SEAPP_DOMAIN
320};
321
322static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400323 uid_t uid,
324 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400325 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400326 const char *pkgname,
327 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500328{
Stephen Smalley895b4462012-09-19 16:27:36 -0400329 const char *username = NULL;
330 char *end = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500331 struct passwd *pw;
332 struct seapp_context *cur;
Stephen Smalley895b4462012-09-19 16:27:36 -0400333 int i;
334 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500335 uid_t userid;
336 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500337
Stephen Smalleya8795982012-11-28 10:42:46 -0500338 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400339 appid = uid % AID_USER;
340 if (appid < AID_APP) {
341 for (n = 0; n < android_id_count; n++) {
342 if (android_ids[n].aid == appid) {
343 username = android_ids[n].name;
344 break;
345 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400346 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400347 if (!username)
348 goto err;
349 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400350 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400351 appid -= AID_APP;
352 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400353 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400354 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400355 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500356
Stephen Smalleya8795982012-11-28 10:42:46 -0500357 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400358 goto err;
359
Stephen Smalleyf0740362012-01-04 12:30:47 -0500360 for (i = 0; i < nspec; i++) {
361 cur = seapp_contexts[i];
362
Stephen Smalley895b4462012-09-19 16:27:36 -0400363 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500364 continue;
365
366 if (cur->user) {
367 if (cur->prefix) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400368 if (strncasecmp(username, cur->user, cur->len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500369 continue;
370 } else {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400371 if (strcasecmp(username, cur->user))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500372 continue;
373 }
374 }
375
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400376 if (cur->seinfo) {
377 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
378 continue;
379 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500380
381 if (cur->name) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400382 if (!pkgname || strcasecmp(pkgname, cur->name))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500383 continue;
384 }
385
Stephen Smalley895b4462012-09-19 16:27:36 -0400386 if (kind == SEAPP_TYPE && !cur->type)
387 continue;
388 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500389 continue;
390
William Roberts1b36ad02012-07-27 13:52:33 -0700391 if (cur->sebool) {
392 int value = security_get_boolean_active(cur->sebool);
393 if (value == 0)
394 continue;
395 else if (value == -1) {
396 selinux_log(SELINUX_ERROR, \
397 "Could not find boolean: %s ", cur->sebool);
398 goto err;
399 }
400 }
401
Stephen Smalley895b4462012-09-19 16:27:36 -0400402 if (kind == SEAPP_TYPE) {
403 if (context_type_set(ctx, cur->type))
404 goto oom;
405 } else if (kind == SEAPP_DOMAIN) {
406 if (context_type_set(ctx, cur->domain))
407 goto oom;
408 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500409
Stephen Smalleya8795982012-11-28 10:42:46 -0500410 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500411 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500412 switch (cur->levelFrom) {
413 case LEVELFROM_APP:
414 snprintf(level, sizeof level, "%s:c%u,c%u",
415 context_range_get(ctx), appid & 0xff,
416 256 + (appid>>8 & 0xff));
417 break;
418 case LEVELFROM_USER:
419 snprintf(level, sizeof level, "%s:c%u,c%u",
420 context_range_get(ctx),
421 512 + (userid & 0xff),
422 768 + (userid>>8 & 0xff));
423 break;
424 case LEVELFROM_ALL:
425 snprintf(level, sizeof level, "%s:c%u,c%u,c%u,c%u",
426 context_range_get(ctx), appid & 0xff,
427 256 + (appid>>8 & 0xff),
428 512 + (userid & 0xff),
429 768 + (userid>>8 & 0xff));
430 break;
431 default:
432 goto err;
433 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500434 if (context_range_set(ctx, level))
435 goto oom;
436 } else if (cur->level) {
437 if (context_range_set(ctx, cur->level))
438 goto oom;
439 }
William Roberts1b36ad02012-07-27 13:52:33 -0700440
Stephen Smalleyf0740362012-01-04 12:30:47 -0500441 break;
442 }
443
Stephen Smalley895b4462012-09-19 16:27:36 -0400444 if (kind == SEAPP_DOMAIN && i == nspec) {
445 /*
446 * No match.
447 * Fail to prevent staying in the zygote's context.
448 */
449 selinux_log(SELINUX_ERROR,
450 "%s: No match for app with uid %d, seinfo %s, name %s\n",
451 __FUNCTION__, uid, seinfo, pkgname);
452
453 if (security_getenforce() == 1)
454 goto err;
455 }
456
457 return 0;
458err:
459 return -1;
460oom:
461 return -2;
462}
463
464int selinux_android_setfilecon2(const char *pkgdir,
465 const char *pkgname,
466 const char *seinfo,
467 uid_t uid)
468{
469 char *orig_ctx_str = NULL, *ctx_str;
470 context_t ctx = NULL;
471 int rc;
472
473 if (is_selinux_enabled() <= 0)
474 return 0;
475
476 __selinux_once(once, seapp_context_init);
477
478 rc = getfilecon(pkgdir, &ctx_str);
479 if (rc < 0)
480 goto err;
481
482 ctx = context_new(ctx_str);
483 orig_ctx_str = ctx_str;
484 if (!ctx)
485 goto oom;
486
487 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
488 if (rc == -1)
489 goto err;
490 else if (rc == -2)
491 goto oom;
492
Stephen Smalleyf0740362012-01-04 12:30:47 -0500493 ctx_str = context_str(ctx);
494 if (!ctx_str)
495 goto oom;
496
497 rc = security_check_context(ctx_str);
498 if (rc < 0)
499 goto err;
500
501 if (strcmp(ctx_str, orig_ctx_str)) {
502 rc = setfilecon(pkgdir, ctx_str);
503 if (rc < 0)
504 goto err;
505 }
506
507 rc = 0;
508out:
509 freecon(orig_ctx_str);
510 context_free(ctx);
511 return rc;
512err:
513 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
514 __FUNCTION__, pkgdir, uid, strerror(errno));
515 rc = -1;
516 goto out;
517oom:
518 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
519 rc = -1;
520 goto out;
521}
522
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400523int selinux_android_setfilecon(const char *pkgdir,
524 const char *pkgname,
525 uid_t uid)
526{
527 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
528}
529
Stephen Smalleyf0740362012-01-04 12:30:47 -0500530int selinux_android_setcontext(uid_t uid,
531 int isSystemServer,
532 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400533 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500534{
Stephen Smalley895b4462012-09-19 16:27:36 -0400535 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500536 context_t ctx = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400537 int rc;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500538
539 if (is_selinux_enabled() <= 0)
540 return 0;
541
542 __selinux_once(once, seapp_context_init);
543
544 rc = getcon(&ctx_str);
545 if (rc)
546 goto err;
547
548 ctx = context_new(ctx_str);
549 orig_ctx_str = ctx_str;
550 if (!ctx)
551 goto oom;
552
Stephen Smalley895b4462012-09-19 16:27:36 -0400553 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
554 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500555 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400556 else if (rc == -2)
557 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500558
559 ctx_str = context_str(ctx);
560 if (!ctx_str)
561 goto oom;
562
563 rc = security_check_context(ctx_str);
564 if (rc < 0)
565 goto err;
566
567 if (strcmp(ctx_str, orig_ctx_str)) {
568 rc = setcon(ctx_str);
569 if (rc < 0)
570 goto err;
571 }
572
573 rc = 0;
574out:
575 freecon(orig_ctx_str);
576 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400577 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500578 return rc;
579err:
580 if (isSystemServer)
581 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700582 "%s: Error setting context for system server: %s\n",
583 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500584 else
585 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700586 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
587 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500588
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400589 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500590 goto out;
591oom:
592 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
593 rc = -1;
594 goto out;
595}
596
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400597static struct selabel_handle *sehandle = NULL;
598
Geremy Condra60646432013-04-10 17:58:48 -0700599static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
Stephen Smalley906742d2012-08-23 16:04:59 -0400600 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400601 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400602
Stephen Smalley906742d2012-08-23 16:04:59 -0400603 h = NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700604 while ((h == NULL) && opts[i].value) {
605 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400606 i++;
607 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400608
Geremy Condra60646432013-04-10 17:58:48 -0700609 return h;
610}
611
612static struct selabel_handle *file_context_open(void)
613{
614 struct selabel_handle *h;
615
616 h = get_selabel_handle(seopts);
617
Stephen Smalley906742d2012-08-23 16:04:59 -0400618 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700619 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
620 __FUNCTION__, strerror(errno));
621 return h;
622}
623
624static struct selabel_handle *file_context_backup_open(void)
625{
626 struct selabel_handle *h;
627
628 h = get_selabel_handle(seopt_backup);
629
630 if (!h)
631 selinux_log(SELINUX_ERROR, "%s: Error getting backup file context handle (%s)\n",
632 __FUNCTION__, strerror(errno));
Stephen Smalley906742d2012-08-23 16:04:59 -0400633 return h;
634}
635
636static void file_context_init(void)
637{
638 sehandle = file_context_open();
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400639}
640
641static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
642
643int selinux_android_restorecon(const char *pathname)
644{
645
Kenny Root20f62f32012-10-22 17:09:23 -0700646 if (is_selinux_enabled() <= 0)
647 return 0;
648
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400649 __selinux_once(fc_once, file_context_init);
650
651 int ret;
652
653 if (!sehandle)
654 goto bail;
655
656 struct stat sb;
657
658 if (lstat(pathname, &sb) < 0)
659 goto err;
660
661 char *oldcontext, *newcontext;
662
663 if (lgetfilecon(pathname, &oldcontext) < 0)
664 goto err;
665
666 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
667 goto err;
668
669 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
670 if (lsetfilecon(pathname, newcontext) < 0)
671 goto err;
672
673 ret = 0;
674out:
675 if (oldcontext)
676 freecon(oldcontext);
677 if (newcontext)
678 freecon(newcontext);
679
680 return ret;
681
682err:
683 selinux_log(SELINUX_ERROR,
684 "%s: Error restoring context for %s (%s)\n",
685 __FUNCTION__, pathname, strerror(errno));
686
687bail:
688 ret = -1;
689 goto out;
690}
rpcraig9b100832012-07-27 06:36:59 -0400691
Geremy Condra60646432013-04-10 17:58:48 -0700692static int file_requires_fixup(const char *pathname,
Geremy Condra01cccbf2013-04-15 12:26:44 -0700693 struct selabel_handle *sehandle_old,
694 struct selabel_handle *sehandle_new)
Geremy Condra60646432013-04-10 17:58:48 -0700695{
696 int ret;
697 struct stat sb;
698 char *current_context, *old_context, *new_context;
699
700 ret = 0;
701 old_context = NULL;
702 new_context = NULL;
703 current_context = NULL;
704
705 if (lstat(pathname, &sb) < 0) {
706 ret = -1;
707 goto err;
708 }
709
710 if (lgetfilecon(pathname, &current_context) < 0) {
711 ret = -1;
712 goto err;
713 }
714
715 if (selabel_lookup(sehandle_old, &old_context, pathname, sb.st_mode) < 0) {
716 ret = -1;
717 goto err;
718 }
719
720 if (selabel_lookup(sehandle_new, &new_context, pathname, sb.st_mode) < 0) {
721 ret = -1;
722 goto err;
723 }
724
Geremy Condra01cccbf2013-04-15 12:26:44 -0700725 if (strstr(current_context, "unlabeled") != NULL) {
726 ret = 1;
727 goto out;
728 }
729
Geremy Condra60646432013-04-10 17:58:48 -0700730 ret = (strcmp(old_context, new_context) && !strcmp(current_context, old_context));
731 goto out;
732
733err:
734 selinux_log(SELINUX_ERROR,
735 "%s: Error comparing context for %s (%s)\n",
736 __FUNCTION__,
737 pathname,
738 strerror(errno));
739
740out:
741 if (current_context)
742 freecon(current_context);
743 if (new_context)
744 freecon(new_context);
745 if (old_context)
746 freecon(old_context);
747 return ret;
748}
749
750static int fixcon_file(const char *pathname,
751 struct selabel_handle *sehandle_old,
752 struct selabel_handle *sehandle_new)
753{
754 int requires_fixup;
755
756 requires_fixup = file_requires_fixup(pathname, sehandle_old, sehandle_new);
757 if (requires_fixup < 0)
758 return -1;
759
760 if (requires_fixup)
761 selinux_android_restorecon(pathname);
762
763 return 0;
764}
765
766static int fixcon_recursive(const char *pathname,
767 struct selabel_handle *sehandle_old,
768 struct selabel_handle *sehandle_new)
769{
770 struct stat statresult;
771 if (lstat(pathname, &statresult) < 0)
772 return -1;
773
774 if (!S_ISDIR(statresult.st_mode))
775 return fixcon_file(pathname, sehandle_old, sehandle_new);
776
777 DIR *dir = opendir(pathname);
778 if (dir == NULL)
779 return -1;
780
781 struct dirent *entry;
782 while ((entry = readdir(dir)) != NULL) {
783 char entryname[PATH_MAX];
784 if (!strcmp(entry->d_name, ".."))
785 continue;
786 if (!strcmp(entry->d_name, "."))
787 continue;
788 sprintf(entryname, "%s/%s", pathname, entry->d_name);
789 fixcon_recursive(entryname, sehandle_old, sehandle_new);
790 }
791
792 if (closedir(dir) < 0)
793 return -1;
794
795 return fixcon_file(pathname, sehandle_old, sehandle_new);
796}
797
798int selinux_android_fixcon(const char *pathname)
799{
800 struct selabel_handle *sehandle_old, *sehandle_new;
801
802 sehandle_old = file_context_backup_open();
803 if (sehandle_old == NULL)
804 return -1;
805
806 sehandle_new = file_context_open();
807 if (sehandle_new == NULL)
808 return -1;
809
810 return fixcon_recursive(pathname, sehandle_old, sehandle_new);
811}
rpcraig9b100832012-07-27 06:36:59 -0400812
rpcraigf1724a32012-08-01 15:35:37 -0400813struct selabel_handle* selinux_android_file_context_handle(void)
814{
Geremy Condra60646432013-04-10 17:58:48 -0700815 return file_context_open();
rpcraigf1724a32012-08-01 15:35:37 -0400816}
rpcraig9b100832012-07-27 06:36:59 -0400817
rpcraigf1724a32012-08-01 15:35:37 -0400818int selinux_android_reload_policy(void)
819{
820 char path[PATH_MAX];
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400821 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400822 struct stat sb;
823 void *map = NULL;
824 int i = 0;
825
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400826 while (fd < 0 && sepolicy_file[i]) {
827 snprintf(path, sizeof(path), "%s",
828 sepolicy_file[i]);
rpcraigf1724a32012-08-01 15:35:37 -0400829 fd = open(path, O_RDONLY);
rpcraigf1724a32012-08-01 15:35:37 -0400830 i++;
831 }
832 if (fd < 0) {
833 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
834 strerror(errno));
835 return -1;
836 }
837 if (fstat(fd, &sb) < 0) {
838 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
839 path, strerror(errno));
840 close(fd);
841 return -1;
842 }
843 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
844 if (map == MAP_FAILED) {
845 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
846 path, strerror(errno));
847 close(fd);
848 return -1;
849 }
850
851 rc = security_load_policy(map, sb.st_size);
852 if (rc < 0) {
853 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
854 strerror(errno));
855 munmap(map, sb.st_size);
856 close(fd);
857 return -1;
858 }
859
860 munmap(map, sb.st_size);
861 close(fd);
862 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", path);
863
864 return 0;
865}
866
867int selinux_android_load_policy(void)
868{
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500869 char *mnt = SELINUXMNT;
870 int rc;
871 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
872 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400873 if (errno == ENODEV) {
874 /* SELinux not enabled in kernel */
875 return -1;
876 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500877 if (errno == ENOENT) {
878 /* Fall back to legacy mountpoint. */
879 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800880 rc = mkdir(mnt, 0755);
881 if (rc == -1 && errno != EEXIST) {
882 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
883 strerror(errno));
884 return -1;
885 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500886 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
887 }
888 }
889 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400890 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
891 strerror(errno));
892 return -1;
893 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500894 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400895
896 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400897}