blob: 6a1fda748dcc99cdbdecd59e6dd76c85bfcc33ed [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 Smalley76d51842015-02-13 15:29:46 -0500192static bool seapp_contexts_dup = false;
193
Stephen Smalleyf0740362012-01-04 12:30:47 -0500194static int seapp_context_cmp(const void *A, const void *B)
195{
Nick Kralevich833cba62013-11-19 11:24:33 -0800196 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
197 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500198 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
Stephen Smalley76d51842015-02-13 15:29:46 -0500199 bool dup;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500200
201 /* Give precedence to isSystemServer=true. */
202 if (s1->isSystemServer != s2->isSystemServer)
203 return (s1->isSystemServer ? -1 : 1);
204
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400205 /* Give precedence to a specified isOwner= over an unspecified isOwner=. */
206 if (s1->isOwnerSet != s2->isOwnerSet)
207 return (s1->isOwnerSet ? -1 : 1);
208
Stephen Smalleyf0740362012-01-04 12:30:47 -0500209 /* Give precedence to a specified user= over an unspecified user=. */
William Robertse3615f92013-09-11 20:35:53 -0700210 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500211 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700212 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500213 return 1;
214
William Robertse3615f92013-09-11 20:35:53 -0700215 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500216 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700217 if (s1->user.is_prefix != s2->user.is_prefix)
218 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500219
220 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700221 if (s1->user.is_prefix && s1->user.len != s2->user.len)
222 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500223 }
224
225 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
226 if (s1->seinfo && !s2->seinfo)
227 return -1;
228 if (!s1->seinfo && s2->seinfo)
229 return 1;
230
231 /* Give precedence to a specified name= over an unspecified name=. */
William Robertse3615f92013-09-11 20:35:53 -0700232 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500233 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700234 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500235 return 1;
236
William Robertse3615f92013-09-11 20:35:53 -0700237 if (s1->name.str) {
238 /* Give precedence to a fixed name= string over a prefix. */
239 if (s1->name.is_prefix != s2->name.is_prefix)
240 return (s2->name.is_prefix ? -1 : 1);
241
242 /* Give precedence to a longer prefix over a shorter prefix. */
243 if (s1->name.is_prefix && s1->name.len != s2->name.len)
244 return (s1->name.len > s2->name.len) ? -1 : 1;
245 }
246
Stephen Smalley274e0f62014-02-19 10:53:09 -0500247 /* Give precedence to a specified path= over an unspecified path=. */
248 if (s1->path.str && !s2->path.str)
249 return -1;
250 if (!s1->path.str && s2->path.str)
251 return 1;
252
253 if (s1->path.str) {
254 /* Give precedence to a fixed path= string over a prefix. */
255 if (s1->path.is_prefix != s2->path.is_prefix)
256 return (s2->path.is_prefix ? -1 : 1);
257
258 /* Give precedence to a longer prefix over a shorter prefix. */
259 if (s1->path.is_prefix && s1->path.len != s2->path.len)
260 return (s1->path.len > s2->path.len) ? -1 : 1;
261 }
262
Stephen Smalley76d51842015-02-13 15:29:46 -0500263 /*
264 * Check for a duplicated entry on the input selectors.
265 * We already compared isSystemServer, isOwnerSet, and isOwner above.
266 * We also have already checked that both entries specify the same
267 * string fields, so if s1 has a non-NULL string, then so does s2.
268 */
269 dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) &&
270 (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) &&
271 (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) &&
272 (!s1->path.str || !strcmp(s1->path.str, s2->path.str));
273 if (dup) {
274 seapp_contexts_dup = true;
275 selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n");
276 if (s1->user.str)
277 selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str);
278 if (s1->seinfo)
279 selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo);
280 if (s1->name.str)
281 selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str);
282 if (s1->path.str)
283 selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str);
284 }
285
Stephen Smalleyf0740362012-01-04 12:30:47 -0500286 /* Anything else has equal precedence. */
287 return 0;
288}
289
290static struct seapp_context **seapp_contexts = NULL;
291static int nspec = 0;
292
Stephen Smalley13319cf2014-04-04 15:44:23 -0400293static void free_seapp_contexts(void)
294{
295 int n;
296
297 if (!seapp_contexts)
298 return;
299
300 for (n = 0; n < nspec; n++)
301 free_seapp_context(seapp_contexts[n]);
302
303 free(seapp_contexts);
304 seapp_contexts = NULL;
305 nspec = 0;
306}
307
Stephen Smalley7446c912012-03-19 10:37:05 -0400308int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500309{
Stephen Smalley7446c912012-03-19 10:37:05 -0400310 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500311 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500312 char *token;
313 unsigned lineno;
314 struct seapp_context *cur;
315 char *p, *name = NULL, *value = NULL, *saveptr;
316 size_t len;
Robert Craig5b5183f2014-03-17 20:53:06 -0400317 int n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500318
Robert Craig5b5183f2014-03-17 20:53:06 -0400319 set_policy_index();
Stephen Smalley7446c912012-03-19 10:37:05 -0400320
Robert Craig5b5183f2014-03-17 20:53:06 -0400321 fp = fopen(seapp_contexts_file[policy_index], "r");
Stephen Smalleyf0740362012-01-04 12:30:47 -0500322 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400323 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
324 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500325 }
326
Stephen Smalley13319cf2014-04-04 15:44:23 -0400327 free_seapp_contexts();
Stephen Smalley300bebb2013-04-16 15:33:16 -0400328
Stephen Smalleyf0740362012-01-04 12:30:47 -0500329 nspec = 0;
330 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
331 p = line_buf;
332 while (isspace(*p))
333 p++;
334 if (*p == '#' || *p == 0)
335 continue;
336 nspec++;
337 }
338
Nick Kralevich833cba62013-11-19 11:24:33 -0800339 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500340 if (!seapp_contexts)
341 goto oom;
342
343 rewind(fp);
344 nspec = 0;
345 lineno = 1;
346 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
347 len = strlen(line_buf);
348 if (line_buf[len - 1] == '\n')
349 line_buf[len - 1] = 0;
350 p = line_buf;
351 while (isspace(*p))
352 p++;
353 if (*p == '#' || *p == 0)
354 continue;
355
Nick Kralevich833cba62013-11-19 11:24:33 -0800356 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500357 if (!cur)
358 goto oom;
359
360 token = strtok_r(p, " \t", &saveptr);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400361 if (!token) {
362 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500363 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400364 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500365
366 while (1) {
367 name = token;
368 value = strchr(name, '=');
Stephen Smalley13319cf2014-04-04 15:44:23 -0400369 if (!value) {
370 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500371 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400372 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500373 *value++ = 0;
374
375 if (!strcasecmp(name, "isSystemServer")) {
376 if (!strcasecmp(value, "true"))
377 cur->isSystemServer = 1;
378 else if (!strcasecmp(value, "false"))
379 cur->isSystemServer = 0;
380 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400381 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500382 goto err;
383 }
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400384 } else if (!strcasecmp(name, "isOwner")) {
385 cur->isOwnerSet = true;
386 if (!strcasecmp(value, "true"))
387 cur->isOwner = true;
388 else if (!strcasecmp(value, "false"))
389 cur->isOwner = false;
390 else {
391 free_seapp_context(cur);
392 goto err;
393 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500394 } else if (!strcasecmp(name, "user")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500395 if (cur->user.str) {
396 free_seapp_context(cur);
397 goto err;
398 }
William Robertse3615f92013-09-11 20:35:53 -0700399 cur->user.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400400 if (!cur->user.str) {
401 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500402 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400403 }
William Robertse3615f92013-09-11 20:35:53 -0700404 cur->user.len = strlen(cur->user.str);
405 if (cur->user.str[cur->user.len-1] == '*')
406 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500407 } else if (!strcasecmp(name, "seinfo")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500408 if (cur->seinfo) {
409 free_seapp_context(cur);
410 goto err;
411 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500412 cur->seinfo = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400413 if (!cur->seinfo) {
414 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500415 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400416 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500417 } else if (!strcasecmp(name, "name")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500418 if (cur->name.str) {
419 free_seapp_context(cur);
420 goto err;
421 }
William Robertse3615f92013-09-11 20:35:53 -0700422 cur->name.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400423 if (!cur->name.str) {
424 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500425 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400426 }
William Robertse3615f92013-09-11 20:35:53 -0700427 cur->name.len = strlen(cur->name.str);
428 if (cur->name.str[cur->name.len-1] == '*')
429 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500430 } else if (!strcasecmp(name, "domain")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500431 if (cur->domain) {
432 free_seapp_context(cur);
433 goto err;
434 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500435 cur->domain = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400436 if (!cur->domain) {
437 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500438 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400439 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500440 } else if (!strcasecmp(name, "type")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500441 if (cur->type) {
442 free_seapp_context(cur);
443 goto err;
444 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500445 cur->type = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400446 if (!cur->type) {
447 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500448 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400449 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500450 } else if (!strcasecmp(name, "levelFromUid")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500451 if (cur->levelFrom) {
452 free_seapp_context(cur);
453 goto err;
454 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500455 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500456 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500457 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500458 cur->levelFrom = LEVELFROM_NONE;
459 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400460 free_seapp_context(cur);
Stephen Smalleya8795982012-11-28 10:42:46 -0500461 goto err;
462 }
463 } else if (!strcasecmp(name, "levelFrom")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500464 if (cur->levelFrom) {
465 free_seapp_context(cur);
466 goto err;
467 }
Stephen Smalleya8795982012-11-28 10:42:46 -0500468 if (!strcasecmp(value, "none"))
469 cur->levelFrom = LEVELFROM_NONE;
470 else if (!strcasecmp(value, "app"))
471 cur->levelFrom = LEVELFROM_APP;
472 else if (!strcasecmp(value, "user"))
473 cur->levelFrom = LEVELFROM_USER;
474 else if (!strcasecmp(value, "all"))
475 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500476 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400477 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500478 goto err;
479 }
480 } else if (!strcasecmp(name, "level")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500481 if (cur->level) {
482 free_seapp_context(cur);
483 goto err;
484 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500485 cur->level = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400486 if (!cur->level) {
487 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500488 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400489 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500490 } else if (!strcasecmp(name, "path")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500491 if (cur->path.str) {
492 free_seapp_context(cur);
493 goto err;
494 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500495 cur->path.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400496 if (!cur->path.str) {
497 free_seapp_context(cur);
Stephen Smalley274e0f62014-02-19 10:53:09 -0500498 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400499 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500500 cur->path.len = strlen(cur->path.str);
501 if (cur->path.str[cur->path.len-1] == '*')
502 cur->path.is_prefix = 1;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400503 } else {
504 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500505 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400506 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500507
508 token = strtok_r(NULL, " \t", &saveptr);
509 if (!token)
510 break;
511 }
512
Stephen Smalley13319cf2014-04-04 15:44:23 -0400513 if (cur->name.str &&
514 (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
515 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 -0400516 seapp_contexts_file[policy_index], cur->name.str, lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400517 free_seapp_context(cur);
518 goto err;
519 }
520
Stephen Smalleyf0740362012-01-04 12:30:47 -0500521 seapp_contexts[nspec] = cur;
522 nspec++;
523 lineno++;
524 }
525
526 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
527 seapp_context_cmp);
528
Stephen Smalley76d51842015-02-13 15:29:46 -0500529 if (seapp_contexts_dup)
530 goto err;
531
Stephen Smalleyf0740362012-01-04 12:30:47 -0500532#if DEBUG
533 {
534 int i;
535 for (i = 0; i < nspec; i++) {
536 cur = seapp_contexts[i];
Stephen Smalley3fb00962015-02-13 15:59:32 -0500537 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 -0400538 __FUNCTION__,
539 cur->isSystemServer ? "true" : "false",
540 cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null",
541 cur->user.str,
Stephen Smalley3fb00962015-02-13 15:59:32 -0500542 cur->seinfo, cur->name.str, cur->path.str, cur->domain,
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400543 cur->type, cur->level,
544 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500545 }
546 }
547#endif
548
Stephen Smalley7446c912012-03-19 10:37:05 -0400549 ret = 0;
550
Stephen Smalleyf0740362012-01-04 12:30:47 -0500551out:
552 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400553 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500554
555err:
Stephen Smalley13319cf2014-04-04 15:44:23 -0400556 selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400557 seapp_contexts_file[policy_index], lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400558 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400559 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500560 goto out;
561oom:
562 selinux_log(SELINUX_ERROR,
563 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400564 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400565 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500566 goto out;
567}
568
Stephen Smalley7446c912012-03-19 10:37:05 -0400569
570static void seapp_context_init(void)
571{
572 selinux_android_seapp_context_reload();
573}
574
Stephen Smalleyf0740362012-01-04 12:30:47 -0500575static pthread_once_t once = PTHREAD_ONCE_INIT;
576
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400577/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500578 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400579 * using the current scheme.
580 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500581#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400582
583enum seapp_kind {
584 SEAPP_TYPE,
585 SEAPP_DOMAIN
586};
587
588static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400589 uid_t uid,
590 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400591 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400592 const char *pkgname,
Stephen Smalley274e0f62014-02-19 10:53:09 -0500593 const char *path,
Stephen Smalley895b4462012-09-19 16:27:36 -0400594 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500595{
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400596 bool isOwner;
Stephen Smalley895b4462012-09-19 16:27:36 -0400597 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700598 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400599 int i;
600 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500601 uid_t userid;
602 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500603
Stephen Smalleye183cec2014-02-05 16:41:47 -0500604 __selinux_once(once, seapp_context_init);
605
Stephen Smalleya8795982012-11-28 10:42:46 -0500606 userid = uid / AID_USER;
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400607 isOwner = (userid == 0);
Stephen Smalley895b4462012-09-19 16:27:36 -0400608 appid = uid % AID_USER;
609 if (appid < AID_APP) {
610 for (n = 0; n < android_id_count; n++) {
611 if (android_ids[n].aid == appid) {
612 username = android_ids[n].name;
613 break;
614 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400615 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400616 if (!username)
617 goto err;
618 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400619 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400620 appid -= AID_APP;
621 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400622 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400623 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400624 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500625
Stephen Smalleya8795982012-11-28 10:42:46 -0500626 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400627 goto err;
628
Stephen Smalleyf0740362012-01-04 12:30:47 -0500629 for (i = 0; i < nspec; i++) {
630 cur = seapp_contexts[i];
631
Stephen Smalley895b4462012-09-19 16:27:36 -0400632 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500633 continue;
634
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400635 if (cur->isOwnerSet && cur->isOwner != isOwner)
636 continue;
637
William Robertse3615f92013-09-11 20:35:53 -0700638 if (cur->user.str) {
639 if (cur->user.is_prefix) {
640 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500641 continue;
642 } else {
William Robertse3615f92013-09-11 20:35:53 -0700643 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500644 continue;
645 }
646 }
647
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400648 if (cur->seinfo) {
649 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
650 continue;
651 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500652
William Robertse3615f92013-09-11 20:35:53 -0700653 if (cur->name.str) {
654 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500655 continue;
William Robertse3615f92013-09-11 20:35:53 -0700656
657 if (cur->name.is_prefix) {
658 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
659 continue;
660 } else {
661 if (strcasecmp(pkgname, cur->name.str))
662 continue;
663 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500664 }
665
Stephen Smalley274e0f62014-02-19 10:53:09 -0500666 if (cur->path.str) {
667 if (!path)
668 continue;
669
670 if (cur->path.is_prefix) {
671 if (strncmp(path, cur->path.str, cur->path.len-1))
672 continue;
673 } else {
674 if (strcmp(path, cur->path.str))
675 continue;
676 }
677 }
678
Stephen Smalley895b4462012-09-19 16:27:36 -0400679 if (kind == SEAPP_TYPE && !cur->type)
680 continue;
681 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500682 continue;
683
Stephen Smalley895b4462012-09-19 16:27:36 -0400684 if (kind == SEAPP_TYPE) {
685 if (context_type_set(ctx, cur->type))
686 goto oom;
687 } else if (kind == SEAPP_DOMAIN) {
688 if (context_type_set(ctx, cur->domain))
689 goto oom;
690 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500691
Stephen Smalleya8795982012-11-28 10:42:46 -0500692 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500693 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500694 switch (cur->levelFrom) {
695 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500696 snprintf(level, sizeof level, "s0:c%u,c%u",
697 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500698 256 + (appid>>8 & 0xff));
699 break;
700 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500701 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500702 512 + (userid & 0xff),
703 768 + (userid>>8 & 0xff));
704 break;
705 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500706 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
707 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500708 256 + (appid>>8 & 0xff),
709 512 + (userid & 0xff),
710 768 + (userid>>8 & 0xff));
711 break;
712 default:
713 goto err;
714 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500715 if (context_range_set(ctx, level))
716 goto oom;
717 } else if (cur->level) {
718 if (context_range_set(ctx, cur->level))
719 goto oom;
720 }
William Roberts1b36ad02012-07-27 13:52:33 -0700721
Stephen Smalleyf0740362012-01-04 12:30:47 -0500722 break;
723 }
724
Stephen Smalley895b4462012-09-19 16:27:36 -0400725 if (kind == SEAPP_DOMAIN && i == nspec) {
726 /*
727 * No match.
728 * Fail to prevent staying in the zygote's context.
729 */
730 selinux_log(SELINUX_ERROR,
731 "%s: No match for app with uid %d, seinfo %s, name %s\n",
732 __FUNCTION__, uid, seinfo, pkgname);
733
734 if (security_getenforce() == 1)
735 goto err;
736 }
737
738 return 0;
739err:
740 return -1;
741oom:
742 return -2;
743}
744
Stephen Smalley1b478ea2014-02-07 09:32:41 -0500745int selinux_android_setfilecon(const char *pkgdir,
Stephen Smalley895b4462012-09-19 16:27:36 -0400746 const char *pkgname,
747 const char *seinfo,
748 uid_t uid)
749{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700750 char *orig_ctx_str = NULL;
751 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400752 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700753 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400754
755 if (is_selinux_enabled() <= 0)
756 return 0;
757
Stephen Smalley895b4462012-09-19 16:27:36 -0400758 rc = getfilecon(pkgdir, &ctx_str);
759 if (rc < 0)
760 goto err;
761
762 ctx = context_new(ctx_str);
763 orig_ctx_str = ctx_str;
764 if (!ctx)
765 goto oom;
766
Stephen Smalley274e0f62014-02-19 10:53:09 -0500767 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400768 if (rc == -1)
769 goto err;
770 else if (rc == -2)
771 goto oom;
772
Stephen Smalleyf0740362012-01-04 12:30:47 -0500773 ctx_str = context_str(ctx);
774 if (!ctx_str)
775 goto oom;
776
777 rc = security_check_context(ctx_str);
778 if (rc < 0)
779 goto err;
780
781 if (strcmp(ctx_str, orig_ctx_str)) {
782 rc = setfilecon(pkgdir, ctx_str);
783 if (rc < 0)
784 goto err;
785 }
786
787 rc = 0;
788out:
789 freecon(orig_ctx_str);
790 context_free(ctx);
791 return rc;
792err:
793 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
794 __FUNCTION__, pkgdir, uid, strerror(errno));
795 rc = -1;
796 goto out;
797oom:
798 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
799 rc = -1;
800 goto out;
801}
802
803int selinux_android_setcontext(uid_t uid,
804 int isSystemServer,
805 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400806 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500807{
Stephen Smalley895b4462012-09-19 16:27:36 -0400808 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500809 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700810 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500811
812 if (is_selinux_enabled() <= 0)
813 return 0;
814
Stephen Smalleyf0740362012-01-04 12:30:47 -0500815 rc = getcon(&ctx_str);
816 if (rc)
817 goto err;
818
819 ctx = context_new(ctx_str);
820 orig_ctx_str = ctx_str;
821 if (!ctx)
822 goto oom;
823
Stephen Smalley274e0f62014-02-19 10:53:09 -0500824 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400825 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500826 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400827 else if (rc == -2)
828 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500829
830 ctx_str = context_str(ctx);
831 if (!ctx_str)
832 goto oom;
833
834 rc = security_check_context(ctx_str);
835 if (rc < 0)
836 goto err;
837
838 if (strcmp(ctx_str, orig_ctx_str)) {
839 rc = setcon(ctx_str);
840 if (rc < 0)
841 goto err;
842 }
843
844 rc = 0;
845out:
846 freecon(orig_ctx_str);
847 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400848 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500849 return rc;
850err:
851 if (isSystemServer)
852 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700853 "%s: Error setting context for system server: %s\n",
854 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500855 else
856 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700857 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
858 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500859
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400860 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500861 goto out;
862oom:
863 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
864 rc = -1;
865 goto out;
866}
867
dcashman965141a2014-12-03 12:51:50 -0800868static struct selabel_handle *fc_sehandle = NULL;
Stephen Smalley826cc292014-01-28 15:04:22 -0500869#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
870static uint8_t fc_digest[FC_DIGEST_SIZE];
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400871
dcashman965141a2014-12-03 12:51:50 -0800872static bool compute_contexts_hash(const struct selinux_opt opts[], uint8_t c_digest[])
Stephen Smalley826cc292014-01-28 15:04:22 -0500873{
Stephen Smalley826cc292014-01-28 15:04:22 -0500874 int fd;
875 struct stat sb;
876 void *map;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400877
dcashman965141a2014-12-03 12:51:50 -0800878 fd = open(opts[policy_index].value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW);
Stephen Smalley826cc292014-01-28 15:04:22 -0500879 if (fd < 0) {
880 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400881 opts[policy_index].value, strerror(errno));
dcashman965141a2014-12-03 12:51:50 -0800882 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500883 }
884 if (fstat(fd, &sb) < 0) {
885 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400886 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500887 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800888 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500889 }
890 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
891 if (map == MAP_FAILED) {
892 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400893 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500894 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800895 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500896 }
dcashman965141a2014-12-03 12:51:50 -0800897 SHA_hash(map, sb.st_size, c_digest);
Stephen Smalley826cc292014-01-28 15:04:22 -0500898 munmap(map, sb.st_size);
899 close(fd);
900
dcashman965141a2014-12-03 12:51:50 -0800901 return true;
Geremy Condra60646432013-04-10 17:58:48 -0700902}
903
Stephen Smalley906742d2012-08-23 16:04:59 -0400904static void file_context_init(void)
905{
dcashman965141a2014-12-03 12:51:50 -0800906 if (!fc_sehandle)
907 fc_sehandle = selinux_android_file_context_handle();
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500908}
909
Riley Spahnbad0ebb2014-06-11 16:07:53 -0700910
Riley Spahnbad0ebb2014-06-11 16:07:53 -0700911
Stephen Smalley08587cf2014-01-30 10:13:12 -0500912static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
913
Stephen Smalleye183cec2014-02-05 16:41:47 -0500914struct pkgInfo {
915 char *name;
916 uid_t uid;
917 bool debuggable;
918 char *dataDir;
919 char *seinfo;
920 struct pkgInfo *next;
921};
922
923#define PKGTAB_SIZE 256
924static struct pkgInfo *pkgTab[PKGTAB_SIZE];
925
926static unsigned int pkghash(const char *pkgname)
927{
928 unsigned int h = 7;
929 for (; *pkgname; pkgname++) {
930 h = h * 31 + *pkgname;
931 }
932 return h & (PKGTAB_SIZE - 1);
933}
934
935/* The file containing the list of installed packages on the system */
936#define PACKAGES_LIST_FILE "/data/system/packages.list"
937
938static void package_info_init(void)
939{
940 char *buf = NULL;
941 size_t buflen = 0;
942 ssize_t bytesread;
943 FILE *fp;
944 char *cur, *next;
945 struct pkgInfo *pkgInfo = NULL;
946 unsigned int hash;
947 unsigned long lineno = 1;
948
949 fp = fopen(PACKAGES_LIST_FILE, "r");
950 if (!fp) {
951 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s.\n",
952 PACKAGES_LIST_FILE, strerror(errno));
953 return;
954 }
955 while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
956 pkgInfo = calloc(1, sizeof(*pkgInfo));
957 if (!pkgInfo)
958 goto err;
959 next = buf;
960 cur = strsep(&next, " \t\n");
961 if (!cur)
962 goto err;
963 pkgInfo->name = strdup(cur);
964 if (!pkgInfo->name)
965 goto err;
966 cur = strsep(&next, " \t\n");
967 if (!cur)
968 goto err;
969 pkgInfo->uid = atoi(cur);
970 if (!pkgInfo->uid)
971 goto err;
972 cur = strsep(&next, " \t\n");
973 if (!cur)
974 goto err;
975 pkgInfo->debuggable = atoi(cur);
976 cur = strsep(&next, " \t\n");
977 if (!cur)
978 goto err;
979 pkgInfo->dataDir = strdup(cur);
980 if (!pkgInfo->dataDir)
981 goto err;
982 cur = strsep(&next, " \t\n");
983 if (!cur)
984 goto err;
985 pkgInfo->seinfo = strdup(cur);
986 if (!pkgInfo->seinfo)
987 goto err;
988
989 hash = pkghash(pkgInfo->name);
990 if (pkgTab[hash])
991 pkgInfo->next = pkgTab[hash];
992 pkgTab[hash] = pkgInfo;
993
994 lineno++;
995 }
996
997#if DEBUG
998 {
999 unsigned int buckets, entries, chainlen, longestchain;
1000
1001 buckets = entries = longestchain = 0;
1002 for (hash = 0; hash < PKGTAB_SIZE; hash++) {
1003 if (pkgTab[hash]) {
1004 buckets++;
1005 chainlen = 0;
1006 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
1007 chainlen++;
1008 selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
1009 __FUNCTION__,
1010 pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo);
1011 }
1012 entries += chainlen;
1013 if (longestchain < chainlen)
1014 longestchain = chainlen;
1015 }
1016 }
1017 selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
1018 }
1019#endif
1020
1021out:
1022 free(buf);
1023 fclose(fp);
1024 return;
1025
1026err:
1027 selinux_log(SELINUX_ERROR, "SELinux: Error reading %s on line %lu.\n",
1028 PACKAGES_LIST_FILE, lineno);
1029 if (pkgInfo) {
1030 free(pkgInfo->name);
1031 free(pkgInfo->dataDir);
1032 free(pkgInfo->seinfo);
1033 free(pkgInfo);
1034 }
1035 goto out;
1036}
1037
1038static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
1039
1040struct pkgInfo *package_info_lookup(const char *name)
1041{
1042 struct pkgInfo *pkgInfo;
1043 unsigned int hash;
1044
1045 __selinux_once(pkg_once, package_info_init);
1046
1047 hash = pkghash(name);
1048 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
1049 if (!strcmp(name, pkgInfo->name))
1050 return pkgInfo;
1051 }
1052 return NULL;
1053}
1054
1055/* The path prefixes of package data directories. */
Stephen Smalley027670d2014-02-18 11:04:37 -05001056#define DATA_DATA_PATH "/data/data"
1057#define DATA_USER_PATH "/data/user"
1058#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
1059#define DATA_USER_PREFIX DATA_USER_PATH "/"
Stephen Smalleye183cec2014-02-05 16:41:47 -05001060
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001061static int pkgdir_selabel_lookup(const char *pathname,
1062 const char *seinfo,
1063 uid_t uid,
1064 char **secontextp)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001065{
1066 char *pkgname = NULL, *end = NULL;
1067 struct pkgInfo *pkgInfo = NULL;
1068 char *secontext = *secontextp;
1069 context_t ctx = NULL;
1070 int rc = 0;
1071
1072 /* Skip directory prefix before package name. */
1073 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
1074 pathname += sizeof(DATA_DATA_PREFIX) - 1;
1075 } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1076 pathname += sizeof(DATA_USER_PREFIX) - 1;
1077 while (isdigit(*pathname))
1078 pathname++;
1079 if (*pathname == '/')
1080 pathname++;
1081 else
1082 return 0;
1083 } else
1084 return 0;
1085
1086 if (!(*pathname))
1087 return 0;
1088
1089 pkgname = strdup(pathname);
1090 if (!pkgname)
1091 return -1;
1092
1093 for (end = pkgname; *end && *end != '/'; end++)
1094 ;
Stephen Smalley274e0f62014-02-19 10:53:09 -05001095 pathname = end;
1096 if (*end)
1097 pathname++;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001098 *end = '\0';
1099
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001100 if (!seinfo) {
1101 pkgInfo = package_info_lookup(pkgname);
1102 if (!pkgInfo) {
1103 selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
1104 pkgname, pathname);
1105 free(pkgname);
1106 return -1;
1107 }
Stephen Smalleye183cec2014-02-05 16:41:47 -05001108 }
1109
1110 ctx = context_new(secontext);
1111 if (!ctx)
1112 goto err;
1113
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001114 rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0,
1115 pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx);
Stephen Smalleye183cec2014-02-05 16:41:47 -05001116 if (rc < 0)
1117 goto err;
1118
1119 secontext = context_str(ctx);
1120 if (!secontext)
1121 goto err;
1122
1123 if (!strcmp(secontext, *secontextp))
1124 goto out;
1125
1126 rc = security_check_context(secontext);
1127 if (rc < 0)
1128 goto err;
1129
1130 freecon(*secontextp);
1131 *secontextp = strdup(secontext);
1132 if (!(*secontextp))
1133 goto err;
1134
1135 rc = 0;
1136
1137out:
1138 free(pkgname);
1139 context_free(ctx);
1140 return rc;
1141err:
1142 selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
1143 __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno));
1144 rc = -1;
1145 goto out;
1146}
1147
Stephen Smalley826cc292014-01-28 15:04:22 -05001148#define RESTORECON_LAST "security.restorecon_last"
1149
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001150static int restorecon_sb(const char *pathname, const struct stat *sb,
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001151 bool nochange, bool verbose,
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001152 const char *seinfo, uid_t uid)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001153{
1154 char *secontext = NULL;
1155 char *oldsecontext = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001156 int rc = 0;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001157
dcashman965141a2014-12-03 12:51:50 -08001158 if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001159 return 0; /* no match, but not an error */
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001160
Stephen Smalleye183cec2014-02-05 16:41:47 -05001161 if (lgetfilecon(pathname, &oldsecontext) < 0)
1162 goto err;
1163
Stephen Smalley833cbd62014-02-27 13:08:40 -05001164 /*
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001165 * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
1166 * and use pkgdir_selabel_lookup() instead. Files within those directories
1167 * have different labeling rules, based off of /seapp_contexts, and
1168 * installd is responsible for managing these labels instead of init.
Stephen Smalley833cbd62014-02-27 13:08:40 -05001169 */
Stephen Smalleye183cec2014-02-05 16:41:47 -05001170 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1171 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001172 if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001173 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001174 }
1175
1176 if (strcmp(oldsecontext, secontext) != 0) {
Stephen Smalley08587cf2014-01-30 10:13:12 -05001177 if (verbose)
1178 selinux_log(SELINUX_INFO,
1179 "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1180 if (!nochange) {
Stephen Smalleye183cec2014-02-05 16:41:47 -05001181 if (lsetfilecon(pathname, secontext) < 0)
1182 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001183 }
1184 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001185
Stephen Smalleye183cec2014-02-05 16:41:47 -05001186 rc = 0;
1187
1188out:
1189 freecon(oldsecontext);
1190 freecon(secontext);
1191 return rc;
1192
1193err:
1194 selinux_log(SELINUX_ERROR,
1195 "SELinux: Could not set context for %s: %s\n",
1196 pathname, strerror(errno));
1197 rc = -1;
1198 goto out;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001199}
1200
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001201#define SYS_PATH "/sys"
1202#define SYS_PREFIX SYS_PATH "/"
1203
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001204static int selinux_android_restorecon_common(const char* pathname,
1205 const char *seinfo,
1206 uid_t uid,
1207 unsigned int flags)
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001208{
Stephen Smalley08587cf2014-01-30 10:13:12 -05001209 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1210 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1211 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1212 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
Stephen Smalley027670d2014-02-18 11:04:37 -05001213 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001214 bool issys = (!strcmp(pathname, SYS_PATH) || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001215 bool setrestoreconlast = true;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001216 struct stat sb;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001217 FTS *fts;
1218 FTSENT *ftsent;
1219 char *const paths[2] = { __UNCONST(pathname), NULL };
Stephen Smalleydfb9fe22014-09-02 12:52:57 -04001220 int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001221 int error, sverrno;
Stephen Smalley826cc292014-01-28 15:04:22 -05001222 char xattr_value[FC_DIGEST_SIZE];
1223 ssize_t size;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001224
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001225 if (is_selinux_enabled() <= 0)
1226 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001227
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001228 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001229
dcashman965141a2014-12-03 12:51:50 -08001230 if (!fc_sehandle)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001231 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001232
Stephen Smalley08587cf2014-01-30 10:13:12 -05001233 if (!recurse) {
1234 if (lstat(pathname, &sb) < 0)
1235 return -1;
1236
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001237 return restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001238 }
1239
Stephen Smalley833cbd62014-02-27 13:08:40 -05001240 /*
1241 * Ignore restorecon_last on /data/data or /data/user
1242 * since their labeling is based on seapp_contexts and seinfo
1243 * assignments rather than file_contexts and is managed by
1244 * installd rather than init.
1245 */
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001246 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1247 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))
1248 setrestoreconlast = false;
Stephen Smalley833cbd62014-02-27 13:08:40 -05001249
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001250 /* Also ignore on /sys since it is regenerated on each boot regardless. */
1251 if (issys)
1252 setrestoreconlast = false;
1253
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001254 if (setrestoreconlast) {
1255 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
1256 if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
1257 selinux_log(SELINUX_INFO,
1258 "SELinux: Skipping restorecon_recursive(%s)\n",
1259 pathname);
1260 return 0;
1261 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001262 }
1263
Stephen Smalley08587cf2014-01-30 10:13:12 -05001264 fts = fts_open(paths, ftsflags, NULL);
1265 if (!fts)
1266 return -1;
1267
1268 error = 0;
1269 while ((ftsent = fts_read(fts)) != NULL) {
1270 switch (ftsent->fts_info) {
1271 case FTS_DC:
1272 selinux_log(SELINUX_ERROR,
1273 "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
1274 errno = ELOOP;
1275 error = -1;
1276 goto out;
1277 case FTS_DP:
1278 continue;
1279 case FTS_DNR:
1280 selinux_log(SELINUX_ERROR,
1281 "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1282 fts_set(fts, ftsent, FTS_SKIP);
1283 continue;
1284 case FTS_NS:
1285 selinux_log(SELINUX_ERROR,
1286 "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1287 fts_set(fts, ftsent, FTS_SKIP);
1288 continue;
1289 case FTS_ERR:
1290 selinux_log(SELINUX_ERROR,
1291 "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1292 fts_set(fts, ftsent, FTS_SKIP);
1293 continue;
Stephen Smalley027670d2014-02-18 11:04:37 -05001294 case FTS_D:
dcashman965141a2014-12-03 12:51:50 -08001295 if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
Stephen Smalley0e7340f2014-04-30 15:13:30 -07001296 fts_set(fts, ftsent, FTS_SKIP);
1297 continue;
1298 }
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001299 if (!datadata &&
1300 (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
Stephen Smalleyb4c98082014-05-28 08:48:59 -04001301 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))) {
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001302 // Don't label anything below this directory.
1303 fts_set(fts, ftsent, FTS_SKIP);
1304 // but fall through and make sure we label the directory itself
1305 }
Stephen Smalley027670d2014-02-18 11:04:37 -05001306 /* fall through */
Stephen Smalley08587cf2014-01-30 10:13:12 -05001307 default:
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001308 error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001309 break;
1310 }
1311 }
1312
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001313 // Labeling successful. Mark the top level directory as completed.
1314 if (setrestoreconlast && !nochange && !error)
1315 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1316
Stephen Smalley08587cf2014-01-30 10:13:12 -05001317out:
1318 sverrno = errno;
1319 (void) fts_close(fts);
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001320 errno = sverrno;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001321 return error;
1322}
1323
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001324int selinux_android_restorecon(const char *file, unsigned int flags)
1325{
1326 return selinux_android_restorecon_common(file, NULL, -1, flags);
1327}
1328
1329int selinux_android_restorecon_pkgdir(const char *pkgdir,
1330 const char *seinfo,
1331 uid_t uid,
1332 unsigned int flags)
1333{
1334 return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1335}
1336
rpcraigf1724a32012-08-01 15:35:37 -04001337struct selabel_handle* selinux_android_file_context_handle(void)
1338{
dcashman965141a2014-12-03 12:51:50 -08001339 struct selabel_handle *sehandle;
1340
1341 set_policy_index();
1342 sehandle = selabel_open(SELABEL_CTX_FILE, &seopts[policy_index], 1);
1343
1344 if (!sehandle) {
1345 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
1346 __FUNCTION__, strerror(errno));
1347 return NULL;
1348 }
1349 if (!compute_contexts_hash(seopts, fc_digest)) {
1350 selabel_close(sehandle);
1351 return NULL;
1352 }
1353 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n",
1354 seopts[policy_index].value);
1355
1356 return sehandle;
1357}
1358
1359struct selabel_handle* selinux_android_prop_context_handle(void)
1360{
1361 struct selabel_handle* sehandle;
1362
1363 set_policy_index();
1364 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1365 &seopts_prop[policy_index], 1);
1366 if (!sehandle) {
1367 selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n",
1368 __FUNCTION__, strerror(errno));
1369 return NULL;
1370 }
1371 selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n",
1372 seopts_prop[policy_index].value);
1373
1374 return sehandle;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001375}
1376
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001377struct selabel_handle* selinux_android_service_context_handle(void)
1378{
dcashman965141a2014-12-03 12:51:50 -08001379 struct selabel_handle* sehandle;
1380
1381 set_policy_index();
1382 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1383 &seopts_service[policy_index], 1);
1384
1385 if (!sehandle) {
1386 selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
1387 __FUNCTION__, strerror(errno));
1388 return NULL;
1389 }
1390 selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n",
1391 seopts_service[policy_index].value);
1392
1393 return sehandle;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001394}
1395
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001396void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1397{
dcashman965141a2014-12-03 12:51:50 -08001398 fc_sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -04001399}
rpcraig9b100832012-07-27 06:36:59 -04001400
Robert Craig5b5183f2014-03-17 20:53:06 -04001401static int selinux_android_load_policy_helper(bool reload)
rpcraigf1724a32012-08-01 15:35:37 -04001402{
Stephen Smalley4a655ec2012-09-18 15:08:32 -04001403 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -04001404 struct stat sb;
1405 void *map = NULL;
Stephen Smalley818815e2015-02-18 17:32:13 -05001406 int old_policy_index = policy_index;
rpcraigf1724a32012-08-01 15:35:37 -04001407
Robert Craig5b5183f2014-03-17 20:53:06 -04001408 /*
1409 * If reloading policy and there is no /data policy or
Stephen Smalley818815e2015-02-18 17:32:13 -05001410 * that /data policy has the wrong version and our prior
1411 * load was from the / policy, then just return.
Robert Craig5b5183f2014-03-17 20:53:06 -04001412 * There is no point in reloading policy from / a second time.
1413 */
dcashman965141a2014-12-03 12:51:50 -08001414 set_policy_index();
Stephen Smalley818815e2015-02-18 17:32:13 -05001415 if (reload && !policy_index && !old_policy_index)
Robert Craig5b5183f2014-03-17 20:53:06 -04001416 return 0;
1417
1418 fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -04001419 if (fd < 0) {
1420 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
1421 strerror(errno));
1422 return -1;
1423 }
1424 if (fstat(fd, &sb) < 0) {
1425 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -04001426 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001427 close(fd);
1428 return -1;
1429 }
1430 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1431 if (map == MAP_FAILED) {
1432 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001433 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001434 close(fd);
1435 return -1;
1436 }
1437
1438 rc = security_load_policy(map, sb.st_size);
1439 if (rc < 0) {
1440 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001441 strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001442 munmap(map, sb.st_size);
1443 close(fd);
1444 return -1;
1445 }
1446
1447 munmap(map, sb.st_size);
1448 close(fd);
Robert Craig5b5183f2014-03-17 20:53:06 -04001449 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
rpcraigf1724a32012-08-01 15:35:37 -04001450
1451 return 0;
1452}
1453
Robert Craig5b5183f2014-03-17 20:53:06 -04001454int selinux_android_reload_policy(void)
1455{
1456 return selinux_android_load_policy_helper(true);
1457}
1458
rpcraigf1724a32012-08-01 15:35:37 -04001459int selinux_android_load_policy(void)
1460{
Nick Kralevich833cba62013-11-19 11:24:33 -08001461 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001462 int rc;
1463 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1464 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001465 if (errno == ENODEV) {
1466 /* SELinux not enabled in kernel */
1467 return -1;
1468 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001469 if (errno == ENOENT) {
1470 /* Fall back to legacy mountpoint. */
1471 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -08001472 rc = mkdir(mnt, 0755);
1473 if (rc == -1 && errno != EEXIST) {
1474 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
1475 strerror(errno));
1476 return -1;
1477 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001478 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1479 }
1480 }
1481 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001482 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
1483 strerror(errno));
1484 return -1;
1485 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001486 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -04001487
Robert Craig5b5183f2014-03-17 20:53:06 -04001488 return selinux_android_load_policy_helper(false);
rpcraig9b100832012-07-27 06:36:59 -04001489}
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001490
1491int selinux_log_callback(int type, const char *fmt, ...)
1492{
1493 va_list ap;
1494 int priority;
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001495 char *strp;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001496
1497 switch(type) {
1498 case SELINUX_WARNING:
1499 priority = ANDROID_LOG_WARN;
1500 break;
1501 case SELINUX_INFO:
1502 priority = ANDROID_LOG_INFO;
1503 break;
1504 default:
1505 priority = ANDROID_LOG_ERROR;
1506 break;
1507 }
1508
1509 va_start(ap, fmt);
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001510 if (vasprintf(&strp, fmt, ap) != -1) {
1511 LOG_PRI(priority, "SELinux", "%s", strp);
1512 LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
1513 free(strp);
1514 }
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001515 va_end(ap);
1516 return 0;
1517}