blob: af6c79c2f0230c289259040b2bd0b6a0ff0462b1 [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 Smalleyf0740362012-01-04 12:30:47 -050020#include "callbacks.h"
21#include "selinux_internal.h"
22
23/*
24 * XXX Where should this configuration file be located?
25 * Needs to be accessible by zygote and installd when
26 * setting credentials for app processes and setting permissions
27 * on app data directories.
28 */
Stephen Smalley7446c912012-03-19 10:37:05 -040029static char const * const seapp_contexts_file[] = {
30 "/data/system/seapp_contexts",
31 "/seapp_contexts",
32 0 };
Stephen Smalleyf0740362012-01-04 12:30:47 -050033
Stephen Smalley32ebfe82012-03-20 13:05:37 -040034static const struct selinux_opt seopts[] = {
35 { SELABEL_OPT_PATH, "/data/system/file_contexts" },
36 { SELABEL_OPT_PATH, "/file_contexts" },
37 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040038
Stephen Smalley4a655ec2012-09-18 15:08:32 -040039static const char *const sepolicy_file[] = {
rpcraigf1724a32012-08-01 15:35:37 -040040 "/data/system/sepolicy",
41 "/sepolicy",
42 0 };
43
Stephen Smalleyf0740362012-01-04 12:30:47 -050044struct seapp_context {
45 /* input selectors */
46 char isSystemServer;
47 char *user;
48 size_t len;
49 char prefix;
50 char *seinfo;
51 char *name;
52 /* outputs */
53 char *domain;
54 char *type;
55 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070056 char *sebool;
Stephen Smalleyf0740362012-01-04 12:30:47 -050057 char levelFromUid;
58};
59
60static int seapp_context_cmp(const void *A, const void *B)
61{
62 const struct seapp_context **sp1 = A, **sp2 = B;
63 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
64
65 /* Give precedence to isSystemServer=true. */
66 if (s1->isSystemServer != s2->isSystemServer)
67 return (s1->isSystemServer ? -1 : 1);
68
69 /* Give precedence to a specified user= over an unspecified user=. */
70 if (s1->user && !s2->user)
71 return -1;
72 if (!s1->user && s2->user)
73 return 1;
74
75 if (s1->user) {
76 /* Give precedence to a fixed user= string over a prefix. */
77 if (s1->prefix != s2->prefix)
78 return (s2->prefix ? -1 : 1);
79
80 /* Give precedence to a longer prefix over a shorter prefix. */
81 if (s1->prefix && s1->len != s2->len)
82 return (s1->len > s2->len) ? -1 : 1;
83 }
84
85 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
86 if (s1->seinfo && !s2->seinfo)
87 return -1;
88 if (!s1->seinfo && s2->seinfo)
89 return 1;
90
91 /* Give precedence to a specified name= over an unspecified name=. */
92 if (s1->name && !s2->name)
93 return -1;
94 if (!s1->name && s2->name)
95 return 1;
96
William Roberts1b36ad02012-07-27 13:52:33 -070097 /* Give precedence to a specified sebool= over an unspecified sebool=. */
98 if (s1->sebool && !s2->sebool)
99 return -1;
100 if (!s1->sebool && s2->sebool)
101 return 1;
102
Stephen Smalleyf0740362012-01-04 12:30:47 -0500103 /* Anything else has equal precedence. */
104 return 0;
105}
106
107static struct seapp_context **seapp_contexts = NULL;
108static int nspec = 0;
109
Stephen Smalley7446c912012-03-19 10:37:05 -0400110int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500111{
Stephen Smalley7446c912012-03-19 10:37:05 -0400112 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500113 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500114 char *token;
115 unsigned lineno;
116 struct seapp_context *cur;
117 char *p, *name = NULL, *value = NULL, *saveptr;
118 size_t len;
Stephen Smalley7446c912012-03-19 10:37:05 -0400119 int i = 0, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500120
Stephen Smalley7446c912012-03-19 10:37:05 -0400121 while ((fp==NULL) && seapp_contexts_file[i])
122 fp = fopen(seapp_contexts_file[i++], "r");
123
Stephen Smalleyf0740362012-01-04 12:30:47 -0500124 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400125 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
126 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500127 }
128
129 nspec = 0;
130 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
131 p = line_buf;
132 while (isspace(*p))
133 p++;
134 if (*p == '#' || *p == 0)
135 continue;
136 nspec++;
137 }
138
139 seapp_contexts = calloc(nspec, sizeof(struct seapp_context *));
140 if (!seapp_contexts)
141 goto oom;
142
143 rewind(fp);
144 nspec = 0;
145 lineno = 1;
146 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
147 len = strlen(line_buf);
148 if (line_buf[len - 1] == '\n')
149 line_buf[len - 1] = 0;
150 p = line_buf;
151 while (isspace(*p))
152 p++;
153 if (*p == '#' || *p == 0)
154 continue;
155
156 cur = calloc(1, sizeof(struct seapp_context));
157 if (!cur)
158 goto oom;
159
160 token = strtok_r(p, " \t", &saveptr);
161 if (!token)
162 goto err;
163
164 while (1) {
165 name = token;
166 value = strchr(name, '=');
167 if (!value)
168 goto err;
169 *value++ = 0;
170
171 if (!strcasecmp(name, "isSystemServer")) {
172 if (!strcasecmp(value, "true"))
173 cur->isSystemServer = 1;
174 else if (!strcasecmp(value, "false"))
175 cur->isSystemServer = 0;
176 else {
177 goto err;
178 }
179 } else if (!strcasecmp(name, "user")) {
180 cur->user = strdup(value);
181 if (!cur->user)
182 goto oom;
183 cur->len = strlen(cur->user);
184 if (cur->user[cur->len-1] == '*')
185 cur->prefix = 1;
186 } else if (!strcasecmp(name, "seinfo")) {
187 cur->seinfo = strdup(value);
188 if (!cur->seinfo)
189 goto oom;
190 } else if (!strcasecmp(name, "name")) {
191 cur->name = strdup(value);
192 if (!cur->name)
193 goto oom;
194 } else if (!strcasecmp(name, "domain")) {
195 cur->domain = strdup(value);
196 if (!cur->domain)
197 goto oom;
198 } else if (!strcasecmp(name, "type")) {
199 cur->type = strdup(value);
200 if (!cur->type)
201 goto oom;
202 } else if (!strcasecmp(name, "levelFromUid")) {
203 if (!strcasecmp(value, "true"))
204 cur->levelFromUid = 1;
205 else if (!strcasecmp(value, "false"))
206 cur->levelFromUid = 0;
207 else {
208 goto err;
209 }
210 } else if (!strcasecmp(name, "level")) {
211 cur->level = strdup(value);
212 if (!cur->level)
213 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700214 } else if (!strcasecmp(name, "sebool")) {
215 cur->sebool = strdup(value);
216 if (!cur->sebool)
217 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500218 } else
219 goto err;
220
221 token = strtok_r(NULL, " \t", &saveptr);
222 if (!token)
223 break;
224 }
225
226 seapp_contexts[nspec] = cur;
227 nspec++;
228 lineno++;
229 }
230
231 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
232 seapp_context_cmp);
233
234#if DEBUG
235 {
236 int i;
237 for (i = 0; i < nspec; i++) {
238 cur = seapp_contexts[i];
William Roberts1b36ad02012-07-27 13:52:33 -0700239 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s user=%s seinfo=%s name=%s sebool=%s -> domain=%s type=%s level=%s levelFromUid=%s",
240 __FUNCTION__,
241 cur->isSystemServer ? "true" : "false", cur->user,
242 cur->seinfo, cur->name, cur->sebool, cur->domain,
243 cur->type, cur->level,
244 cur->levelFromUid ? "true" : "false");
Stephen Smalleyf0740362012-01-04 12:30:47 -0500245 }
246 }
247#endif
248
Stephen Smalley7446c912012-03-19 10:37:05 -0400249 ret = 0;
250
Stephen Smalleyf0740362012-01-04 12:30:47 -0500251out:
252 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400253 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500254
255err:
256 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400257 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
258 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500259 goto out;
260oom:
261 selinux_log(SELINUX_ERROR,
262 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400263 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500264 goto out;
265}
266
Stephen Smalley7446c912012-03-19 10:37:05 -0400267
268static void seapp_context_init(void)
269{
270 selinux_android_seapp_context_reload();
271}
272
Stephen Smalleyf0740362012-01-04 12:30:47 -0500273static pthread_once_t once = PTHREAD_ONCE_INIT;
274
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400275int selinux_android_setfilecon2(const char *pkgdir,
276 const char *pkgname,
277 const char *seinfo,
278 uid_t uid)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500279{
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400280 const char *username;
281 char *orig_ctx_str = NULL, *ctx_str, *end = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500282 context_t ctx = NULL;
283 struct passwd *pw;
284 struct seapp_context *cur;
285 int i, rc;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400286 unsigned long id = 0;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500287
288 if (is_selinux_enabled() <= 0)
289 return 0;
290
291 __selinux_once(once, seapp_context_init);
292
293 rc = getfilecon(pkgdir, &ctx_str);
294 if (rc < 0)
295 goto err;
296
297 ctx = context_new(ctx_str);
298 orig_ctx_str = ctx_str;
299 if (!ctx)
300 goto oom;
301
302 pw = getpwuid(uid);
303 if (!pw)
304 goto err;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400305 username = pw->pw_name;
306
307 if (!strncmp(username, "app_", 4)) {
308 id = strtoul(username + 4, NULL, 10);
309 if (id >= MLS_CATS)
310 goto err;
311 } else if (username[0] == 'u' && isdigit(username[1])) {
312 unsigned long unused;
313 unused = strtoul(username+1, &end, 10);
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400314 if (end[0] != '_' || end[1] == 0)
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400315 goto err;
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400316 if (end[1] == 'a' && isdigit(end[2])) {
317 id = strtoul(end + 2, NULL, 10);
318 if (id >= MLS_CATS/2)
319 goto err;
320 /* regular app UID */
321 username = "app_";
322 } else if (end[1] == 'i' && isdigit(end[2])) {
323 id = strtoul(end + 2, NULL, 10);
324 if (id >= MLS_CATS/2)
325 goto err;
326 /* isolated service */
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400327 id += MLS_CATS/2;
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400328 username = "app_";
329 } else {
330 username = end + 1;
331 }
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400332 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500333
334 for (i = 0; i < nspec; i++) {
335 cur = seapp_contexts[i];
336
337 /* isSystemServer=true is only for app process labeling. */
338 if (cur->isSystemServer)
339 continue;
340
341 if (cur->user) {
342 if (cur->prefix) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400343 if (strncasecmp(username, cur->user, cur->len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500344 continue;
345 } else {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400346 if (strcasecmp(username, cur->user))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500347 continue;
348 }
349 }
350
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400351 if (cur->seinfo) {
352 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
353 continue;
354 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500355
356 if (cur->name) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400357 if (!pkgname || strcasecmp(pkgname, cur->name))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500358 continue;
359 }
360
361 if (!cur->type)
362 continue;
363
William Roberts1b36ad02012-07-27 13:52:33 -0700364 if (cur->sebool) {
365 int value = security_get_boolean_active(cur->sebool);
366 if (value == 0)
367 continue;
368 else if (value == -1) {
369 selinux_log(SELINUX_ERROR, \
370 "Could not find boolean: %s ", cur->sebool);
371 goto err;
372 }
373 }
374
Stephen Smalleyf0740362012-01-04 12:30:47 -0500375 if (context_type_set(ctx, cur->type))
376 goto oom;
377
Stephen Smalleyc9726ab2012-07-11 16:10:13 -0400378 if (cur->levelFromUid) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500379 char level[255];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500380 snprintf(level, sizeof level, "%s:c%lu",
381 context_range_get(ctx), id);
382 if (context_range_set(ctx, level))
383 goto oom;
384 } else if (cur->level) {
385 if (context_range_set(ctx, cur->level))
386 goto oom;
387 }
William Roberts1b36ad02012-07-27 13:52:33 -0700388
Stephen Smalleyf0740362012-01-04 12:30:47 -0500389 break;
390 }
391
392 ctx_str = context_str(ctx);
393 if (!ctx_str)
394 goto oom;
395
396 rc = security_check_context(ctx_str);
397 if (rc < 0)
398 goto err;
399
400 if (strcmp(ctx_str, orig_ctx_str)) {
401 rc = setfilecon(pkgdir, ctx_str);
402 if (rc < 0)
403 goto err;
404 }
405
406 rc = 0;
407out:
408 freecon(orig_ctx_str);
409 context_free(ctx);
410 return rc;
411err:
412 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
413 __FUNCTION__, pkgdir, uid, strerror(errno));
414 rc = -1;
415 goto out;
416oom:
417 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
418 rc = -1;
419 goto out;
420}
421
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400422int selinux_android_setfilecon(const char *pkgdir,
423 const char *pkgname,
424 uid_t uid)
425{
426 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
427}
428
Stephen Smalleyf0740362012-01-04 12:30:47 -0500429int selinux_android_setcontext(uid_t uid,
430 int isSystemServer,
431 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400432 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500433{
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400434 const char *username;
435 char *orig_ctx_str = NULL, *ctx_str, *end = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500436 context_t ctx = NULL;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400437 unsigned long id = 0;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500438 struct passwd *pw;
439 struct seapp_context *cur;
440 int i, rc;
441
442 if (is_selinux_enabled() <= 0)
443 return 0;
444
445 __selinux_once(once, seapp_context_init);
446
447 rc = getcon(&ctx_str);
448 if (rc)
449 goto err;
450
451 ctx = context_new(ctx_str);
452 orig_ctx_str = ctx_str;
453 if (!ctx)
454 goto oom;
455
456 pw = getpwuid(uid);
457 if (!pw)
458 goto err;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400459 username = pw->pw_name;
460
461 if (!strncmp(username, "app_", 4)) {
462 id = strtoul(username + 4, NULL, 10);
463 if (id >= MLS_CATS)
464 goto err;
465 } else if (username[0] == 'u' && isdigit(username[1])) {
466 unsigned long unused;
467 unused = strtoul(username+1, &end, 10);
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400468 if (end[0] != '_' || end[1] == 0)
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400469 goto err;
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400470 if (end[1] == 'a' && isdigit(end[2])) {
471 id = strtoul(end + 2, NULL, 10);
472 if (id >= MLS_CATS/2)
473 goto err;
474 /* regular app UID */
475 username = "app_";
476 } else if (end[1] == 'i' && isdigit(end[2])) {
477 id = strtoul(end + 2, NULL, 10);
478 if (id >= MLS_CATS/2)
479 goto err;
480 /* isolated service */
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400481 id += MLS_CATS/2;
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400482 username = "app_";
483 } else {
484 username = end + 1;
485 }
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400486 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500487
488 for (i = 0; i < nspec; i++) {
489 cur = seapp_contexts[i];
William Roberts1b36ad02012-07-27 13:52:33 -0700490
Stephen Smalleyf0740362012-01-04 12:30:47 -0500491 if (cur->isSystemServer != isSystemServer)
492 continue;
493 if (cur->user) {
494 if (cur->prefix) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400495 if (strncasecmp(username, cur->user, cur->len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500496 continue;
497 } else {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400498 if (strcasecmp(username, cur->user))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500499 continue;
500 }
501 }
502 if (cur->seinfo) {
503 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
504 continue;
505 }
506 if (cur->name) {
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400507 if (!pkgname || strcasecmp(pkgname, cur->name))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500508 continue;
509 }
510
511 if (!cur->domain)
512 continue;
513
William Roberts1b36ad02012-07-27 13:52:33 -0700514 if (cur->sebool) {
515 int value = security_get_boolean_active(cur->sebool);
516 if (value == 0)
517 continue;
518 else if (value == -1) {
519 selinux_log(SELINUX_ERROR, \
520 "Could not find boolean: %s ", cur->sebool);
521 goto err;
522 }
523 }
524
Stephen Smalleyf0740362012-01-04 12:30:47 -0500525 if (context_type_set(ctx, cur->domain))
526 goto oom;
527
Stephen Smalleyc9726ab2012-07-11 16:10:13 -0400528 if (cur->levelFromUid) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500529 char level[255];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500530 snprintf(level, sizeof level, "%s:c%lu",
531 context_range_get(ctx), id);
532 if (context_range_set(ctx, level))
533 goto oom;
534 } else if (cur->level) {
535 if (context_range_set(ctx, cur->level))
536 goto oom;
537 }
538
539 break;
540 }
541
542 if (i == nspec) {
543 /*
544 * No match.
545 * Fail to prevent staying in the zygote's context.
546 */
547 selinux_log(SELINUX_ERROR,
548 "%s: No match for app with uid %d, seinfo %s, name %s\n",
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400549 __FUNCTION__, uid, seinfo, pkgname);
William Roberts09f69842012-07-27 15:16:43 -0700550
551 rc = (security_getenforce() == 0) ? 0 : -1;
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400552 goto out;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500553 }
554
555 ctx_str = context_str(ctx);
556 if (!ctx_str)
557 goto oom;
558
559 rc = security_check_context(ctx_str);
560 if (rc < 0)
561 goto err;
562
563 if (strcmp(ctx_str, orig_ctx_str)) {
564 rc = setcon(ctx_str);
565 if (rc < 0)
566 goto err;
567 }
568
569 rc = 0;
570out:
571 freecon(orig_ctx_str);
572 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400573 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500574 return rc;
575err:
576 if (isSystemServer)
577 selinux_log(SELINUX_ERROR,
578 "%s: Error setting context for system server: %s\n",
579 __FUNCTION__, strerror(errno));
580 else
581 selinux_log(SELINUX_ERROR,
582 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
583 __FUNCTION__, uid, seinfo, strerror(errno));
584
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400585 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500586 goto out;
587oom:
588 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
589 rc = -1;
590 goto out;
591}
592
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400593static struct selabel_handle *sehandle = NULL;
594
Stephen Smalley906742d2012-08-23 16:04:59 -0400595static struct selabel_handle *file_context_open(void)
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400596{
Stephen Smalley906742d2012-08-23 16:04:59 -0400597 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400598 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400599
Stephen Smalley906742d2012-08-23 16:04:59 -0400600 h = NULL;
601 while ((h == NULL) && seopts[i].value) {
602 h = selabel_open(SELABEL_CTX_FILE, &seopts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400603 i++;
604 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400605
Stephen Smalley906742d2012-08-23 16:04:59 -0400606 if (!h)
rpcraigf1724a32012-08-01 15:35:37 -0400607 selinux_log(SELINUX_ERROR, "%s: Error getting sehandle label (%s)\n",
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400608 __FUNCTION__, strerror(errno));
Stephen Smalley906742d2012-08-23 16:04:59 -0400609 return h;
610}
611
612static void file_context_init(void)
613{
614 sehandle = file_context_open();
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400615}
616
617static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
618
619int selinux_android_restorecon(const char *pathname)
620{
621
622 __selinux_once(fc_once, file_context_init);
623
624 int ret;
625
626 if (!sehandle)
627 goto bail;
628
629 struct stat sb;
630
631 if (lstat(pathname, &sb) < 0)
632 goto err;
633
634 char *oldcontext, *newcontext;
635
636 if (lgetfilecon(pathname, &oldcontext) < 0)
637 goto err;
638
639 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
640 goto err;
641
642 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
643 if (lsetfilecon(pathname, newcontext) < 0)
644 goto err;
645
646 ret = 0;
647out:
648 if (oldcontext)
649 freecon(oldcontext);
650 if (newcontext)
651 freecon(newcontext);
652
653 return ret;
654
655err:
656 selinux_log(SELINUX_ERROR,
657 "%s: Error restoring context for %s (%s)\n",
658 __FUNCTION__, pathname, strerror(errno));
659
660bail:
661 ret = -1;
662 goto out;
663}
rpcraig9b100832012-07-27 06:36:59 -0400664
665
rpcraigf1724a32012-08-01 15:35:37 -0400666struct selabel_handle* selinux_android_file_context_handle(void)
667{
Stephen Smalley906742d2012-08-23 16:04:59 -0400668 return file_context_open();
rpcraigf1724a32012-08-01 15:35:37 -0400669}
rpcraig9b100832012-07-27 06:36:59 -0400670
rpcraigf1724a32012-08-01 15:35:37 -0400671int selinux_android_reload_policy(void)
672{
673 char path[PATH_MAX];
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400674 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400675 struct stat sb;
676 void *map = NULL;
677 int i = 0;
678
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400679 while (fd < 0 && sepolicy_file[i]) {
680 snprintf(path, sizeof(path), "%s",
681 sepolicy_file[i]);
rpcraigf1724a32012-08-01 15:35:37 -0400682 fd = open(path, O_RDONLY);
rpcraigf1724a32012-08-01 15:35:37 -0400683 i++;
684 }
685 if (fd < 0) {
686 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
687 strerror(errno));
688 return -1;
689 }
690 if (fstat(fd, &sb) < 0) {
691 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
692 path, strerror(errno));
693 close(fd);
694 return -1;
695 }
696 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
697 if (map == MAP_FAILED) {
698 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
699 path, strerror(errno));
700 close(fd);
701 return -1;
702 }
703
704 rc = security_load_policy(map, sb.st_size);
705 if (rc < 0) {
706 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
707 strerror(errno));
708 munmap(map, sb.st_size);
709 close(fd);
710 return -1;
711 }
712
713 munmap(map, sb.st_size);
714 close(fd);
715 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", path);
716
717 return 0;
718}
719
720int selinux_android_load_policy(void)
721{
722 mkdir(SELINUXMNT, 0755);
723 if (mount("selinuxfs", SELINUXMNT, "selinuxfs", 0, NULL)) {
724 if (errno == ENODEV) {
725 /* SELinux not enabled in kernel */
726 return -1;
727 }
728 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
729 strerror(errno));
730 return -1;
731 }
732 set_selinuxmnt(SELINUXMNT);
733
734 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400735}