blob: 7773489885cdeeefd79a032895cf3848fb293513 [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>
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>
Stephen Smalley826cc292014-01-28 15:04:22 -050015#include <sys/xattr.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050016#include <fcntl.h>
Stephen Smalley08587cf2014-01-30 10:13:12 -050017#include <fts.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050018#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>
Riley Spahnbad0ebb2014-06-11 16:07:53 -070025#include <log/log.h>
Stephen Smalleyd10c3432012-11-05 11:49:35 -050026#include "policy.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050027#include "callbacks.h"
28#include "selinux_internal.h"
Stephen Smalley0e7340f2014-04-30 15:13:30 -070029#include "label_internal.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050030
31/*
32 * XXX Where should this configuration file be located?
33 * Needs to be accessible by zygote and installd when
34 * setting credentials for app processes and setting permissions
35 * on app data directories.
36 */
Stephen Smalley7446c912012-03-19 10:37:05 -040037static char const * const seapp_contexts_file[] = {
Stephen Smalley7446c912012-03-19 10:37:05 -040038 "/seapp_contexts",
Robert Craig5b5183f2014-03-17 20:53:06 -040039 "/data/security/current/seapp_contexts",
William Roberts8ed42422013-04-15 16:13:30 -070040 NULL };
Stephen Smalleyf0740362012-01-04 12:30:47 -050041
Stephen Smalley32ebfe82012-03-20 13:05:37 -040042static const struct selinux_opt seopts[] = {
Stephen Smalley32ebfe82012-03-20 13:05:37 -040043 { SELABEL_OPT_PATH, "/file_contexts" },
Robert Craig5b5183f2014-03-17 20:53:06 -040044 { SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
Stephen Smalley32ebfe82012-03-20 13:05:37 -040045 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040046
Stephen Smalley4a655ec2012-09-18 15:08:32 -040047static const char *const sepolicy_file[] = {
Robert Craig5b5183f2014-03-17 20:53:06 -040048 "/sepolicy",
49 "/data/security/current/sepolicy",
50 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040051
dcashman965141a2014-12-03 12:51:50 -080052static const struct selinux_opt seopts_prop[] = {
53 { SELABEL_OPT_PATH, "/property_contexts" },
54 { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
55 { 0, NULL }
56};
57
Riley Spahnbad0ebb2014-06-11 16:07:53 -070058static const struct selinux_opt seopts_service[] = {
59 { SELABEL_OPT_PATH, "/service_contexts" },
60 { SELABEL_OPT_PATH, "/data/security/current/service_contexts" },
61 { 0, NULL }
62};
63
Stephen Smalleya8795982012-11-28 10:42:46 -050064enum levelFrom {
65 LEVELFROM_NONE,
66 LEVELFROM_APP,
67 LEVELFROM_USER,
68 LEVELFROM_ALL
69};
70
Robert Craig5b5183f2014-03-17 20:53:06 -040071#define POLICY_OVERRIDE_VERSION "/data/security/current/selinux_version"
72#define POLICY_BASE_VERSION "/selinux_version"
73static int policy_index = 0;
74
75static void set_policy_index(void)
76{
77 int fd_base = -1, fd_override = -1;
78 struct stat sb_base;
79 struct stat sb_override;
80 void *map_base, *map_override;
81
82 policy_index = 0;
83
84 fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW);
85 if (fd_base < 0)
86 return;
87
Stephen Smalley1e9d2762015-02-19 09:42:58 -050088 if (fstat(fd_base, &sb_base) < 0)
89 goto close_base;
Robert Craig5b5183f2014-03-17 20:53:06 -040090
91 fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW);
Stephen Smalley1e9d2762015-02-19 09:42:58 -050092 if (fd_override < 0)
93 goto close_base;
Robert Craig5b5183f2014-03-17 20:53:06 -040094
Stephen Smalley1e9d2762015-02-19 09:42:58 -050095 if (fstat(fd_override, &sb_override) < 0)
96 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -040097
Stephen Smalley1e9d2762015-02-19 09:42:58 -050098 if (sb_base.st_size != sb_override.st_size)
99 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400100
101 map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500102 if (map_base == MAP_FAILED)
103 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400104
105 map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500106 if (map_override == MAP_FAILED)
107 goto unmap_base;
Robert Craig5b5183f2014-03-17 20:53:06 -0400108
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500109 if (memcmp(map_base, map_override, sb_base.st_size) != 0)
110 goto unmap_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400111
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500112 if (access(sepolicy_file[1], R_OK) != 0)
113 goto unmap_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400114
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500115 if (access(seopts[1].value, R_OK) != 0)
116 goto unmap_override;
117
118 if (access(seopts_prop[1].value, R_OK) != 0)
119 goto unmap_override;
120
121 if (access(seopts_service[1].value, R_OK) != 0)
122 goto unmap_override;
123
124 if (access(seapp_contexts_file[1], R_OK) != 0)
125 goto unmap_override;
126
127 policy_index = 1;
128
129unmap_override:
Robert Craig5b5183f2014-03-17 20:53:06 -0400130 munmap(map_override, sb_override.st_size);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500131unmap_base:
132 munmap(map_base, sb_base.st_size);
133close_override:
134 close(fd_override);
135close_base:
136 close(fd_base);
137 return;
Robert Craig5b5183f2014-03-17 20:53:06 -0400138}
139
Stephen Smalleya8795982012-11-28 10:42:46 -0500140#if DEBUG
141static char const * const levelFromName[] = {
142 "none",
143 "app",
144 "user",
145 "all"
146};
147#endif
148
William Robertse3615f92013-09-11 20:35:53 -0700149struct prefix_str {
150 size_t len;
151 char *str;
152 char is_prefix;
153};
154
Stephen Smalley13319cf2014-04-04 15:44:23 -0400155static void free_prefix_str(struct prefix_str *p)
156{
157 if (!p)
158 return;
159 free(p->str);
160}
161
Stephen Smalleyf0740362012-01-04 12:30:47 -0500162struct seapp_context {
163 /* input selectors */
164 char isSystemServer;
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400165 bool isOwnerSet;
166 bool isOwner;
William Robertse3615f92013-09-11 20:35:53 -0700167 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500168 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -0700169 struct prefix_str name;
Stephen Smalley274e0f62014-02-19 10:53:09 -0500170 struct prefix_str path;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500171 /* outputs */
172 char *domain;
173 char *type;
174 char *level;
Stephen Smalleya8795982012-11-28 10:42:46 -0500175 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500176};
177
Stephen Smalley13319cf2014-04-04 15:44:23 -0400178static void free_seapp_context(struct seapp_context *s)
179{
180 if (!s)
181 return;
182
183 free_prefix_str(&s->user);
184 free(s->seinfo);
185 free_prefix_str(&s->name);
186 free_prefix_str(&s->path);
187 free(s->domain);
188 free(s->type);
189 free(s->level);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400190}
191
Stephen Smalleyf0740362012-01-04 12:30:47 -0500192static int seapp_context_cmp(const void *A, const void *B)
193{
Nick Kralevich833cba62013-11-19 11:24:33 -0800194 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
195 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500196 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
197
198 /* Give precedence to isSystemServer=true. */
199 if (s1->isSystemServer != s2->isSystemServer)
200 return (s1->isSystemServer ? -1 : 1);
201
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400202 /* Give precedence to a specified isOwner= over an unspecified isOwner=. */
203 if (s1->isOwnerSet != s2->isOwnerSet)
204 return (s1->isOwnerSet ? -1 : 1);
205
Stephen Smalleyf0740362012-01-04 12:30:47 -0500206 /* Give precedence to a specified user= over an unspecified user=. */
William Robertse3615f92013-09-11 20:35:53 -0700207 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500208 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700209 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500210 return 1;
211
William Robertse3615f92013-09-11 20:35:53 -0700212 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500213 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700214 if (s1->user.is_prefix != s2->user.is_prefix)
215 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500216
217 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700218 if (s1->user.is_prefix && s1->user.len != s2->user.len)
219 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500220 }
221
222 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
223 if (s1->seinfo && !s2->seinfo)
224 return -1;
225 if (!s1->seinfo && s2->seinfo)
226 return 1;
227
228 /* Give precedence to a specified name= over an unspecified name=. */
William Robertse3615f92013-09-11 20:35:53 -0700229 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500230 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700231 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500232 return 1;
233
William Robertse3615f92013-09-11 20:35:53 -0700234 if (s1->name.str) {
235 /* Give precedence to a fixed name= string over a prefix. */
236 if (s1->name.is_prefix != s2->name.is_prefix)
237 return (s2->name.is_prefix ? -1 : 1);
238
239 /* Give precedence to a longer prefix over a shorter prefix. */
240 if (s1->name.is_prefix && s1->name.len != s2->name.len)
241 return (s1->name.len > s2->name.len) ? -1 : 1;
242 }
243
Stephen Smalley274e0f62014-02-19 10:53:09 -0500244 /* Give precedence to a specified path= over an unspecified path=. */
245 if (s1->path.str && !s2->path.str)
246 return -1;
247 if (!s1->path.str && s2->path.str)
248 return 1;
249
250 if (s1->path.str) {
251 /* Give precedence to a fixed path= string over a prefix. */
252 if (s1->path.is_prefix != s2->path.is_prefix)
253 return (s2->path.is_prefix ? -1 : 1);
254
255 /* Give precedence to a longer prefix over a shorter prefix. */
256 if (s1->path.is_prefix && s1->path.len != s2->path.len)
257 return (s1->path.len > s2->path.len) ? -1 : 1;
258 }
259
Stephen Smalleyf0740362012-01-04 12:30:47 -0500260 /* Anything else has equal precedence. */
261 return 0;
262}
263
264static struct seapp_context **seapp_contexts = NULL;
265static int nspec = 0;
266
Stephen Smalley13319cf2014-04-04 15:44:23 -0400267static void free_seapp_contexts(void)
268{
269 int n;
270
271 if (!seapp_contexts)
272 return;
273
274 for (n = 0; n < nspec; n++)
275 free_seapp_context(seapp_contexts[n]);
276
277 free(seapp_contexts);
278 seapp_contexts = NULL;
279 nspec = 0;
280}
281
Stephen Smalley7446c912012-03-19 10:37:05 -0400282int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500283{
Stephen Smalley7446c912012-03-19 10:37:05 -0400284 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500285 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500286 char *token;
287 unsigned lineno;
288 struct seapp_context *cur;
289 char *p, *name = NULL, *value = NULL, *saveptr;
290 size_t len;
Robert Craig5b5183f2014-03-17 20:53:06 -0400291 int n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500292
Robert Craig5b5183f2014-03-17 20:53:06 -0400293 set_policy_index();
Stephen Smalley7446c912012-03-19 10:37:05 -0400294
Robert Craig5b5183f2014-03-17 20:53:06 -0400295 fp = fopen(seapp_contexts_file[policy_index], "r");
Stephen Smalleyf0740362012-01-04 12:30:47 -0500296 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400297 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
298 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500299 }
300
Stephen Smalley13319cf2014-04-04 15:44:23 -0400301 free_seapp_contexts();
Stephen Smalley300bebb2013-04-16 15:33:16 -0400302
Stephen Smalleyf0740362012-01-04 12:30:47 -0500303 nspec = 0;
304 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
305 p = line_buf;
306 while (isspace(*p))
307 p++;
308 if (*p == '#' || *p == 0)
309 continue;
310 nspec++;
311 }
312
Nick Kralevich833cba62013-11-19 11:24:33 -0800313 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500314 if (!seapp_contexts)
315 goto oom;
316
317 rewind(fp);
318 nspec = 0;
319 lineno = 1;
320 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
321 len = strlen(line_buf);
322 if (line_buf[len - 1] == '\n')
323 line_buf[len - 1] = 0;
324 p = line_buf;
325 while (isspace(*p))
326 p++;
327 if (*p == '#' || *p == 0)
328 continue;
329
Nick Kralevich833cba62013-11-19 11:24:33 -0800330 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500331 if (!cur)
332 goto oom;
333
334 token = strtok_r(p, " \t", &saveptr);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400335 if (!token) {
336 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500337 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400338 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500339
340 while (1) {
341 name = token;
342 value = strchr(name, '=');
Stephen Smalley13319cf2014-04-04 15:44:23 -0400343 if (!value) {
344 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500345 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400346 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500347 *value++ = 0;
348
349 if (!strcasecmp(name, "isSystemServer")) {
350 if (!strcasecmp(value, "true"))
351 cur->isSystemServer = 1;
352 else if (!strcasecmp(value, "false"))
353 cur->isSystemServer = 0;
354 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400355 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500356 goto err;
357 }
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400358 } else if (!strcasecmp(name, "isOwner")) {
359 cur->isOwnerSet = true;
360 if (!strcasecmp(value, "true"))
361 cur->isOwner = true;
362 else if (!strcasecmp(value, "false"))
363 cur->isOwner = false;
364 else {
365 free_seapp_context(cur);
366 goto err;
367 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500368 } else if (!strcasecmp(name, "user")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500369 if (cur->user.str) {
370 free_seapp_context(cur);
371 goto err;
372 }
William Robertse3615f92013-09-11 20:35:53 -0700373 cur->user.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400374 if (!cur->user.str) {
375 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500376 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400377 }
William Robertse3615f92013-09-11 20:35:53 -0700378 cur->user.len = strlen(cur->user.str);
379 if (cur->user.str[cur->user.len-1] == '*')
380 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500381 } else if (!strcasecmp(name, "seinfo")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500382 if (cur->seinfo) {
383 free_seapp_context(cur);
384 goto err;
385 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500386 cur->seinfo = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400387 if (!cur->seinfo) {
388 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500389 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400390 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500391 } else if (!strcasecmp(name, "name")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500392 if (cur->name.str) {
393 free_seapp_context(cur);
394 goto err;
395 }
William Robertse3615f92013-09-11 20:35:53 -0700396 cur->name.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400397 if (!cur->name.str) {
398 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500399 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400400 }
William Robertse3615f92013-09-11 20:35:53 -0700401 cur->name.len = strlen(cur->name.str);
402 if (cur->name.str[cur->name.len-1] == '*')
403 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500404 } else if (!strcasecmp(name, "domain")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500405 if (cur->domain) {
406 free_seapp_context(cur);
407 goto err;
408 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500409 cur->domain = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400410 if (!cur->domain) {
411 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500412 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400413 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500414 } else if (!strcasecmp(name, "type")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500415 if (cur->type) {
416 free_seapp_context(cur);
417 goto err;
418 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500419 cur->type = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400420 if (!cur->type) {
421 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500422 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400423 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500424 } else if (!strcasecmp(name, "levelFromUid")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500425 if (cur->levelFrom) {
426 free_seapp_context(cur);
427 goto err;
428 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500429 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500430 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500431 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500432 cur->levelFrom = LEVELFROM_NONE;
433 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400434 free_seapp_context(cur);
Stephen Smalleya8795982012-11-28 10:42:46 -0500435 goto err;
436 }
437 } else if (!strcasecmp(name, "levelFrom")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500438 if (cur->levelFrom) {
439 free_seapp_context(cur);
440 goto err;
441 }
Stephen Smalleya8795982012-11-28 10:42:46 -0500442 if (!strcasecmp(value, "none"))
443 cur->levelFrom = LEVELFROM_NONE;
444 else if (!strcasecmp(value, "app"))
445 cur->levelFrom = LEVELFROM_APP;
446 else if (!strcasecmp(value, "user"))
447 cur->levelFrom = LEVELFROM_USER;
448 else if (!strcasecmp(value, "all"))
449 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500450 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400451 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500452 goto err;
453 }
454 } else if (!strcasecmp(name, "level")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500455 if (cur->level) {
456 free_seapp_context(cur);
457 goto err;
458 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500459 cur->level = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400460 if (!cur->level) {
461 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500462 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400463 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500464 } else if (!strcasecmp(name, "path")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500465 if (cur->path.str) {
466 free_seapp_context(cur);
467 goto err;
468 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500469 cur->path.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400470 if (!cur->path.str) {
471 free_seapp_context(cur);
Stephen Smalley274e0f62014-02-19 10:53:09 -0500472 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400473 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500474 cur->path.len = strlen(cur->path.str);
475 if (cur->path.str[cur->path.len-1] == '*')
476 cur->path.is_prefix = 1;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400477 } else {
478 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500479 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400480 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500481
482 token = strtok_r(NULL, " \t", &saveptr);
483 if (!token)
484 break;
485 }
486
Stephen Smalley13319cf2014-04-04 15:44:23 -0400487 if (cur->name.str &&
488 (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
489 selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400490 seapp_contexts_file[policy_index], cur->name.str, lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400491 free_seapp_context(cur);
492 goto err;
493 }
494
Stephen Smalleyf0740362012-01-04 12:30:47 -0500495 seapp_contexts[nspec] = cur;
496 nspec++;
497 lineno++;
498 }
499
500 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
501 seapp_context_cmp);
502
503#if DEBUG
504 {
505 int i;
506 for (i = 0; i < nspec; i++) {
507 cur = seapp_contexts[i];
Stephen Smalley3fb00962015-02-13 15:59:32 -0500508 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isOwner=%s user=%s seinfo=%s name=%s path=%s -> domain=%s type=%s level=%s levelFrom=%s",
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400509 __FUNCTION__,
510 cur->isSystemServer ? "true" : "false",
511 cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null",
512 cur->user.str,
Stephen Smalley3fb00962015-02-13 15:59:32 -0500513 cur->seinfo, cur->name.str, cur->path.str, cur->domain,
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400514 cur->type, cur->level,
515 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500516 }
517 }
518#endif
519
Stephen Smalley7446c912012-03-19 10:37:05 -0400520 ret = 0;
521
Stephen Smalleyf0740362012-01-04 12:30:47 -0500522out:
523 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400524 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500525
526err:
Stephen Smalley13319cf2014-04-04 15:44:23 -0400527 selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400528 seapp_contexts_file[policy_index], lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400529 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400530 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500531 goto out;
532oom:
533 selinux_log(SELINUX_ERROR,
534 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400535 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400536 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500537 goto out;
538}
539
Stephen Smalley7446c912012-03-19 10:37:05 -0400540
541static void seapp_context_init(void)
542{
543 selinux_android_seapp_context_reload();
544}
545
Stephen Smalleyf0740362012-01-04 12:30:47 -0500546static pthread_once_t once = PTHREAD_ONCE_INIT;
547
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400548/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500549 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400550 * using the current scheme.
551 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500552#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400553
554enum seapp_kind {
555 SEAPP_TYPE,
556 SEAPP_DOMAIN
557};
558
559static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400560 uid_t uid,
561 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400562 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400563 const char *pkgname,
Stephen Smalley274e0f62014-02-19 10:53:09 -0500564 const char *path,
Stephen Smalley895b4462012-09-19 16:27:36 -0400565 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500566{
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400567 bool isOwner;
Stephen Smalley895b4462012-09-19 16:27:36 -0400568 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700569 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400570 int i;
571 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500572 uid_t userid;
573 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500574
Stephen Smalleye183cec2014-02-05 16:41:47 -0500575 __selinux_once(once, seapp_context_init);
576
Stephen Smalleya8795982012-11-28 10:42:46 -0500577 userid = uid / AID_USER;
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400578 isOwner = (userid == 0);
Stephen Smalley895b4462012-09-19 16:27:36 -0400579 appid = uid % AID_USER;
580 if (appid < AID_APP) {
581 for (n = 0; n < android_id_count; n++) {
582 if (android_ids[n].aid == appid) {
583 username = android_ids[n].name;
584 break;
585 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400586 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400587 if (!username)
588 goto err;
589 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400590 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400591 appid -= AID_APP;
592 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400593 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400594 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400595 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500596
Stephen Smalleya8795982012-11-28 10:42:46 -0500597 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400598 goto err;
599
Stephen Smalleyf0740362012-01-04 12:30:47 -0500600 for (i = 0; i < nspec; i++) {
601 cur = seapp_contexts[i];
602
Stephen Smalley895b4462012-09-19 16:27:36 -0400603 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500604 continue;
605
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400606 if (cur->isOwnerSet && cur->isOwner != isOwner)
607 continue;
608
William Robertse3615f92013-09-11 20:35:53 -0700609 if (cur->user.str) {
610 if (cur->user.is_prefix) {
611 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500612 continue;
613 } else {
William Robertse3615f92013-09-11 20:35:53 -0700614 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500615 continue;
616 }
617 }
618
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400619 if (cur->seinfo) {
620 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
621 continue;
622 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500623
William Robertse3615f92013-09-11 20:35:53 -0700624 if (cur->name.str) {
625 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500626 continue;
William Robertse3615f92013-09-11 20:35:53 -0700627
628 if (cur->name.is_prefix) {
629 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
630 continue;
631 } else {
632 if (strcasecmp(pkgname, cur->name.str))
633 continue;
634 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500635 }
636
Stephen Smalley274e0f62014-02-19 10:53:09 -0500637 if (cur->path.str) {
638 if (!path)
639 continue;
640
641 if (cur->path.is_prefix) {
642 if (strncmp(path, cur->path.str, cur->path.len-1))
643 continue;
644 } else {
645 if (strcmp(path, cur->path.str))
646 continue;
647 }
648 }
649
Stephen Smalley895b4462012-09-19 16:27:36 -0400650 if (kind == SEAPP_TYPE && !cur->type)
651 continue;
652 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500653 continue;
654
Stephen Smalley895b4462012-09-19 16:27:36 -0400655 if (kind == SEAPP_TYPE) {
656 if (context_type_set(ctx, cur->type))
657 goto oom;
658 } else if (kind == SEAPP_DOMAIN) {
659 if (context_type_set(ctx, cur->domain))
660 goto oom;
661 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500662
Stephen Smalleya8795982012-11-28 10:42:46 -0500663 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500664 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500665 switch (cur->levelFrom) {
666 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500667 snprintf(level, sizeof level, "s0:c%u,c%u",
668 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500669 256 + (appid>>8 & 0xff));
670 break;
671 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500672 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500673 512 + (userid & 0xff),
674 768 + (userid>>8 & 0xff));
675 break;
676 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500677 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
678 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500679 256 + (appid>>8 & 0xff),
680 512 + (userid & 0xff),
681 768 + (userid>>8 & 0xff));
682 break;
683 default:
684 goto err;
685 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500686 if (context_range_set(ctx, level))
687 goto oom;
688 } else if (cur->level) {
689 if (context_range_set(ctx, cur->level))
690 goto oom;
691 }
William Roberts1b36ad02012-07-27 13:52:33 -0700692
Stephen Smalleyf0740362012-01-04 12:30:47 -0500693 break;
694 }
695
Stephen Smalley895b4462012-09-19 16:27:36 -0400696 if (kind == SEAPP_DOMAIN && i == nspec) {
697 /*
698 * No match.
699 * Fail to prevent staying in the zygote's context.
700 */
701 selinux_log(SELINUX_ERROR,
702 "%s: No match for app with uid %d, seinfo %s, name %s\n",
703 __FUNCTION__, uid, seinfo, pkgname);
704
705 if (security_getenforce() == 1)
706 goto err;
707 }
708
709 return 0;
710err:
711 return -1;
712oom:
713 return -2;
714}
715
Stephen Smalley1b478ea2014-02-07 09:32:41 -0500716int selinux_android_setfilecon(const char *pkgdir,
Stephen Smalley895b4462012-09-19 16:27:36 -0400717 const char *pkgname,
718 const char *seinfo,
719 uid_t uid)
720{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700721 char *orig_ctx_str = NULL;
722 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400723 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700724 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400725
726 if (is_selinux_enabled() <= 0)
727 return 0;
728
Stephen Smalley895b4462012-09-19 16:27:36 -0400729 rc = getfilecon(pkgdir, &ctx_str);
730 if (rc < 0)
731 goto err;
732
733 ctx = context_new(ctx_str);
734 orig_ctx_str = ctx_str;
735 if (!ctx)
736 goto oom;
737
Stephen Smalley274e0f62014-02-19 10:53:09 -0500738 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400739 if (rc == -1)
740 goto err;
741 else if (rc == -2)
742 goto oom;
743
Stephen Smalleyf0740362012-01-04 12:30:47 -0500744 ctx_str = context_str(ctx);
745 if (!ctx_str)
746 goto oom;
747
748 rc = security_check_context(ctx_str);
749 if (rc < 0)
750 goto err;
751
752 if (strcmp(ctx_str, orig_ctx_str)) {
753 rc = setfilecon(pkgdir, ctx_str);
754 if (rc < 0)
755 goto err;
756 }
757
758 rc = 0;
759out:
760 freecon(orig_ctx_str);
761 context_free(ctx);
762 return rc;
763err:
764 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
765 __FUNCTION__, pkgdir, uid, strerror(errno));
766 rc = -1;
767 goto out;
768oom:
769 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
770 rc = -1;
771 goto out;
772}
773
774int selinux_android_setcontext(uid_t uid,
775 int isSystemServer,
776 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400777 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500778{
Stephen Smalley895b4462012-09-19 16:27:36 -0400779 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500780 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700781 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500782
783 if (is_selinux_enabled() <= 0)
784 return 0;
785
Stephen Smalleyf0740362012-01-04 12:30:47 -0500786 rc = getcon(&ctx_str);
787 if (rc)
788 goto err;
789
790 ctx = context_new(ctx_str);
791 orig_ctx_str = ctx_str;
792 if (!ctx)
793 goto oom;
794
Stephen Smalley274e0f62014-02-19 10:53:09 -0500795 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400796 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500797 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400798 else if (rc == -2)
799 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500800
801 ctx_str = context_str(ctx);
802 if (!ctx_str)
803 goto oom;
804
805 rc = security_check_context(ctx_str);
806 if (rc < 0)
807 goto err;
808
809 if (strcmp(ctx_str, orig_ctx_str)) {
810 rc = setcon(ctx_str);
811 if (rc < 0)
812 goto err;
813 }
814
815 rc = 0;
816out:
817 freecon(orig_ctx_str);
818 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400819 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500820 return rc;
821err:
822 if (isSystemServer)
823 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700824 "%s: Error setting context for system server: %s\n",
825 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500826 else
827 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700828 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
829 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500830
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400831 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500832 goto out;
833oom:
834 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
835 rc = -1;
836 goto out;
837}
838
dcashman965141a2014-12-03 12:51:50 -0800839static struct selabel_handle *fc_sehandle = NULL;
Stephen Smalley826cc292014-01-28 15:04:22 -0500840#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
841static uint8_t fc_digest[FC_DIGEST_SIZE];
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400842
dcashman965141a2014-12-03 12:51:50 -0800843static bool compute_contexts_hash(const struct selinux_opt opts[], uint8_t c_digest[])
Stephen Smalley826cc292014-01-28 15:04:22 -0500844{
Stephen Smalley826cc292014-01-28 15:04:22 -0500845 int fd;
846 struct stat sb;
847 void *map;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400848
dcashman965141a2014-12-03 12:51:50 -0800849 fd = open(opts[policy_index].value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW);
Stephen Smalley826cc292014-01-28 15:04:22 -0500850 if (fd < 0) {
851 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400852 opts[policy_index].value, strerror(errno));
dcashman965141a2014-12-03 12:51:50 -0800853 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500854 }
855 if (fstat(fd, &sb) < 0) {
856 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400857 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500858 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800859 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500860 }
861 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
862 if (map == MAP_FAILED) {
863 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400864 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500865 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800866 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500867 }
dcashman965141a2014-12-03 12:51:50 -0800868 SHA_hash(map, sb.st_size, c_digest);
Stephen Smalley826cc292014-01-28 15:04:22 -0500869 munmap(map, sb.st_size);
870 close(fd);
871
dcashman965141a2014-12-03 12:51:50 -0800872 return true;
Geremy Condra60646432013-04-10 17:58:48 -0700873}
874
Stephen Smalley906742d2012-08-23 16:04:59 -0400875static void file_context_init(void)
876{
dcashman965141a2014-12-03 12:51:50 -0800877 if (!fc_sehandle)
878 fc_sehandle = selinux_android_file_context_handle();
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500879}
880
Riley Spahnbad0ebb2014-06-11 16:07:53 -0700881
Riley Spahnbad0ebb2014-06-11 16:07:53 -0700882
Stephen Smalley08587cf2014-01-30 10:13:12 -0500883static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
884
Stephen Smalleye183cec2014-02-05 16:41:47 -0500885struct pkgInfo {
886 char *name;
887 uid_t uid;
888 bool debuggable;
889 char *dataDir;
890 char *seinfo;
891 struct pkgInfo *next;
892};
893
894#define PKGTAB_SIZE 256
895static struct pkgInfo *pkgTab[PKGTAB_SIZE];
896
897static unsigned int pkghash(const char *pkgname)
898{
899 unsigned int h = 7;
900 for (; *pkgname; pkgname++) {
901 h = h * 31 + *pkgname;
902 }
903 return h & (PKGTAB_SIZE - 1);
904}
905
906/* The file containing the list of installed packages on the system */
907#define PACKAGES_LIST_FILE "/data/system/packages.list"
908
909static void package_info_init(void)
910{
911 char *buf = NULL;
912 size_t buflen = 0;
913 ssize_t bytesread;
914 FILE *fp;
915 char *cur, *next;
916 struct pkgInfo *pkgInfo = NULL;
917 unsigned int hash;
918 unsigned long lineno = 1;
919
920 fp = fopen(PACKAGES_LIST_FILE, "r");
921 if (!fp) {
922 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s.\n",
923 PACKAGES_LIST_FILE, strerror(errno));
924 return;
925 }
926 while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
927 pkgInfo = calloc(1, sizeof(*pkgInfo));
928 if (!pkgInfo)
929 goto err;
930 next = buf;
931 cur = strsep(&next, " \t\n");
932 if (!cur)
933 goto err;
934 pkgInfo->name = strdup(cur);
935 if (!pkgInfo->name)
936 goto err;
937 cur = strsep(&next, " \t\n");
938 if (!cur)
939 goto err;
940 pkgInfo->uid = atoi(cur);
941 if (!pkgInfo->uid)
942 goto err;
943 cur = strsep(&next, " \t\n");
944 if (!cur)
945 goto err;
946 pkgInfo->debuggable = atoi(cur);
947 cur = strsep(&next, " \t\n");
948 if (!cur)
949 goto err;
950 pkgInfo->dataDir = strdup(cur);
951 if (!pkgInfo->dataDir)
952 goto err;
953 cur = strsep(&next, " \t\n");
954 if (!cur)
955 goto err;
956 pkgInfo->seinfo = strdup(cur);
957 if (!pkgInfo->seinfo)
958 goto err;
959
960 hash = pkghash(pkgInfo->name);
961 if (pkgTab[hash])
962 pkgInfo->next = pkgTab[hash];
963 pkgTab[hash] = pkgInfo;
964
965 lineno++;
966 }
967
968#if DEBUG
969 {
970 unsigned int buckets, entries, chainlen, longestchain;
971
972 buckets = entries = longestchain = 0;
973 for (hash = 0; hash < PKGTAB_SIZE; hash++) {
974 if (pkgTab[hash]) {
975 buckets++;
976 chainlen = 0;
977 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
978 chainlen++;
979 selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
980 __FUNCTION__,
981 pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo);
982 }
983 entries += chainlen;
984 if (longestchain < chainlen)
985 longestchain = chainlen;
986 }
987 }
988 selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
989 }
990#endif
991
992out:
993 free(buf);
994 fclose(fp);
995 return;
996
997err:
998 selinux_log(SELINUX_ERROR, "SELinux: Error reading %s on line %lu.\n",
999 PACKAGES_LIST_FILE, lineno);
1000 if (pkgInfo) {
1001 free(pkgInfo->name);
1002 free(pkgInfo->dataDir);
1003 free(pkgInfo->seinfo);
1004 free(pkgInfo);
1005 }
1006 goto out;
1007}
1008
1009static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
1010
1011struct pkgInfo *package_info_lookup(const char *name)
1012{
1013 struct pkgInfo *pkgInfo;
1014 unsigned int hash;
1015
1016 __selinux_once(pkg_once, package_info_init);
1017
1018 hash = pkghash(name);
1019 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
1020 if (!strcmp(name, pkgInfo->name))
1021 return pkgInfo;
1022 }
1023 return NULL;
1024}
1025
1026/* The path prefixes of package data directories. */
Stephen Smalley027670d2014-02-18 11:04:37 -05001027#define DATA_DATA_PATH "/data/data"
1028#define DATA_USER_PATH "/data/user"
1029#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
1030#define DATA_USER_PREFIX DATA_USER_PATH "/"
Stephen Smalleye183cec2014-02-05 16:41:47 -05001031
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001032static int pkgdir_selabel_lookup(const char *pathname,
1033 const char *seinfo,
1034 uid_t uid,
1035 char **secontextp)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001036{
1037 char *pkgname = NULL, *end = NULL;
1038 struct pkgInfo *pkgInfo = NULL;
1039 char *secontext = *secontextp;
1040 context_t ctx = NULL;
1041 int rc = 0;
1042
1043 /* Skip directory prefix before package name. */
1044 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
1045 pathname += sizeof(DATA_DATA_PREFIX) - 1;
1046 } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1047 pathname += sizeof(DATA_USER_PREFIX) - 1;
1048 while (isdigit(*pathname))
1049 pathname++;
1050 if (*pathname == '/')
1051 pathname++;
1052 else
1053 return 0;
1054 } else
1055 return 0;
1056
1057 if (!(*pathname))
1058 return 0;
1059
1060 pkgname = strdup(pathname);
1061 if (!pkgname)
1062 return -1;
1063
1064 for (end = pkgname; *end && *end != '/'; end++)
1065 ;
Stephen Smalley274e0f62014-02-19 10:53:09 -05001066 pathname = end;
1067 if (*end)
1068 pathname++;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001069 *end = '\0';
1070
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001071 if (!seinfo) {
1072 pkgInfo = package_info_lookup(pkgname);
1073 if (!pkgInfo) {
1074 selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
1075 pkgname, pathname);
1076 free(pkgname);
1077 return -1;
1078 }
Stephen Smalleye183cec2014-02-05 16:41:47 -05001079 }
1080
1081 ctx = context_new(secontext);
1082 if (!ctx)
1083 goto err;
1084
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001085 rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0,
1086 pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx);
Stephen Smalleye183cec2014-02-05 16:41:47 -05001087 if (rc < 0)
1088 goto err;
1089
1090 secontext = context_str(ctx);
1091 if (!secontext)
1092 goto err;
1093
1094 if (!strcmp(secontext, *secontextp))
1095 goto out;
1096
1097 rc = security_check_context(secontext);
1098 if (rc < 0)
1099 goto err;
1100
1101 freecon(*secontextp);
1102 *secontextp = strdup(secontext);
1103 if (!(*secontextp))
1104 goto err;
1105
1106 rc = 0;
1107
1108out:
1109 free(pkgname);
1110 context_free(ctx);
1111 return rc;
1112err:
1113 selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
1114 __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno));
1115 rc = -1;
1116 goto out;
1117}
1118
Stephen Smalley826cc292014-01-28 15:04:22 -05001119#define RESTORECON_LAST "security.restorecon_last"
1120
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001121static int restorecon_sb(const char *pathname, const struct stat *sb,
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001122 bool nochange, bool verbose,
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001123 const char *seinfo, uid_t uid)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001124{
1125 char *secontext = NULL;
1126 char *oldsecontext = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001127 int rc = 0;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001128
dcashman965141a2014-12-03 12:51:50 -08001129 if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001130 return 0; /* no match, but not an error */
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001131
Stephen Smalleye183cec2014-02-05 16:41:47 -05001132 if (lgetfilecon(pathname, &oldsecontext) < 0)
1133 goto err;
1134
Stephen Smalley833cbd62014-02-27 13:08:40 -05001135 /*
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001136 * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
1137 * and use pkgdir_selabel_lookup() instead. Files within those directories
1138 * have different labeling rules, based off of /seapp_contexts, and
1139 * installd is responsible for managing these labels instead of init.
Stephen Smalley833cbd62014-02-27 13:08:40 -05001140 */
Stephen Smalleye183cec2014-02-05 16:41:47 -05001141 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1142 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001143 if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001144 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001145 }
1146
1147 if (strcmp(oldsecontext, secontext) != 0) {
Stephen Smalley08587cf2014-01-30 10:13:12 -05001148 if (verbose)
1149 selinux_log(SELINUX_INFO,
1150 "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1151 if (!nochange) {
Stephen Smalleye183cec2014-02-05 16:41:47 -05001152 if (lsetfilecon(pathname, secontext) < 0)
1153 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001154 }
1155 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001156
Stephen Smalleye183cec2014-02-05 16:41:47 -05001157 rc = 0;
1158
1159out:
1160 freecon(oldsecontext);
1161 freecon(secontext);
1162 return rc;
1163
1164err:
1165 selinux_log(SELINUX_ERROR,
1166 "SELinux: Could not set context for %s: %s\n",
1167 pathname, strerror(errno));
1168 rc = -1;
1169 goto out;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001170}
1171
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001172#define SYS_PATH "/sys"
1173#define SYS_PREFIX SYS_PATH "/"
1174
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001175static int selinux_android_restorecon_common(const char* pathname,
1176 const char *seinfo,
1177 uid_t uid,
1178 unsigned int flags)
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001179{
Stephen Smalley08587cf2014-01-30 10:13:12 -05001180 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1181 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1182 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1183 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
Stephen Smalley027670d2014-02-18 11:04:37 -05001184 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001185 bool issys = (!strcmp(pathname, SYS_PATH) || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001186 bool setrestoreconlast = true;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001187 struct stat sb;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001188 FTS *fts;
1189 FTSENT *ftsent;
1190 char *const paths[2] = { __UNCONST(pathname), NULL };
Stephen Smalleydfb9fe22014-09-02 12:52:57 -04001191 int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001192 int error, sverrno;
Stephen Smalley826cc292014-01-28 15:04:22 -05001193 char xattr_value[FC_DIGEST_SIZE];
1194 ssize_t size;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001195
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001196 if (is_selinux_enabled() <= 0)
1197 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001198
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001199 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001200
dcashman965141a2014-12-03 12:51:50 -08001201 if (!fc_sehandle)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001202 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001203
Stephen Smalley08587cf2014-01-30 10:13:12 -05001204 if (!recurse) {
1205 if (lstat(pathname, &sb) < 0)
1206 return -1;
1207
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001208 return restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001209 }
1210
Stephen Smalley833cbd62014-02-27 13:08:40 -05001211 /*
1212 * Ignore restorecon_last on /data/data or /data/user
1213 * since their labeling is based on seapp_contexts and seinfo
1214 * assignments rather than file_contexts and is managed by
1215 * installd rather than init.
1216 */
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001217 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1218 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))
1219 setrestoreconlast = false;
Stephen Smalley833cbd62014-02-27 13:08:40 -05001220
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001221 /* Also ignore on /sys since it is regenerated on each boot regardless. */
1222 if (issys)
1223 setrestoreconlast = false;
1224
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001225 if (setrestoreconlast) {
1226 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
1227 if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
1228 selinux_log(SELINUX_INFO,
1229 "SELinux: Skipping restorecon_recursive(%s)\n",
1230 pathname);
1231 return 0;
1232 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001233 }
1234
Stephen Smalley08587cf2014-01-30 10:13:12 -05001235 fts = fts_open(paths, ftsflags, NULL);
1236 if (!fts)
1237 return -1;
1238
1239 error = 0;
1240 while ((ftsent = fts_read(fts)) != NULL) {
1241 switch (ftsent->fts_info) {
1242 case FTS_DC:
1243 selinux_log(SELINUX_ERROR,
1244 "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
1245 errno = ELOOP;
1246 error = -1;
1247 goto out;
1248 case FTS_DP:
1249 continue;
1250 case FTS_DNR:
1251 selinux_log(SELINUX_ERROR,
1252 "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1253 fts_set(fts, ftsent, FTS_SKIP);
1254 continue;
1255 case FTS_NS:
1256 selinux_log(SELINUX_ERROR,
1257 "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1258 fts_set(fts, ftsent, FTS_SKIP);
1259 continue;
1260 case FTS_ERR:
1261 selinux_log(SELINUX_ERROR,
1262 "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1263 fts_set(fts, ftsent, FTS_SKIP);
1264 continue;
Stephen Smalley027670d2014-02-18 11:04:37 -05001265 case FTS_D:
dcashman965141a2014-12-03 12:51:50 -08001266 if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
Stephen Smalley0e7340f2014-04-30 15:13:30 -07001267 fts_set(fts, ftsent, FTS_SKIP);
1268 continue;
1269 }
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001270 if (!datadata &&
1271 (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
Stephen Smalleyb4c98082014-05-28 08:48:59 -04001272 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))) {
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001273 // Don't label anything below this directory.
1274 fts_set(fts, ftsent, FTS_SKIP);
1275 // but fall through and make sure we label the directory itself
1276 }
Stephen Smalley027670d2014-02-18 11:04:37 -05001277 /* fall through */
Stephen Smalley08587cf2014-01-30 10:13:12 -05001278 default:
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001279 error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001280 break;
1281 }
1282 }
1283
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001284 // Labeling successful. Mark the top level directory as completed.
1285 if (setrestoreconlast && !nochange && !error)
1286 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1287
Stephen Smalley08587cf2014-01-30 10:13:12 -05001288out:
1289 sverrno = errno;
1290 (void) fts_close(fts);
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001291 errno = sverrno;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001292 return error;
1293}
1294
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001295int selinux_android_restorecon(const char *file, unsigned int flags)
1296{
1297 return selinux_android_restorecon_common(file, NULL, -1, flags);
1298}
1299
1300int selinux_android_restorecon_pkgdir(const char *pkgdir,
1301 const char *seinfo,
1302 uid_t uid,
1303 unsigned int flags)
1304{
1305 return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1306}
1307
rpcraigf1724a32012-08-01 15:35:37 -04001308struct selabel_handle* selinux_android_file_context_handle(void)
1309{
dcashman965141a2014-12-03 12:51:50 -08001310 struct selabel_handle *sehandle;
1311
1312 set_policy_index();
1313 sehandle = selabel_open(SELABEL_CTX_FILE, &seopts[policy_index], 1);
1314
1315 if (!sehandle) {
1316 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
1317 __FUNCTION__, strerror(errno));
1318 return NULL;
1319 }
1320 if (!compute_contexts_hash(seopts, fc_digest)) {
1321 selabel_close(sehandle);
1322 return NULL;
1323 }
1324 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n",
1325 seopts[policy_index].value);
1326
1327 return sehandle;
1328}
1329
1330struct selabel_handle* selinux_android_prop_context_handle(void)
1331{
1332 struct selabel_handle* sehandle;
1333
1334 set_policy_index();
1335 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1336 &seopts_prop[policy_index], 1);
1337 if (!sehandle) {
1338 selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n",
1339 __FUNCTION__, strerror(errno));
1340 return NULL;
1341 }
1342 selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n",
1343 seopts_prop[policy_index].value);
1344
1345 return sehandle;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001346}
1347
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001348struct selabel_handle* selinux_android_service_context_handle(void)
1349{
dcashman965141a2014-12-03 12:51:50 -08001350 struct selabel_handle* sehandle;
1351
1352 set_policy_index();
1353 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1354 &seopts_service[policy_index], 1);
1355
1356 if (!sehandle) {
1357 selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
1358 __FUNCTION__, strerror(errno));
1359 return NULL;
1360 }
1361 selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n",
1362 seopts_service[policy_index].value);
1363
1364 return sehandle;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001365}
1366
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001367void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1368{
dcashman965141a2014-12-03 12:51:50 -08001369 fc_sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -04001370}
rpcraig9b100832012-07-27 06:36:59 -04001371
Robert Craig5b5183f2014-03-17 20:53:06 -04001372static int selinux_android_load_policy_helper(bool reload)
rpcraigf1724a32012-08-01 15:35:37 -04001373{
Stephen Smalley4a655ec2012-09-18 15:08:32 -04001374 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -04001375 struct stat sb;
1376 void *map = NULL;
Stephen Smalley818815e2015-02-18 17:32:13 -05001377 int old_policy_index = policy_index;
rpcraigf1724a32012-08-01 15:35:37 -04001378
Robert Craig5b5183f2014-03-17 20:53:06 -04001379 /*
1380 * If reloading policy and there is no /data policy or
Stephen Smalley818815e2015-02-18 17:32:13 -05001381 * that /data policy has the wrong version and our prior
1382 * load was from the / policy, then just return.
Robert Craig5b5183f2014-03-17 20:53:06 -04001383 * There is no point in reloading policy from / a second time.
1384 */
dcashman965141a2014-12-03 12:51:50 -08001385 set_policy_index();
Stephen Smalley818815e2015-02-18 17:32:13 -05001386 if (reload && !policy_index && !old_policy_index)
Robert Craig5b5183f2014-03-17 20:53:06 -04001387 return 0;
1388
1389 fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -04001390 if (fd < 0) {
1391 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
1392 strerror(errno));
1393 return -1;
1394 }
1395 if (fstat(fd, &sb) < 0) {
1396 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -04001397 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001398 close(fd);
1399 return -1;
1400 }
1401 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1402 if (map == MAP_FAILED) {
1403 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001404 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001405 close(fd);
1406 return -1;
1407 }
1408
1409 rc = security_load_policy(map, sb.st_size);
1410 if (rc < 0) {
1411 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001412 strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001413 munmap(map, sb.st_size);
1414 close(fd);
1415 return -1;
1416 }
1417
1418 munmap(map, sb.st_size);
1419 close(fd);
Robert Craig5b5183f2014-03-17 20:53:06 -04001420 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
rpcraigf1724a32012-08-01 15:35:37 -04001421
1422 return 0;
1423}
1424
Robert Craig5b5183f2014-03-17 20:53:06 -04001425int selinux_android_reload_policy(void)
1426{
1427 return selinux_android_load_policy_helper(true);
1428}
1429
rpcraigf1724a32012-08-01 15:35:37 -04001430int selinux_android_load_policy(void)
1431{
Nick Kralevich833cba62013-11-19 11:24:33 -08001432 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001433 int rc;
1434 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1435 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001436 if (errno == ENODEV) {
1437 /* SELinux not enabled in kernel */
1438 return -1;
1439 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001440 if (errno == ENOENT) {
1441 /* Fall back to legacy mountpoint. */
1442 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -08001443 rc = mkdir(mnt, 0755);
1444 if (rc == -1 && errno != EEXIST) {
1445 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
1446 strerror(errno));
1447 return -1;
1448 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001449 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1450 }
1451 }
1452 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001453 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
1454 strerror(errno));
1455 return -1;
1456 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001457 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -04001458
Robert Craig5b5183f2014-03-17 20:53:06 -04001459 return selinux_android_load_policy_helper(false);
rpcraig9b100832012-07-27 06:36:59 -04001460}
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001461
1462int selinux_log_callback(int type, const char *fmt, ...)
1463{
1464 va_list ap;
1465 int priority;
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001466 char *strp;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001467
1468 switch(type) {
1469 case SELINUX_WARNING:
1470 priority = ANDROID_LOG_WARN;
1471 break;
1472 case SELINUX_INFO:
1473 priority = ANDROID_LOG_INFO;
1474 break;
1475 default:
1476 priority = ANDROID_LOG_ERROR;
1477 break;
1478 }
1479
1480 va_start(ap, fmt);
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001481 if (vasprintf(&strp, fmt, ap) != -1) {
1482 LOG_PRI(priority, "SELinux", "%s", strp);
1483 LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
1484 free(strp);
1485 }
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001486 va_end(ap);
1487 return 0;
1488}