blob: e0b4a0b09210e62727301c5e88447a44f9c5a6ca [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>
Stephen Smalley7fc97fb2014-01-28 10:37:58 -050010#include <ftw.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",
William Roberts8ed42422013-04-15 16:13:30 -070035 NULL };
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
Stephen Smalley4a655ec2012-09-18 15:08:32 -040042static const char *const sepolicy_file[] = {
Geremy Condra01cccbf2013-04-15 12:26:44 -070043 "/data/security/current/sepolicy",
rpcraigf1724a32012-08-01 15:35:37 -040044 "/sepolicy",
William Roberts8ed42422013-04-15 16:13:30 -070045 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040046
Stephen Smalleya8795982012-11-28 10:42:46 -050047enum levelFrom {
48 LEVELFROM_NONE,
49 LEVELFROM_APP,
50 LEVELFROM_USER,
51 LEVELFROM_ALL
52};
53
54#if DEBUG
55static char const * const levelFromName[] = {
56 "none",
57 "app",
58 "user",
59 "all"
60};
61#endif
62
William Robertse3615f92013-09-11 20:35:53 -070063struct prefix_str {
64 size_t len;
65 char *str;
66 char is_prefix;
67};
68
Stephen Smalleyf0740362012-01-04 12:30:47 -050069struct seapp_context {
70 /* input selectors */
71 char isSystemServer;
William Robertse3615f92013-09-11 20:35:53 -070072 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -050073 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -070074 struct prefix_str name;
Stephen Smalleyf0740362012-01-04 12:30:47 -050075 /* outputs */
76 char *domain;
77 char *type;
78 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070079 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050080 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050081};
82
83static int seapp_context_cmp(const void *A, const void *B)
84{
Nick Kralevich833cba62013-11-19 11:24:33 -080085 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
86 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) 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=. */
William Robertse3615f92013-09-11 20:35:53 -070094 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -050095 return -1;
William Robertse3615f92013-09-11 20:35:53 -070096 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -050097 return 1;
98
William Robertse3615f92013-09-11 20:35:53 -070099 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500100 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700101 if (s1->user.is_prefix != s2->user.is_prefix)
102 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500103
104 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700105 if (s1->user.is_prefix && s1->user.len != s2->user.len)
106 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500107 }
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=. */
William Robertse3615f92013-09-11 20:35:53 -0700116 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500117 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700118 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500119 return 1;
120
William Robertse3615f92013-09-11 20:35:53 -0700121 if (s1->name.str) {
122 /* Give precedence to a fixed name= string over a prefix. */
123 if (s1->name.is_prefix != s2->name.is_prefix)
124 return (s2->name.is_prefix ? -1 : 1);
125
126 /* Give precedence to a longer prefix over a shorter prefix. */
127 if (s1->name.is_prefix && s1->name.len != s2->name.len)
128 return (s1->name.len > s2->name.len) ? -1 : 1;
129 }
130
William Roberts1b36ad02012-07-27 13:52:33 -0700131 /* Give precedence to a specified sebool= over an unspecified sebool=. */
132 if (s1->sebool && !s2->sebool)
133 return -1;
134 if (!s1->sebool && s2->sebool)
135 return 1;
136
Stephen Smalleyf0740362012-01-04 12:30:47 -0500137 /* Anything else has equal precedence. */
138 return 0;
139}
140
141static struct seapp_context **seapp_contexts = NULL;
142static int nspec = 0;
143
Stephen Smalley7446c912012-03-19 10:37:05 -0400144int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500145{
Stephen Smalley7446c912012-03-19 10:37:05 -0400146 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500147 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500148 char *token;
149 unsigned lineno;
150 struct seapp_context *cur;
151 char *p, *name = NULL, *value = NULL, *saveptr;
152 size_t len;
Stephen Smalley300bebb2013-04-16 15:33:16 -0400153 int i = 0, n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500154
Stephen Smalley7446c912012-03-19 10:37:05 -0400155 while ((fp==NULL) && seapp_contexts_file[i])
156 fp = fopen(seapp_contexts_file[i++], "r");
157
Stephen Smalleyf0740362012-01-04 12:30:47 -0500158 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400159 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
160 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500161 }
162
Stephen Smalley300bebb2013-04-16 15:33:16 -0400163 if (seapp_contexts) {
164 for (n = 0; n < nspec; n++) {
165 cur = seapp_contexts[n];
William Robertse3615f92013-09-11 20:35:53 -0700166 free(cur->user.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400167 free(cur->seinfo);
William Robertse3615f92013-09-11 20:35:53 -0700168 free(cur->name.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400169 free(cur->domain);
170 free(cur->type);
171 free(cur->level);
172 free(cur->sebool);
173 }
174 free(seapp_contexts);
175 }
176
Stephen Smalleyf0740362012-01-04 12:30:47 -0500177 nspec = 0;
178 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
179 p = line_buf;
180 while (isspace(*p))
181 p++;
182 if (*p == '#' || *p == 0)
183 continue;
184 nspec++;
185 }
186
Nick Kralevich833cba62013-11-19 11:24:33 -0800187 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500188 if (!seapp_contexts)
189 goto oom;
190
191 rewind(fp);
192 nspec = 0;
193 lineno = 1;
194 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
195 len = strlen(line_buf);
196 if (line_buf[len - 1] == '\n')
197 line_buf[len - 1] = 0;
198 p = line_buf;
199 while (isspace(*p))
200 p++;
201 if (*p == '#' || *p == 0)
202 continue;
203
Nick Kralevich833cba62013-11-19 11:24:33 -0800204 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500205 if (!cur)
206 goto oom;
207
208 token = strtok_r(p, " \t", &saveptr);
209 if (!token)
210 goto err;
211
212 while (1) {
213 name = token;
214 value = strchr(name, '=');
215 if (!value)
216 goto err;
217 *value++ = 0;
218
219 if (!strcasecmp(name, "isSystemServer")) {
220 if (!strcasecmp(value, "true"))
221 cur->isSystemServer = 1;
222 else if (!strcasecmp(value, "false"))
223 cur->isSystemServer = 0;
224 else {
225 goto err;
226 }
227 } else if (!strcasecmp(name, "user")) {
William Robertse3615f92013-09-11 20:35:53 -0700228 cur->user.str = strdup(value);
229 if (!cur->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500230 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700231 cur->user.len = strlen(cur->user.str);
232 if (cur->user.str[cur->user.len-1] == '*')
233 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500234 } else if (!strcasecmp(name, "seinfo")) {
235 cur->seinfo = strdup(value);
236 if (!cur->seinfo)
237 goto oom;
238 } else if (!strcasecmp(name, "name")) {
William Robertse3615f92013-09-11 20:35:53 -0700239 cur->name.str = strdup(value);
240 if (!cur->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500241 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700242 cur->name.len = strlen(cur->name.str);
243 if (cur->name.str[cur->name.len-1] == '*')
244 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500245 } else if (!strcasecmp(name, "domain")) {
246 cur->domain = strdup(value);
247 if (!cur->domain)
248 goto oom;
249 } else if (!strcasecmp(name, "type")) {
250 cur->type = strdup(value);
251 if (!cur->type)
252 goto oom;
253 } else if (!strcasecmp(name, "levelFromUid")) {
254 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500255 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500256 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500257 cur->levelFrom = LEVELFROM_NONE;
258 else {
259 goto err;
260 }
261 } else if (!strcasecmp(name, "levelFrom")) {
262 if (!strcasecmp(value, "none"))
263 cur->levelFrom = LEVELFROM_NONE;
264 else if (!strcasecmp(value, "app"))
265 cur->levelFrom = LEVELFROM_APP;
266 else if (!strcasecmp(value, "user"))
267 cur->levelFrom = LEVELFROM_USER;
268 else if (!strcasecmp(value, "all"))
269 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500270 else {
271 goto err;
272 }
273 } else if (!strcasecmp(name, "level")) {
274 cur->level = strdup(value);
275 if (!cur->level)
276 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700277 } else if (!strcasecmp(name, "sebool")) {
278 cur->sebool = strdup(value);
279 if (!cur->sebool)
280 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500281 } else
282 goto err;
283
284 token = strtok_r(NULL, " \t", &saveptr);
285 if (!token)
286 break;
287 }
288
289 seapp_contexts[nspec] = cur;
290 nspec++;
291 lineno++;
292 }
293
294 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
295 seapp_context_cmp);
296
297#if DEBUG
298 {
299 int i;
300 for (i = 0; i < nspec; i++) {
301 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500302 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 -0700303 __FUNCTION__,
William Robertse3615f92013-09-11 20:35:53 -0700304 cur->isSystemServer ? "true" : "false", cur->user.str,
305 cur->seinfo, cur->name.str, cur->sebool, cur->domain,
William Roberts1b36ad02012-07-27 13:52:33 -0700306 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500307 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500308 }
309 }
310#endif
311
Stephen Smalley7446c912012-03-19 10:37:05 -0400312 ret = 0;
313
Stephen Smalleyf0740362012-01-04 12:30:47 -0500314out:
315 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400316 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500317
318err:
319 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400320 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
321 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500322 goto out;
323oom:
324 selinux_log(SELINUX_ERROR,
325 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400326 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500327 goto out;
328}
329
Stephen Smalley7446c912012-03-19 10:37:05 -0400330
331static void seapp_context_init(void)
332{
333 selinux_android_seapp_context_reload();
334}
335
Stephen Smalleyf0740362012-01-04 12:30:47 -0500336static pthread_once_t once = PTHREAD_ONCE_INIT;
337
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400338/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500339 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400340 * using the current scheme.
341 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500342#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400343
344enum seapp_kind {
345 SEAPP_TYPE,
346 SEAPP_DOMAIN
347};
348
349static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400350 uid_t uid,
351 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400352 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400353 const char *pkgname,
354 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500355{
Stephen Smalley895b4462012-09-19 16:27:36 -0400356 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700357 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400358 int i;
359 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500360 uid_t userid;
361 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500362
Stephen Smalleya8795982012-11-28 10:42:46 -0500363 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400364 appid = uid % AID_USER;
365 if (appid < AID_APP) {
366 for (n = 0; n < android_id_count; n++) {
367 if (android_ids[n].aid == appid) {
368 username = android_ids[n].name;
369 break;
370 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400371 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400372 if (!username)
373 goto err;
374 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400375 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400376 appid -= AID_APP;
377 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400378 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400379 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400380 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500381
Stephen Smalleya8795982012-11-28 10:42:46 -0500382 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400383 goto err;
384
Stephen Smalleyf0740362012-01-04 12:30:47 -0500385 for (i = 0; i < nspec; i++) {
386 cur = seapp_contexts[i];
387
Stephen Smalley895b4462012-09-19 16:27:36 -0400388 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500389 continue;
390
William Robertse3615f92013-09-11 20:35:53 -0700391 if (cur->user.str) {
392 if (cur->user.is_prefix) {
393 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500394 continue;
395 } else {
William Robertse3615f92013-09-11 20:35:53 -0700396 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500397 continue;
398 }
399 }
400
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400401 if (cur->seinfo) {
402 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
403 continue;
404 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500405
William Robertse3615f92013-09-11 20:35:53 -0700406 if (cur->name.str) {
407 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500408 continue;
William Robertse3615f92013-09-11 20:35:53 -0700409
410 if (cur->name.is_prefix) {
411 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
412 continue;
413 } else {
414 if (strcasecmp(pkgname, cur->name.str))
415 continue;
416 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500417 }
418
Stephen Smalley895b4462012-09-19 16:27:36 -0400419 if (kind == SEAPP_TYPE && !cur->type)
420 continue;
421 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500422 continue;
423
William Roberts1b36ad02012-07-27 13:52:33 -0700424 if (cur->sebool) {
425 int value = security_get_boolean_active(cur->sebool);
426 if (value == 0)
427 continue;
428 else if (value == -1) {
429 selinux_log(SELINUX_ERROR, \
430 "Could not find boolean: %s ", cur->sebool);
431 goto err;
432 }
433 }
434
Stephen Smalley895b4462012-09-19 16:27:36 -0400435 if (kind == SEAPP_TYPE) {
436 if (context_type_set(ctx, cur->type))
437 goto oom;
438 } else if (kind == SEAPP_DOMAIN) {
439 if (context_type_set(ctx, cur->domain))
440 goto oom;
441 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500442
Stephen Smalleya8795982012-11-28 10:42:46 -0500443 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500444 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500445 switch (cur->levelFrom) {
446 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500447 snprintf(level, sizeof level, "s0:c%u,c%u",
448 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500449 256 + (appid>>8 & 0xff));
450 break;
451 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500452 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500453 512 + (userid & 0xff),
454 768 + (userid>>8 & 0xff));
455 break;
456 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500457 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
458 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500459 256 + (appid>>8 & 0xff),
460 512 + (userid & 0xff),
461 768 + (userid>>8 & 0xff));
462 break;
463 default:
464 goto err;
465 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500466 if (context_range_set(ctx, level))
467 goto oom;
468 } else if (cur->level) {
469 if (context_range_set(ctx, cur->level))
470 goto oom;
471 }
William Roberts1b36ad02012-07-27 13:52:33 -0700472
Stephen Smalleyf0740362012-01-04 12:30:47 -0500473 break;
474 }
475
Stephen Smalley895b4462012-09-19 16:27:36 -0400476 if (kind == SEAPP_DOMAIN && i == nspec) {
477 /*
478 * No match.
479 * Fail to prevent staying in the zygote's context.
480 */
481 selinux_log(SELINUX_ERROR,
482 "%s: No match for app with uid %d, seinfo %s, name %s\n",
483 __FUNCTION__, uid, seinfo, pkgname);
484
485 if (security_getenforce() == 1)
486 goto err;
487 }
488
489 return 0;
490err:
491 return -1;
492oom:
493 return -2;
494}
495
496int selinux_android_setfilecon2(const char *pkgdir,
497 const char *pkgname,
498 const char *seinfo,
499 uid_t uid)
500{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700501 char *orig_ctx_str = NULL;
502 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400503 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700504 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400505
506 if (is_selinux_enabled() <= 0)
507 return 0;
508
509 __selinux_once(once, seapp_context_init);
510
511 rc = getfilecon(pkgdir, &ctx_str);
512 if (rc < 0)
513 goto err;
514
515 ctx = context_new(ctx_str);
516 orig_ctx_str = ctx_str;
517 if (!ctx)
518 goto oom;
519
520 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
521 if (rc == -1)
522 goto err;
523 else if (rc == -2)
524 goto oom;
525
Stephen Smalleyf0740362012-01-04 12:30:47 -0500526 ctx_str = context_str(ctx);
527 if (!ctx_str)
528 goto oom;
529
530 rc = security_check_context(ctx_str);
531 if (rc < 0)
532 goto err;
533
534 if (strcmp(ctx_str, orig_ctx_str)) {
535 rc = setfilecon(pkgdir, ctx_str);
536 if (rc < 0)
537 goto err;
538 }
539
540 rc = 0;
541out:
542 freecon(orig_ctx_str);
543 context_free(ctx);
544 return rc;
545err:
546 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
547 __FUNCTION__, pkgdir, uid, strerror(errno));
548 rc = -1;
549 goto out;
550oom:
551 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
552 rc = -1;
553 goto out;
554}
555
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400556int selinux_android_setfilecon(const char *pkgdir,
557 const char *pkgname,
558 uid_t uid)
559{
560 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
561}
562
Stephen Smalleyf0740362012-01-04 12:30:47 -0500563int selinux_android_setcontext(uid_t uid,
564 int isSystemServer,
565 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400566 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500567{
Stephen Smalley895b4462012-09-19 16:27:36 -0400568 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500569 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700570 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500571
572 if (is_selinux_enabled() <= 0)
573 return 0;
574
575 __selinux_once(once, seapp_context_init);
576
577 rc = getcon(&ctx_str);
578 if (rc)
579 goto err;
580
581 ctx = context_new(ctx_str);
582 orig_ctx_str = ctx_str;
583 if (!ctx)
584 goto oom;
585
Stephen Smalley895b4462012-09-19 16:27:36 -0400586 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
587 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500588 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400589 else if (rc == -2)
590 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500591
592 ctx_str = context_str(ctx);
593 if (!ctx_str)
594 goto oom;
595
596 rc = security_check_context(ctx_str);
597 if (rc < 0)
598 goto err;
599
600 if (strcmp(ctx_str, orig_ctx_str)) {
601 rc = setcon(ctx_str);
602 if (rc < 0)
603 goto err;
604 }
605
606 rc = 0;
607out:
608 freecon(orig_ctx_str);
609 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400610 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500611 return rc;
612err:
613 if (isSystemServer)
614 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700615 "%s: Error setting context for system server: %s\n",
616 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500617 else
618 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700619 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
620 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500621
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400622 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500623 goto out;
624oom:
625 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
626 rc = -1;
627 goto out;
628}
629
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400630static struct selabel_handle *sehandle = NULL;
631
Geremy Condra60646432013-04-10 17:58:48 -0700632static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
Stephen Smalley906742d2012-08-23 16:04:59 -0400633 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400634 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400635
Stephen Smalley906742d2012-08-23 16:04:59 -0400636 h = NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700637 while ((h == NULL) && opts[i].value) {
638 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400639 i++;
640 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400641
Geremy Condra60646432013-04-10 17:58:48 -0700642 return h;
643}
644
645static struct selabel_handle *file_context_open(void)
646{
647 struct selabel_handle *h;
648
649 h = get_selabel_handle(seopts);
650
Stephen Smalley906742d2012-08-23 16:04:59 -0400651 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700652 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
653 __FUNCTION__, strerror(errno));
654 return h;
655}
656
Stephen Smalley906742d2012-08-23 16:04:59 -0400657static void file_context_init(void)
658{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500659 if (!sehandle)
660 sehandle = file_context_open();
661}
662
663static int restorecon_sb(const char *pathname, const struct stat *sb)
664{
665 char *secontext = NULL;
666 char *oldsecontext = NULL;
667 int i;
668
669 if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
670 return -errno;
671
672 if (lgetfilecon(pathname, &oldsecontext) < 0) {
673 freecon(secontext);
674 return -errno;
675 }
676
677 if (strcmp(oldsecontext, secontext) != 0) {
678 if (lsetfilecon(pathname, secontext) < 0) {
679 selinux_log(SELINUX_ERROR,
680 "SELinux: Could not set context for %s to %s: %s\n",
681 pathname, secontext, strerror(errno));
682 freecon(oldsecontext);
683 freecon(secontext);
684 return -errno;
685 }
686 }
687 freecon(oldsecontext);
688 freecon(secontext);
689 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400690}
691
692static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
693
694int selinux_android_restorecon(const char *pathname)
695{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500696 struct stat sb;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400697
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500698 if (is_selinux_enabled() <= 0)
699 return 0;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700700
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500701 __selinux_once(fc_once, file_context_init);
Kenny Root20f62f32012-10-22 17:09:23 -0700702
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500703 if (!sehandle)
704 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400705
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500706 if (lstat(pathname, &sb) < 0)
707 return -errno;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400708
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500709 return restorecon_sb(pathname, &sb);
710}
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400711
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500712static int nftw_restorecon(const char* filename, const struct stat* statptr,
713 int fileflags __attribute__((unused)),
714 struct FTW* pftw __attribute__((unused)))
715{
716 restorecon_sb(filename, statptr);
717 return 0;
718}
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400719
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500720int selinux_android_restorecon_recursive(const char* pathname)
721{
722 int fd_limit = 20;
723 int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400724
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500725 if (is_selinux_enabled() <= 0)
726 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400727
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500728 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400729
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500730 if (!sehandle)
731 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400732
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500733 return nftw(pathname, nftw_restorecon, fd_limit, flags);
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400734}
rpcraig9b100832012-07-27 06:36:59 -0400735
rpcraigf1724a32012-08-01 15:35:37 -0400736struct selabel_handle* selinux_android_file_context_handle(void)
737{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500738 return file_context_open();
739}
740
741void selinux_android_set_sehandle(const struct selabel_handle *hndl)
742{
743 sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -0400744}
rpcraig9b100832012-07-27 06:36:59 -0400745
rpcraigf1724a32012-08-01 15:35:37 -0400746int selinux_android_reload_policy(void)
747{
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400748 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400749 struct stat sb;
750 void *map = NULL;
751 int i = 0;
752
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400753 while (fd < 0 && sepolicy_file[i]) {
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700754 fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -0400755 i++;
756 }
757 if (fd < 0) {
758 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
759 strerror(errno));
760 return -1;
761 }
762 if (fstat(fd, &sb) < 0) {
763 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400764 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400765 close(fd);
766 return -1;
767 }
768 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
769 if (map == MAP_FAILED) {
770 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400771 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400772 close(fd);
773 return -1;
774 }
775
776 rc = security_load_policy(map, sb.st_size);
777 if (rc < 0) {
778 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
779 strerror(errno));
780 munmap(map, sb.st_size);
781 close(fd);
782 return -1;
783 }
784
785 munmap(map, sb.st_size);
786 close(fd);
Stephen Smalleycb925042013-07-26 10:45:44 -0400787 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i-1]);
rpcraigf1724a32012-08-01 15:35:37 -0400788
789 return 0;
790}
791
792int selinux_android_load_policy(void)
793{
Nick Kralevich833cba62013-11-19 11:24:33 -0800794 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500795 int rc;
796 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
797 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400798 if (errno == ENODEV) {
799 /* SELinux not enabled in kernel */
800 return -1;
801 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500802 if (errno == ENOENT) {
803 /* Fall back to legacy mountpoint. */
804 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800805 rc = mkdir(mnt, 0755);
806 if (rc == -1 && errno != EEXIST) {
807 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
808 strerror(errno));
809 return -1;
810 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500811 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
812 }
813 }
814 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400815 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
816 strerror(errno));
817 return -1;
818 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500819 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400820
821 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400822}