blob: 8aa1ef6dac0d3df10898a47409112cb18552aa8e [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",
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
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",
William Roberts8ed42422013-04-15 16:13:30 -070050 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040051
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
William Robertse3615f92013-09-11 20:35:53 -070068struct prefix_str {
69 size_t len;
70 char *str;
71 char is_prefix;
72};
73
Stephen Smalleyf0740362012-01-04 12:30:47 -050074struct seapp_context {
75 /* input selectors */
76 char isSystemServer;
William Robertse3615f92013-09-11 20:35:53 -070077 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -050078 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -070079 struct prefix_str name;
Stephen Smalleyf0740362012-01-04 12:30:47 -050080 /* outputs */
81 char *domain;
82 char *type;
83 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070084 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050085 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050086};
87
88static int seapp_context_cmp(const void *A, const void *B)
89{
Nick Kralevich833cba62013-11-19 11:24:33 -080090 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
91 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -050092 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
93
94 /* Give precedence to isSystemServer=true. */
95 if (s1->isSystemServer != s2->isSystemServer)
96 return (s1->isSystemServer ? -1 : 1);
97
98 /* Give precedence to a specified user= over an unspecified user=. */
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;
William Robertse3615f92013-09-11 20:35:53 -0700101 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500102 return 1;
103
William Robertse3615f92013-09-11 20:35:53 -0700104 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500105 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700106 if (s1->user.is_prefix != s2->user.is_prefix)
107 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500108
109 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700110 if (s1->user.is_prefix && s1->user.len != s2->user.len)
111 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500112 }
113
114 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
115 if (s1->seinfo && !s2->seinfo)
116 return -1;
117 if (!s1->seinfo && s2->seinfo)
118 return 1;
119
120 /* Give precedence to a specified name= over an unspecified name=. */
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;
William Robertse3615f92013-09-11 20:35:53 -0700123 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500124 return 1;
125
William Robertse3615f92013-09-11 20:35:53 -0700126 if (s1->name.str) {
127 /* Give precedence to a fixed name= string over a prefix. */
128 if (s1->name.is_prefix != s2->name.is_prefix)
129 return (s2->name.is_prefix ? -1 : 1);
130
131 /* Give precedence to a longer prefix over a shorter prefix. */
132 if (s1->name.is_prefix && s1->name.len != s2->name.len)
133 return (s1->name.len > s2->name.len) ? -1 : 1;
134 }
135
William Roberts1b36ad02012-07-27 13:52:33 -0700136 /* Give precedence to a specified sebool= over an unspecified sebool=. */
137 if (s1->sebool && !s2->sebool)
138 return -1;
139 if (!s1->sebool && s2->sebool)
140 return 1;
141
Stephen Smalleyf0740362012-01-04 12:30:47 -0500142 /* Anything else has equal precedence. */
143 return 0;
144}
145
146static struct seapp_context **seapp_contexts = NULL;
147static int nspec = 0;
148
Stephen Smalley7446c912012-03-19 10:37:05 -0400149int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500150{
Stephen Smalley7446c912012-03-19 10:37:05 -0400151 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500152 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500153 char *token;
154 unsigned lineno;
155 struct seapp_context *cur;
156 char *p, *name = NULL, *value = NULL, *saveptr;
157 size_t len;
Stephen Smalley300bebb2013-04-16 15:33:16 -0400158 int i = 0, n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500159
Stephen Smalley7446c912012-03-19 10:37:05 -0400160 while ((fp==NULL) && seapp_contexts_file[i])
161 fp = fopen(seapp_contexts_file[i++], "r");
162
Stephen Smalleyf0740362012-01-04 12:30:47 -0500163 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400164 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
165 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500166 }
167
Stephen Smalley300bebb2013-04-16 15:33:16 -0400168 if (seapp_contexts) {
169 for (n = 0; n < nspec; n++) {
170 cur = seapp_contexts[n];
William Robertse3615f92013-09-11 20:35:53 -0700171 free(cur->user.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400172 free(cur->seinfo);
William Robertse3615f92013-09-11 20:35:53 -0700173 free(cur->name.str);
Stephen Smalley300bebb2013-04-16 15:33:16 -0400174 free(cur->domain);
175 free(cur->type);
176 free(cur->level);
177 free(cur->sebool);
178 }
179 free(seapp_contexts);
180 }
181
Stephen Smalleyf0740362012-01-04 12:30:47 -0500182 nspec = 0;
183 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
184 p = line_buf;
185 while (isspace(*p))
186 p++;
187 if (*p == '#' || *p == 0)
188 continue;
189 nspec++;
190 }
191
Nick Kralevich833cba62013-11-19 11:24:33 -0800192 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500193 if (!seapp_contexts)
194 goto oom;
195
196 rewind(fp);
197 nspec = 0;
198 lineno = 1;
199 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
200 len = strlen(line_buf);
201 if (line_buf[len - 1] == '\n')
202 line_buf[len - 1] = 0;
203 p = line_buf;
204 while (isspace(*p))
205 p++;
206 if (*p == '#' || *p == 0)
207 continue;
208
Nick Kralevich833cba62013-11-19 11:24:33 -0800209 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500210 if (!cur)
211 goto oom;
212
213 token = strtok_r(p, " \t", &saveptr);
214 if (!token)
215 goto err;
216
217 while (1) {
218 name = token;
219 value = strchr(name, '=');
220 if (!value)
221 goto err;
222 *value++ = 0;
223
224 if (!strcasecmp(name, "isSystemServer")) {
225 if (!strcasecmp(value, "true"))
226 cur->isSystemServer = 1;
227 else if (!strcasecmp(value, "false"))
228 cur->isSystemServer = 0;
229 else {
230 goto err;
231 }
232 } else if (!strcasecmp(name, "user")) {
William Robertse3615f92013-09-11 20:35:53 -0700233 cur->user.str = strdup(value);
234 if (!cur->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500235 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700236 cur->user.len = strlen(cur->user.str);
237 if (cur->user.str[cur->user.len-1] == '*')
238 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500239 } else if (!strcasecmp(name, "seinfo")) {
240 cur->seinfo = strdup(value);
241 if (!cur->seinfo)
242 goto oom;
243 } else if (!strcasecmp(name, "name")) {
William Robertse3615f92013-09-11 20:35:53 -0700244 cur->name.str = strdup(value);
245 if (!cur->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500246 goto oom;
William Robertse3615f92013-09-11 20:35:53 -0700247 cur->name.len = strlen(cur->name.str);
248 if (cur->name.str[cur->name.len-1] == '*')
249 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500250 } else if (!strcasecmp(name, "domain")) {
251 cur->domain = strdup(value);
252 if (!cur->domain)
253 goto oom;
254 } else if (!strcasecmp(name, "type")) {
255 cur->type = strdup(value);
256 if (!cur->type)
257 goto oom;
258 } else if (!strcasecmp(name, "levelFromUid")) {
259 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500260 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500261 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500262 cur->levelFrom = LEVELFROM_NONE;
263 else {
264 goto err;
265 }
266 } else if (!strcasecmp(name, "levelFrom")) {
267 if (!strcasecmp(value, "none"))
268 cur->levelFrom = LEVELFROM_NONE;
269 else if (!strcasecmp(value, "app"))
270 cur->levelFrom = LEVELFROM_APP;
271 else if (!strcasecmp(value, "user"))
272 cur->levelFrom = LEVELFROM_USER;
273 else if (!strcasecmp(value, "all"))
274 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500275 else {
276 goto err;
277 }
278 } else if (!strcasecmp(name, "level")) {
279 cur->level = strdup(value);
280 if (!cur->level)
281 goto oom;
William Roberts1b36ad02012-07-27 13:52:33 -0700282 } else if (!strcasecmp(name, "sebool")) {
283 cur->sebool = strdup(value);
284 if (!cur->sebool)
285 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500286 } else
287 goto err;
288
289 token = strtok_r(NULL, " \t", &saveptr);
290 if (!token)
291 break;
292 }
293
294 seapp_contexts[nspec] = cur;
295 nspec++;
296 lineno++;
297 }
298
299 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
300 seapp_context_cmp);
301
302#if DEBUG
303 {
304 int i;
305 for (i = 0; i < nspec; i++) {
306 cur = seapp_contexts[i];
Stephen Smalleya8795982012-11-28 10:42:46 -0500307 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 -0700308 __FUNCTION__,
William Robertse3615f92013-09-11 20:35:53 -0700309 cur->isSystemServer ? "true" : "false", cur->user.str,
310 cur->seinfo, cur->name.str, cur->sebool, cur->domain,
William Roberts1b36ad02012-07-27 13:52:33 -0700311 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500312 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500313 }
314 }
315#endif
316
Stephen Smalley7446c912012-03-19 10:37:05 -0400317 ret = 0;
318
Stephen Smalleyf0740362012-01-04 12:30:47 -0500319out:
320 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400321 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500322
323err:
324 selinux_log(SELINUX_ERROR, "%s: Error reading %s, line %u, name %s, value %s\n",
Stephen Smalley7446c912012-03-19 10:37:05 -0400325 __FUNCTION__, seapp_contexts_file[i - 1], lineno, name, value);
326 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500327 goto out;
328oom:
329 selinux_log(SELINUX_ERROR,
330 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley7446c912012-03-19 10:37:05 -0400331 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500332 goto out;
333}
334
Stephen Smalley7446c912012-03-19 10:37:05 -0400335
336static void seapp_context_init(void)
337{
338 selinux_android_seapp_context_reload();
339}
340
Stephen Smalleyf0740362012-01-04 12:30:47 -0500341static pthread_once_t once = PTHREAD_ONCE_INIT;
342
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400343/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500344 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400345 * using the current scheme.
346 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500347#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400348
349enum seapp_kind {
350 SEAPP_TYPE,
351 SEAPP_DOMAIN
352};
353
354static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400355 uid_t uid,
356 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400357 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400358 const char *pkgname,
359 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500360{
Stephen Smalley895b4462012-09-19 16:27:36 -0400361 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700362 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400363 int i;
364 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500365 uid_t userid;
366 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500367
Stephen Smalleya8795982012-11-28 10:42:46 -0500368 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400369 appid = uid % AID_USER;
370 if (appid < AID_APP) {
371 for (n = 0; n < android_id_count; n++) {
372 if (android_ids[n].aid == appid) {
373 username = android_ids[n].name;
374 break;
375 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400376 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400377 if (!username)
378 goto err;
379 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400380 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400381 appid -= AID_APP;
382 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400383 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400384 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400385 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500386
Stephen Smalleya8795982012-11-28 10:42:46 -0500387 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400388 goto err;
389
Stephen Smalleyf0740362012-01-04 12:30:47 -0500390 for (i = 0; i < nspec; i++) {
391 cur = seapp_contexts[i];
392
Stephen Smalley895b4462012-09-19 16:27:36 -0400393 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500394 continue;
395
William Robertse3615f92013-09-11 20:35:53 -0700396 if (cur->user.str) {
397 if (cur->user.is_prefix) {
398 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500399 continue;
400 } else {
William Robertse3615f92013-09-11 20:35:53 -0700401 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500402 continue;
403 }
404 }
405
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400406 if (cur->seinfo) {
407 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
408 continue;
409 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500410
William Robertse3615f92013-09-11 20:35:53 -0700411 if (cur->name.str) {
412 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500413 continue;
William Robertse3615f92013-09-11 20:35:53 -0700414
415 if (cur->name.is_prefix) {
416 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
417 continue;
418 } else {
419 if (strcasecmp(pkgname, cur->name.str))
420 continue;
421 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500422 }
423
Stephen Smalley895b4462012-09-19 16:27:36 -0400424 if (kind == SEAPP_TYPE && !cur->type)
425 continue;
426 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500427 continue;
428
William Roberts1b36ad02012-07-27 13:52:33 -0700429 if (cur->sebool) {
430 int value = security_get_boolean_active(cur->sebool);
431 if (value == 0)
432 continue;
433 else if (value == -1) {
434 selinux_log(SELINUX_ERROR, \
435 "Could not find boolean: %s ", cur->sebool);
436 goto err;
437 }
438 }
439
Stephen Smalley895b4462012-09-19 16:27:36 -0400440 if (kind == SEAPP_TYPE) {
441 if (context_type_set(ctx, cur->type))
442 goto oom;
443 } else if (kind == SEAPP_DOMAIN) {
444 if (context_type_set(ctx, cur->domain))
445 goto oom;
446 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500447
Stephen Smalleya8795982012-11-28 10:42:46 -0500448 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500449 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500450 switch (cur->levelFrom) {
451 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500452 snprintf(level, sizeof level, "s0:c%u,c%u",
453 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500454 256 + (appid>>8 & 0xff));
455 break;
456 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500457 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500458 512 + (userid & 0xff),
459 768 + (userid>>8 & 0xff));
460 break;
461 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500462 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
463 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500464 256 + (appid>>8 & 0xff),
465 512 + (userid & 0xff),
466 768 + (userid>>8 & 0xff));
467 break;
468 default:
469 goto err;
470 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500471 if (context_range_set(ctx, level))
472 goto oom;
473 } else if (cur->level) {
474 if (context_range_set(ctx, cur->level))
475 goto oom;
476 }
William Roberts1b36ad02012-07-27 13:52:33 -0700477
Stephen Smalleyf0740362012-01-04 12:30:47 -0500478 break;
479 }
480
Stephen Smalley895b4462012-09-19 16:27:36 -0400481 if (kind == SEAPP_DOMAIN && i == nspec) {
482 /*
483 * No match.
484 * Fail to prevent staying in the zygote's context.
485 */
486 selinux_log(SELINUX_ERROR,
487 "%s: No match for app with uid %d, seinfo %s, name %s\n",
488 __FUNCTION__, uid, seinfo, pkgname);
489
490 if (security_getenforce() == 1)
491 goto err;
492 }
493
494 return 0;
495err:
496 return -1;
497oom:
498 return -2;
499}
500
501int selinux_android_setfilecon2(const char *pkgdir,
502 const char *pkgname,
503 const char *seinfo,
504 uid_t uid)
505{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700506 char *orig_ctx_str = NULL;
507 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400508 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700509 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400510
511 if (is_selinux_enabled() <= 0)
512 return 0;
513
514 __selinux_once(once, seapp_context_init);
515
516 rc = getfilecon(pkgdir, &ctx_str);
517 if (rc < 0)
518 goto err;
519
520 ctx = context_new(ctx_str);
521 orig_ctx_str = ctx_str;
522 if (!ctx)
523 goto oom;
524
525 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, ctx);
526 if (rc == -1)
527 goto err;
528 else if (rc == -2)
529 goto oom;
530
Stephen Smalleyf0740362012-01-04 12:30:47 -0500531 ctx_str = context_str(ctx);
532 if (!ctx_str)
533 goto oom;
534
535 rc = security_check_context(ctx_str);
536 if (rc < 0)
537 goto err;
538
539 if (strcmp(ctx_str, orig_ctx_str)) {
540 rc = setfilecon(pkgdir, ctx_str);
541 if (rc < 0)
542 goto err;
543 }
544
545 rc = 0;
546out:
547 freecon(orig_ctx_str);
548 context_free(ctx);
549 return rc;
550err:
551 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
552 __FUNCTION__, pkgdir, uid, strerror(errno));
553 rc = -1;
554 goto out;
555oom:
556 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
557 rc = -1;
558 goto out;
559}
560
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400561int selinux_android_setfilecon(const char *pkgdir,
562 const char *pkgname,
563 uid_t uid)
564{
565 return selinux_android_setfilecon2(pkgdir, pkgname, NULL, uid);
566}
567
Stephen Smalleyf0740362012-01-04 12:30:47 -0500568int selinux_android_setcontext(uid_t uid,
569 int isSystemServer,
570 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400571 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500572{
Stephen Smalley895b4462012-09-19 16:27:36 -0400573 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500574 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700575 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500576
577 if (is_selinux_enabled() <= 0)
578 return 0;
579
580 __selinux_once(once, seapp_context_init);
581
582 rc = getcon(&ctx_str);
583 if (rc)
584 goto err;
585
586 ctx = context_new(ctx_str);
587 orig_ctx_str = ctx_str;
588 if (!ctx)
589 goto oom;
590
Stephen Smalley895b4462012-09-19 16:27:36 -0400591 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
592 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500593 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400594 else if (rc == -2)
595 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500596
597 ctx_str = context_str(ctx);
598 if (!ctx_str)
599 goto oom;
600
601 rc = security_check_context(ctx_str);
602 if (rc < 0)
603 goto err;
604
605 if (strcmp(ctx_str, orig_ctx_str)) {
606 rc = setcon(ctx_str);
607 if (rc < 0)
608 goto err;
609 }
610
611 rc = 0;
612out:
613 freecon(orig_ctx_str);
614 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400615 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500616 return rc;
617err:
618 if (isSystemServer)
619 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700620 "%s: Error setting context for system server: %s\n",
621 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500622 else
623 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700624 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
625 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500626
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400627 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500628 goto out;
629oom:
630 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
631 rc = -1;
632 goto out;
633}
634
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400635static struct selabel_handle *sehandle = NULL;
636
Geremy Condra60646432013-04-10 17:58:48 -0700637static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[]) {
Stephen Smalley906742d2012-08-23 16:04:59 -0400638 struct selabel_handle *h;
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400639 int i = 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400640
Stephen Smalley906742d2012-08-23 16:04:59 -0400641 h = NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700642 while ((h == NULL) && opts[i].value) {
643 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
Stephen Smalley32ebfe82012-03-20 13:05:37 -0400644 i++;
645 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400646
Geremy Condra60646432013-04-10 17:58:48 -0700647 return h;
648}
649
650static struct selabel_handle *file_context_open(void)
651{
652 struct selabel_handle *h;
653
654 h = get_selabel_handle(seopts);
655
Stephen Smalley906742d2012-08-23 16:04:59 -0400656 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700657 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
658 __FUNCTION__, strerror(errno));
659 return h;
660}
661
662static struct selabel_handle *file_context_backup_open(void)
663{
664 struct selabel_handle *h;
665
666 h = get_selabel_handle(seopt_backup);
667
668 if (!h)
669 selinux_log(SELINUX_ERROR, "%s: Error getting backup file context handle (%s)\n",
670 __FUNCTION__, strerror(errno));
Stephen Smalley906742d2012-08-23 16:04:59 -0400671 return h;
672}
673
674static void file_context_init(void)
675{
676 sehandle = file_context_open();
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400677}
678
679static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
680
681int selinux_android_restorecon(const char *pathname)
682{
683
Nick Kralevich9ca40882013-07-11 16:58:44 -0700684 char* oldcontext = NULL;
685 char* newcontext = NULL;
686 struct stat sb;
687 int ret = -1;
688
Kenny Root20f62f32012-10-22 17:09:23 -0700689 if (is_selinux_enabled() <= 0)
690 return 0;
691
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400692 __selinux_once(fc_once, file_context_init);
693
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400694 if (!sehandle)
695 goto bail;
696
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400697 if (lstat(pathname, &sb) < 0)
698 goto err;
699
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400700 if (lgetfilecon(pathname, &oldcontext) < 0)
701 goto err;
702
703 if (selabel_lookup(sehandle, &newcontext, pathname, sb.st_mode) < 0)
704 goto err;
705
706 if (strcmp(newcontext, "<<none>>") && strcmp(oldcontext, newcontext))
707 if (lsetfilecon(pathname, newcontext) < 0)
708 goto err;
709
710 ret = 0;
711out:
712 if (oldcontext)
713 freecon(oldcontext);
714 if (newcontext)
715 freecon(newcontext);
716
717 return ret;
718
719err:
720 selinux_log(SELINUX_ERROR,
721 "%s: Error restoring context for %s (%s)\n",
722 __FUNCTION__, pathname, strerror(errno));
723
724bail:
725 ret = -1;
726 goto out;
727}
rpcraig9b100832012-07-27 06:36:59 -0400728
rpcraigf1724a32012-08-01 15:35:37 -0400729struct selabel_handle* selinux_android_file_context_handle(void)
730{
Geremy Condra60646432013-04-10 17:58:48 -0700731 return file_context_open();
rpcraigf1724a32012-08-01 15:35:37 -0400732}
rpcraig9b100832012-07-27 06:36:59 -0400733
rpcraigf1724a32012-08-01 15:35:37 -0400734int selinux_android_reload_policy(void)
735{
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400736 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -0400737 struct stat sb;
738 void *map = NULL;
739 int i = 0;
740
Stephen Smalley4a655ec2012-09-18 15:08:32 -0400741 while (fd < 0 && sepolicy_file[i]) {
Nick Kralevich9c30ac62013-05-06 12:03:07 -0700742 fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -0400743 i++;
744 }
745 if (fd < 0) {
746 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
747 strerror(errno));
748 return -1;
749 }
750 if (fstat(fd, &sb) < 0) {
751 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400752 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400753 close(fd);
754 return -1;
755 }
756 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
757 if (map == MAP_FAILED) {
758 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -0400759 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -0400760 close(fd);
761 return -1;
762 }
763
764 rc = security_load_policy(map, sb.st_size);
765 if (rc < 0) {
766 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
767 strerror(errno));
768 munmap(map, sb.st_size);
769 close(fd);
770 return -1;
771 }
772
773 munmap(map, sb.st_size);
774 close(fd);
Stephen Smalleycb925042013-07-26 10:45:44 -0400775 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i-1]);
rpcraigf1724a32012-08-01 15:35:37 -0400776
777 return 0;
778}
779
780int selinux_android_load_policy(void)
781{
Nick Kralevich833cba62013-11-19 11:24:33 -0800782 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500783 int rc;
784 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
785 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400786 if (errno == ENODEV) {
787 /* SELinux not enabled in kernel */
788 return -1;
789 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500790 if (errno == ENOENT) {
791 /* Fall back to legacy mountpoint. */
792 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -0800793 rc = mkdir(mnt, 0755);
794 if (rc == -1 && errno != EEXIST) {
795 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
796 strerror(errno));
797 return -1;
798 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500799 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
800 }
801 }
802 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -0400803 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
804 strerror(errno));
805 return -1;
806 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -0500807 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -0400808
809 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -0400810}