blob: f514e2b78152dfbeec574774c298d5a92f7b11d6 [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>
Stephen Smalley826cc292014-01-28 15:04:22 -05006#include <stdbool.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -05007#include <ctype.h>
8#include <errno.h>
9#include <pwd.h>
10#include <grp.h>
Stephen Smalley7fc97fb2014-01-28 10:37:58 -050011#include <ftw.h>
rpcraigf1724a32012-08-01 15:35:37 -040012#include <sys/mman.h>
13#include <sys/mount.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050014#include <sys/types.h>
15#include <sys/stat.h>
Stephen Smalley826cc292014-01-28 15:04:22 -050016#include <sys/xattr.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050017#include <fcntl.h>
18#include <selinux/selinux.h>
19#include <selinux/context.h>
20#include <selinux/android.h>
Stephen Smalley0ca91b32012-03-19 10:25:53 -040021#include <selinux/label.h>
Stephen Smalleye8b0fd82012-07-31 09:12:53 -040022#include <selinux/avc.h>
Stephen Smalley826cc292014-01-28 15:04:22 -050023#include <mincrypt/sha.h>
Stephen Smalley895b4462012-09-19 16:27:36 -040024#include <private/android_filesystem_config.h>
Stephen Smalleyd10c3432012-11-05 11:49:35 -050025#include "policy.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050026#include "callbacks.h"
27#include "selinux_internal.h"
28
29/*
30 * XXX Where should this configuration file be located?
31 * Needs to be accessible by zygote and installd when
32 * setting credentials for app processes and setting permissions
33 * on app data directories.
34 */
Stephen Smalley7446c912012-03-19 10:37:05 -040035static char const * const seapp_contexts_file[] = {
repo sync67507802013-04-26 15:49:39 -070036 "/data/security/current/seapp_contexts",
Stephen Smalley7446c912012-03-19 10:37:05 -040037 "/seapp_contexts",
William Roberts8ed42422013-04-15 16:13:30 -070038 NULL };
Stephen Smalleyf0740362012-01-04 12:30:47 -050039
Stephen Smalley32ebfe82012-03-20 13:05:37 -040040static const struct selinux_opt seopts[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070041 { SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
Stephen Smalley32ebfe82012-03-20 13:05:37 -040042 { SELABEL_OPT_PATH, "/file_contexts" },
43 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040044
Stephen Smalley4a655ec2012-09-18 15:08:32 -040045static const char *const sepolicy_file[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070046 "/data/security/current/sepolicy",
rpcraigf1724a32012-08-01 15:35:37 -040047 "/sepolicy",
William Roberts8ed42422013-04-15 16:13:30 -070048 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040049
Stephen Smalleya8795982012-11-28 10:42:46 -050050enum levelFrom {
51 LEVELFROM_NONE,
52 LEVELFROM_APP,
53 LEVELFROM_USER,
54 LEVELFROM_ALL
55};
56
57#if DEBUG
58static char const * const levelFromName[] = {
59 "none",
60 "app",
61 "user",
62 "all"
63};
64#endif
65
William Robertse3615f92013-09-11 20:35:53 -070066struct prefix_str {
67 size_t len;
68 char *str;
69 char is_prefix;
70};
71
Stephen Smalleyf0740362012-01-04 12:30:47 -050072struct seapp_context {
73 /* input selectors */
74 char isSystemServer;
William Robertse3615f92013-09-11 20:35:53 -070075 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -050076 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -070077 struct prefix_str name;
Stephen Smalleyf0740362012-01-04 12:30:47 -050078 /* outputs */
79 char *domain;
80 char *type;
81 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070082 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050083 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050084};
85
86static int seapp_context_cmp(const void *A, const void *B)
87{
Nick Kralevich833cba62013-11-19 11:24:33 -080088 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
89 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -050090 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
91
92 /* Give precedence to isSystemServer=true. */
93 if (s1->isSystemServer != s2->isSystemServer)
94 return (s1->isSystemServer ? -1 : 1);
95
96 /* Give precedence to a specified user= over an unspecified user=. */
William Robertse3615f92013-09-11 20:35:53 -070097 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -050098 return -1;
William Robertse3615f92013-09-11 20:35:53 -070099 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500100 return 1;
101
William Robertse3615f92013-09-11 20:35:53 -0700102 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500103 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700104 if (s1->user.is_prefix != s2->user.is_prefix)
105 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500106
107 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700108 if (s1->user.is_prefix && s1->user.len != s2->user.len)
109 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500110 }
111
112 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
113 if (s1->seinfo && !s2->seinfo)
114 return -1;
115 if (!s1->seinfo && s2->seinfo)
116 return 1;
117
118 /* Give precedence to a specified name= over an unspecified name=. */
William Robertse3615f92013-09-11 20:35:53 -0700119 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500120 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700121 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500122 return 1;
123
William Robertse3615f92013-09-11 20:35:53 -0700124 if (s1->name.str) {
125 /* Give precedence to a fixed name= string over a prefix. */
126 if (s1->name.is_prefix != s2->name.is_prefix)
127 return (s2->name.is_prefix ? -1 : 1);
128
129 /* Give precedence to a longer prefix over a shorter prefix. */
130 if (s1->name.is_prefix && s1->name.len != s2->name.len)
131 return (s1->name.len > s2->name.len) ? -1 : 1;
132 }
133
William Roberts1b36ad02012-07-27 13:52:33 -0700134 /* Give precedence to a specified sebool= over an unspecified sebool=. */
135 if (s1->sebool && !s2->sebool)
136 return -1;
137 if (!s1->sebool && s2->sebool)
138 return 1;
139
Stephen Smalleyf0740362012-01-04 12:30:47 -0500140 /* Anything else has equal precedence. */
141 return 0;
142}
143
144static struct seapp_context **seapp_contexts = NULL;
145static int nspec = 0;
146
Stephen Smalley7446c912012-03-19 10:37:05 -0400147int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500148{
Stephen Smalley7446c912012-03-19 10:37:05 -0400149 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500150 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500151 char *token;
152 unsigned lineno;
153 struct seapp_context *cur;
154 char *p, *name = NULL, *value = NULL, *saveptr;
155 size_t len;
Stephen Smalley300bebb2013-04-16 15:33:16 -0400156 int i = 0, n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500157
Stephen Smalley7446c912012-03-19 10:37:05 -0400158 while ((fp==NULL) && seapp_contexts_file[i])
159 fp = fopen(seapp_contexts_file[i++], "r");
160
Stephen Smalleyf0740362012-01-04 12:30:47 -0500161 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400162 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
163 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500164 }
165
Stephen Smalley300bebb2013-04-16 15:33:16 -0400166 if (seapp_contexts) {
167 for (n = 0; n < nspec; n++) {
168 cur = seapp_contexts[n];
William Robertse3615f92013-09-11 20:35:53 -0700169 free(cur->user.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400170 free(cur->seinfo);
William Robertse3615f92013-09-11 20:35:53 -0700171 free(cur->name.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400172 free(cur->domain);
173 free(cur->type);
174 free(cur->level);
175 free(cur->sebool);
176 }
177 free(seapp_contexts);
178 }
179
Stephen Smalleyf0740362012-01-04 12:30:47 -0500180 nspec = 0;
181 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
182 p = line_buf;
183 while (isspace(*p))
184 p++;
185 if (*p == '#' || *p == 0)
186 continue;
187 nspec++;
188 }
189
Nick Kralevich833cba62013-11-19 11:24:33 -0800190 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500191 if (!seapp_contexts)
192 goto oom;
193
194 rewind(fp);
195 nspec = 0;
196 lineno = 1;
197 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
198 len = strlen(line_buf);
199 if (line_buf[len - 1] == '\n')
200 line_buf[len - 1] = 0;
201 p = line_buf;
202 while (isspace(*p))
203 p++;
204 if (*p == '#' || *p == 0)
205 continue;
206
Nick Kralevich833cba62013-11-19 11:24:33 -0800207 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500208 if (!cur)
209 goto oom;
210
211 token = strtok_r(p, " \t", &saveptr);
212 if (!token)
213 goto err;
214
215 while (1) {
216 name = token;
217 value = strchr(name, '=');
218 if (!value)
219 goto err;
220 *value++ = 0;
221
222 if (!strcasecmp(name, "isSystemServer")) {
223 if (!strcasecmp(value, "true"))
224 cur->isSystemServer = 1;
225 else if (!strcasecmp(value, "false"))
226 cur->isSystemServer = 0;
227 else {
228 goto err;
229 }
230 } else if (!strcasecmp(name, "user")) {
William Robertse3615f92013-09-11 20:35:53 -0700231 cur->user.str = strdup(value);
232 if (!cur->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500233 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700234 cur->user.len = strlen(cur->user.str);
235 if (cur->user.str[cur->user.len-1] == '*')
236 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500237 } else if (!strcasecmp(name, "seinfo")) {
238 cur->seinfo = strdup(value);
239 if (!cur->seinfo)
240 goto oom;
241 } else if (!strcasecmp(name, "name")) {
William Robertse3615f92013-09-11 20:35:53 -0700242 cur->name.str = strdup(value);
243 if (!cur->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500244 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700245 cur->name.len = strlen(cur->name.str);
246 if (cur->name.str[cur->name.len-1] == '*')
247 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500248 } else if (!strcasecmp(name, "domain")) {
249 cur->domain = strdup(value);
250 if (!cur->domain)
251 goto oom;
252 } else if (!strcasecmp(name, "type")) {
253 cur->type = strdup(value);
254 if (!cur->type)
255 goto oom;
256 } else if (!strcasecmp(name, "levelFromUid")) {
257 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500258 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500259 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500260 cur->levelFrom = LEVELFROM_NONE;
261 else {
262 goto err;
263 }
264 } else if (!strcasecmp(name, "levelFrom")) {
265 if (!strcasecmp(value, "none"))
266 cur->levelFrom = LEVELFROM_NONE;
267 else if (!strcasecmp(value, "app"))
268 cur->levelFrom = LEVELFROM_APP;
269 else if (!strcasecmp(value, "user"))
270 cur->levelFrom = LEVELFROM_USER;
271 else if (!strcasecmp(value, "all"))
272 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500273 else {
274 goto err;
275 }
276 } else if (!strcasecmp(name, "level")) {
277 cur->level = strdup(value);
278 if (!cur->level)
279 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700280 } else if (!strcasecmp(name, "sebool")) {
281 cur->sebool = strdup(value);
282 if (!cur->sebool)
283 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500284 } else
285 goto err;
286
287 token = strtok_r(NULL, " \t", &saveptr);
288 if (!token)
289 break;
290 }
291
292 seapp_contexts[nspec] = cur;
293 nspec++;
294 lineno++;
295 }
296
297 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
298 seapp_context_cmp);
299
300#if DEBUG
301 {
302 int i;
303 for (i = 0; i < nspec; i++) {
304 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500305 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 -0700306 __FUNCTION__,
William Robertse3615f92013-09-11 20:35:53 -0700307 cur->isSystemServer ? "true" : "false", cur->user.str,
308 cur->seinfo, cur->name.str, cur->sebool, cur->domain,
William Roberts1b36ad02012-07-27 13:52:33 -0700309 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500310 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500311 }
312 }
313#endif
314
Stephen Smalley7446c912012-03-19 10:37:05 -0400315 ret = 0;
316
Stephen Smalleyf0740362012-01-04 12:30:47 -0500317out:
318 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400319 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500320
321err:
322 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400323 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
324 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500325 goto out;
326oom:
327 selinux_log(SELINUX_ERROR,
328 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400329 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500330 goto out;
331}
332
Stephen Smalley7446c912012-03-19 10:37:05 -0400333
334static void seapp_context_init(void)
335{
336 selinux_android_seapp_context_reload();
337}
338
Stephen Smalleyf0740362012-01-04 12:30:47 -0500339static pthread_once_t once = PTHREAD_ONCE_INIT;
340
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400341/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500342 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400343 * using the current scheme.
344 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500345#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400346
347enum seapp_kind {
348 SEAPP_TYPE,
349 SEAPP_DOMAIN
350};
351
352static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400353 uid_t uid,
354 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400355 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400356 const char *pkgname,
357 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500358{
Stephen Smalley895b4462012-09-19 16:27:36 -0400359 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700360 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400361 int i;
362 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500363 uid_t userid;
364 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500365
Stephen Smalleya8795982012-11-28 10:42:46 -0500366 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400367 appid = uid % AID_USER;
368 if (appid < AID_APP) {
369 for (n = 0; n < android_id_count; n++) {
370 if (android_ids[n].aid == appid) {
371 username = android_ids[n].name;
372 break;
373 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400374 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400375 if (!username)
376 goto err;
377 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400378 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400379 appid -= AID_APP;
380 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400381 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400382 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400383 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500384
Stephen Smalleya8795982012-11-28 10:42:46 -0500385 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400386 goto err;
387
Stephen Smalleyf0740362012-01-04 12:30:47 -0500388 for (i = 0; i < nspec; i++) {
389 cur = seapp_contexts[i];
390
Stephen Smalley895b4462012-09-19 16:27:36 -0400391 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500392 continue;
393
William Robertse3615f92013-09-11 20:35:53 -0700394 if (cur->user.str) {
395 if (cur->user.is_prefix) {
396 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500397 continue;
398 } else {
William Robertse3615f92013-09-11 20:35:53 -0700399 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500400 continue;
401 }
402 }
403
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400404 if (cur->seinfo) {
405 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
406 continue;
407 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500408
William Robertse3615f92013-09-11 20:35:53 -0700409 if (cur->name.str) {
410 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500411 continue;
William Robertse3615f92013-09-11 20:35:53 -0700412
413 if (cur->name.is_prefix) {
414 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
415 continue;
416 } else {
417 if (strcasecmp(pkgname, cur->name.str))
418 continue;
419 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500420 }
421
Stephen Smalley895b4462012-09-19 16:27:36 -0400422 if (kind == SEAPP_TYPE && !cur->type)
423 continue;
424 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500425 continue;
426
William Roberts1b36ad02012-07-27 13:52:33 -0700427 if (cur->sebool) {
428 int value = security_get_boolean_active(cur->sebool);
429 if (value == 0)
430 continue;
431 else if (value == -1) {
432 selinux_log(SELINUX_ERROR, \
433 "Could not find boolean: %s ", cur->sebool);
434 goto err;
435 }
436 }
437
Stephen Smalley895b4462012-09-19 16:27:36 -0400438 if (kind == SEAPP_TYPE) {
439 if (context_type_set(ctx, cur->type))
440 goto oom;
441 } else if (kind == SEAPP_DOMAIN) {
442 if (context_type_set(ctx, cur->domain))
443 goto oom;
444 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500445
Stephen Smalleya8795982012-11-28 10:42:46 -0500446 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500447 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500448 switch (cur->levelFrom) {
449 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500450 snprintf(level, sizeof level, "s0:c%u,c%u",
451 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500452 256 + (appid>>8 & 0xff));
453 break;
454 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500455 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500456 512 + (userid & 0xff),
457 768 + (userid>>8 & 0xff));
458 break;
459 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500460 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
461 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500462 256 + (appid>>8 & 0xff),
463 512 + (userid & 0xff),
464 768 + (userid>>8 & 0xff));
465 break;
466 default:
467 goto err;
468 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500469 if (context_range_set(ctx, level))
470 goto oom;
471 } else if (cur->level) {
472 if (context_range_set(ctx, cur->level))
473 goto oom;
474 }
William Roberts1b36ad02012-07-27 13:52:33 -0700475
Stephen Smalleyf0740362012-01-04 12:30:47 -0500476 break;
477 }
478
Stephen Smalley895b4462012-09-19 16:27:36 -0400479 if (kind == SEAPP_DOMAIN && i == nspec) {
480 /*
481 * No match.
482 * Fail to prevent staying in the zygote's context.
483 */
484 selinux_log(SELINUX_ERROR,
485 "%s: No match for app with uid %d, seinfo %s, name %s\n",
486 __FUNCTION__, uid, seinfo, pkgname);
487
488 if (security_getenforce() == 1)
489 goto err;
490 }
491
492 return 0;
493err:
494 return -1;
495oom:
496 return -2;
497}
498
499int selinux_android_setfilecon2(const char *pkgdir,
500 const char *pkgname,
501 const char *seinfo,
502 uid_t uid)
503{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700504 char *orig_ctx_str = NULL;
505 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400506 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700507 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400508
509 if (is_selinux_enabled() <= 0)
510 return 0;
511
512 __selinux_once(once, seapp_context_init);
513
514 rc = getfilecon(pkgdir, &ctx_str);
515 if (rc < 0)
516 goto err;
517
518 ctx = context_new(ctx_str);
519 orig_ctx_str = ctx_str;
520 if (!ctx)
521 goto oom;
522
523 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
524 if (rc == -1)
525 goto err;
526 else if (rc == -2)
527 goto oom;
528
Stephen Smalleyf0740362012-01-04 12:30:47 -0500529 ctx_str = context_str(ctx);
530 if (!ctx_str)
531 goto oom;
532
533 rc = security_check_context(ctx_str);
534 if (rc < 0)
535 goto err;
536
537 if (strcmp(ctx_str, orig_ctx_str)) {
538 rc = setfilecon(pkgdir, ctx_str);
539 if (rc < 0)
540 goto err;
541 }
542
543 rc = 0;
544out:
545 freecon(orig_ctx_str);
546 context_free(ctx);
547 return rc;
548err:
549 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
550 __FUNCTION__, pkgdir, uid, strerror(errno));
551 rc = -1;
552 goto out;
553oom:
554 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
555 rc = -1;
556 goto out;
557}
558
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400559int selinux_android_setfilecon(const char *pkgdir,
560 const char *pkgname,
561 uid_t uid)
562{
563 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
564}
565
Stephen Smalleyf0740362012-01-04 12:30:47 -0500566int selinux_android_setcontext(uid_t uid,
567 int isSystemServer,
568 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400569 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500570{
Stephen Smalley895b4462012-09-19 16:27:36 -0400571 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500572 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700573 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500574
575 if (is_selinux_enabled() <= 0)
576 return 0;
577
578 __selinux_once(once, seapp_context_init);
579
580 rc = getcon(&ctx_str);
581 if (rc)
582 goto err;
583
584 ctx = context_new(ctx_str);
585 orig_ctx_str = ctx_str;
586 if (!ctx)
587 goto oom;
588
Stephen Smalley895b4462012-09-19 16:27:36 -0400589 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
590 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500591 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400592 else if (rc == -2)
593 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500594
595 ctx_str = context_str(ctx);
596 if (!ctx_str)
597 goto oom;
598
599 rc = security_check_context(ctx_str);
600 if (rc < 0)
601 goto err;
602
603 if (strcmp(ctx_str, orig_ctx_str)) {
604 rc = setcon(ctx_str);
605 if (rc < 0)
606 goto err;
607 }
608
609 rc = 0;
610out:
611 freecon(orig_ctx_str);
612 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400613 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500614 return rc;
615err:
616 if (isSystemServer)
617 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700618 "%s: Error setting context for system server: %s\n",
619 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500620 else
621 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700622 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
623 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500624
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400625 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500626 goto out;
627oom:
628 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
629 rc = -1;
630 goto out;
631}
632
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400633static struct selabel_handle *sehandle = NULL;
Stephen Smalley826cc292014-01-28 15:04:22 -0500634#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
635static uint8_t fc_digest[FC_DIGEST_SIZE];
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400636
Stephen Smalley826cc292014-01-28 15:04:22 -0500637static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[])
638{
639 struct selabel_handle *h;
640 unsigned int i = 0;
641 int fd;
642 struct stat sb;
643 void *map;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400644
Stephen Smalley826cc292014-01-28 15:04:22 -0500645 h = NULL;
646 while ((h == NULL) && opts[i].value) {
647 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
648 if (h)
649 break;
650 i++;
651 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400652
Stephen Smalley826cc292014-01-28 15:04:22 -0500653 if (!h)
654 return NULL;
655
656 fd = open(opts[i].value, O_RDONLY | O_NOFOLLOW);
657 if (fd < 0) {
658 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n",
659 opts[i].value, strerror(errno));
660 goto err;
661 }
662 if (fstat(fd, &sb) < 0) {
663 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
664 opts[i].value, strerror(errno));
665 close(fd);
666 goto err;
667 }
668 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
669 if (map == MAP_FAILED) {
670 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
671 opts[i].value, strerror(errno));
672 close(fd);
673 goto err;
674 }
675 SHA_hash(map, sb.st_size, fc_digest);
676 munmap(map, sb.st_size);
677 close(fd);
678
679 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts from %s, ",
680 opts[i].value);
681 selinux_log(SELINUX_INFO, "digest=");
682 for (i = 0; i < sizeof fc_digest; i++)
683 selinux_log(SELINUX_INFO, "%02x",fc_digest[i]);
684 selinux_log(SELINUX_INFO, "\n");
685
686 return h;
687
688err:
689 selabel_close(h);
690 return NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700691}
692
693static struct selabel_handle *file_context_open(void)
694{
695 struct selabel_handle *h;
696
697 h = get_selabel_handle(seopts);
698
Stephen Smalley906742d2012-08-23 16:04:59 -0400699 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700700 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
701 __FUNCTION__, strerror(errno));
702 return h;
703}
704
Stephen Smalley906742d2012-08-23 16:04:59 -0400705static void file_context_init(void)
706{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500707 if (!sehandle)
708 sehandle = file_context_open();
709}
710
Stephen Smalley826cc292014-01-28 15:04:22 -0500711#define RESTORECON_LAST "security.restorecon_last"
712
713static int restorecon_sb(const char *pathname, const struct stat *sb, bool setrestoreconlast)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500714{
715 char *secontext = NULL;
716 char *oldsecontext = NULL;
717 int i;
718
719 if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
720 return -errno;
721
722 if (lgetfilecon(pathname, &oldsecontext) < 0) {
723 freecon(secontext);
724 return -errno;
725 }
726
727 if (strcmp(oldsecontext, secontext) != 0) {
728 if (lsetfilecon(pathname, secontext) < 0) {
729 selinux_log(SELINUX_ERROR,
730 "SELinux: Could not set context for %s to %s: %s\n",
731 pathname, secontext, strerror(errno));
732 freecon(oldsecontext);
733 freecon(secontext);
734 return -errno;
735 }
736 }
737 freecon(oldsecontext);
738 freecon(secontext);
Stephen Smalley826cc292014-01-28 15:04:22 -0500739
740 if (setrestoreconlast && S_ISDIR(sb->st_mode))
741 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
742
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500743 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400744}
745
746static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
747
748int selinux_android_restorecon(const char *pathname)
749{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500750 struct stat sb;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400751
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500752 if (is_selinux_enabled() <= 0)
753 return 0;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700754
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500755 __selinux_once(fc_once, file_context_init);
Kenny Root20f62f32012-10-22 17:09:23 -0700756
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500757 if (!sehandle)
758 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400759
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500760 if (lstat(pathname, &sb) < 0)
761 return -errno;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400762
Stephen Smalley826cc292014-01-28 15:04:22 -0500763 return restorecon_sb(pathname, &sb, false);
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500764}
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400765
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500766static int nftw_restorecon(const char* filename, const struct stat* statptr,
767 int fileflags __attribute__((unused)),
768 struct FTW* pftw __attribute__((unused)))
769{
Stephen Smalley826cc292014-01-28 15:04:22 -0500770 restorecon_sb(filename, statptr, true);
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500771 return 0;
772}
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400773
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500774int selinux_android_restorecon_recursive(const char* pathname)
775{
776 int fd_limit = 20;
777 int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
Stephen Smalley826cc292014-01-28 15:04:22 -0500778 char xattr_value[FC_DIGEST_SIZE];
779 ssize_t size;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400780
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500781 if (is_selinux_enabled() <= 0)
782 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400783
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500784 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400785
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500786 if (!sehandle)
787 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400788
Stephen Smalley826cc292014-01-28 15:04:22 -0500789 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
790 if (size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
791 selinux_log(SELINUX_INFO,
792 "SELinux: Skipping restorecon_recursive(%s)\n",
793 pathname);
794 return 0;
795 }
796
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500797 return nftw(pathname, nftw_restorecon, fd_limit, flags);
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400798}
rpcraig9b100832012-07-27 06:36:59 -0400799
rpcraigf1724a32012-08-01 15:35:37 -0400800struct selabel_handle* selinux_android_file_context_handle(void)
801{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500802 return file_context_open();
803}
804
805void selinux_android_set_sehandle(const struct selabel_handle *hndl)
806{
807 sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -0400808}
rpcraig9b100832012-07-27 06:36:59 -0400809
rpcraigf1724a32012-08-01 15:35:37 -0400810int selinux_android_reload_policy(void)
811{
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400812 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400813 struct stat sb;
814 void *map = NULL;
815 int i = 0;
816
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400817 while (fd < 0 && sepolicy_file[i]) {
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700818 fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -0400819 i++;
820 }
821 if (fd < 0) {
822 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
823 strerror(errno));
824 return -1;
825 }
826 if (fstat(fd, &sb) < 0) {
827 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400828 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400829 close(fd);
830 return -1;
831 }
832 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
833 if (map == MAP_FAILED) {
834 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400835 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400836 close(fd);
837 return -1;
838 }
839
840 rc = security_load_policy(map, sb.st_size);
841 if (rc < 0) {
842 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
843 strerror(errno));
844 munmap(map, sb.st_size);
845 close(fd);
846 return -1;
847 }
848
849 munmap(map, sb.st_size);
850 close(fd);
Stephen Smalleycb925042013-07-26 10:45:44 -0400851 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i-1]);
rpcraigf1724a32012-08-01 15:35:37 -0400852
853 return 0;
854}
855
856int selinux_android_load_policy(void)
857{
Nick Kralevich833cba62013-11-19 11:24:33 -0800858 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500859 int rc;
860 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
861 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400862 if (errno == ENODEV) {
863 /* SELinux not enabled in kernel */
864 return -1;
865 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500866 if (errno == ENOENT) {
867 /* Fall back to legacy mountpoint. */
868 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800869 rc = mkdir(mnt, 0755);
870 if (rc == -1 && errno != EEXIST) {
871 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
872 strerror(errno));
873 return -1;
874 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500875 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
876 }
877 }
878 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400879 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
880 strerror(errno));
881 return -1;
882 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500883 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400884
885 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400886}