blob: a15c9abc3e1f6d9fe94d9e76d9c945349210b00d [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>
Stephen Smalleyd10c3432012-11-05 11:49:35 -050025#include "policy.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050026#include "callbacks.h"
27#include "selinux_internal.h"
Stephen Smalley0e7340f2014-04-30 15:13:30 -070028#include "label_internal.h"
Stephen Smalleyf0740362012-01-04 12:30:47 -050029
30/*
31 * XXX Where should this configuration file be located?
32 * Needs to be accessible by zygote and installd when
33 * setting credentials for app processes and setting permissions
34 * on app data directories.
35 */
Stephen Smalley7446c912012-03-19 10:37:05 -040036static char const * const seapp_contexts_file[] = {
Stephen Smalley7446c912012-03-19 10:37:05 -040037 "/seapp_contexts",
William Roberts8ed42422013-04-15 16:13:30 -070038 NULL };
Stephen Smalleyf0740362012-01-04 12:30:47 -050039
Stephen Smalley32ebfe82012-03-20 13:05:37 -040040static const struct selinux_opt seopts[] = {
Stephen Smalley32ebfe82012-03-20 13:05:37 -040041 { SELABEL_OPT_PATH, "/file_contexts" },
42 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040043
Stephen Smalley4a655ec2012-09-18 15:08:32 -040044static const char *const sepolicy_file[] = {
rpcraigf1724a32012-08-01 15:35:37 -040045 "/sepolicy",
William Roberts8ed42422013-04-15 16:13:30 -070046 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040047
Stephen Smalleya8795982012-11-28 10:42:46 -050048enum levelFrom {
49 LEVELFROM_NONE,
50 LEVELFROM_APP,
51 LEVELFROM_USER,
52 LEVELFROM_ALL
53};
54
55#if DEBUG
56static char const * const levelFromName[] = {
57 "none",
58 "app",
59 "user",
60 "all"
61};
62#endif
63
William Robertse3615f92013-09-11 20:35:53 -070064struct prefix_str {
65 size_t len;
66 char *str;
67 char is_prefix;
68};
69
Stephen Smalley13319cf2014-04-04 15:44:23 -040070static void free_prefix_str(struct prefix_str *p)
71{
72 if (!p)
73 return;
74 free(p->str);
75}
76
Stephen Smalleyf0740362012-01-04 12:30:47 -050077struct seapp_context {
78 /* input selectors */
79 char isSystemServer;
William Robertse3615f92013-09-11 20:35:53 -070080 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -050081 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -070082 struct prefix_str name;
Stephen Smalley274e0f62014-02-19 10:53:09 -050083 struct prefix_str path;
Stephen Smalleyf0740362012-01-04 12:30:47 -050084 /* outputs */
85 char *domain;
86 char *type;
87 char *level;
William Roberts1b36ad02012-07-27 13:52:33 -070088 char *sebool;
Stephen Smalleya8795982012-11-28 10:42:46 -050089 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -050090};
91
Stephen Smalley13319cf2014-04-04 15:44:23 -040092static void free_seapp_context(struct seapp_context *s)
93{
94 if (!s)
95 return;
96
97 free_prefix_str(&s->user);
98 free(s->seinfo);
99 free_prefix_str(&s->name);
100 free_prefix_str(&s->path);
101 free(s->domain);
102 free(s->type);
103 free(s->level);
104 free(s->sebool);
105}
106
Stephen Smalleyf0740362012-01-04 12:30:47 -0500107static int seapp_context_cmp(const void *A, const void *B)
108{
Nick Kralevich833cba62013-11-19 11:24:33 -0800109 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
110 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500111 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
112
113 /* Give precedence to isSystemServer=true. */
114 if (s1->isSystemServer != s2->isSystemServer)
115 return (s1->isSystemServer ? -1 : 1);
116
117 /* Give precedence to a specified user= over an unspecified user=. */
William Robertse3615f92013-09-11 20:35:53 -0700118 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500119 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700120 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500121 return 1;
122
William Robertse3615f92013-09-11 20:35:53 -0700123 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500124 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700125 if (s1->user.is_prefix != s2->user.is_prefix)
126 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500127
128 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700129 if (s1->user.is_prefix && s1->user.len != s2->user.len)
130 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500131 }
132
133 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
134 if (s1->seinfo && !s2->seinfo)
135 return -1;
136 if (!s1->seinfo && s2->seinfo)
137 return 1;
138
139 /* Give precedence to a specified name= over an unspecified name=. */
William Robertse3615f92013-09-11 20:35:53 -0700140 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500141 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700142 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500143 return 1;
144
William Robertse3615f92013-09-11 20:35:53 -0700145 if (s1->name.str) {
146 /* Give precedence to a fixed name= string over a prefix. */
147 if (s1->name.is_prefix != s2->name.is_prefix)
148 return (s2->name.is_prefix ? -1 : 1);
149
150 /* Give precedence to a longer prefix over a shorter prefix. */
151 if (s1->name.is_prefix && s1->name.len != s2->name.len)
152 return (s1->name.len > s2->name.len) ? -1 : 1;
153 }
154
Stephen Smalley274e0f62014-02-19 10:53:09 -0500155 /* Give precedence to a specified path= over an unspecified path=. */
156 if (s1->path.str && !s2->path.str)
157 return -1;
158 if (!s1->path.str && s2->path.str)
159 return 1;
160
161 if (s1->path.str) {
162 /* Give precedence to a fixed path= string over a prefix. */
163 if (s1->path.is_prefix != s2->path.is_prefix)
164 return (s2->path.is_prefix ? -1 : 1);
165
166 /* Give precedence to a longer prefix over a shorter prefix. */
167 if (s1->path.is_prefix && s1->path.len != s2->path.len)
168 return (s1->path.len > s2->path.len) ? -1 : 1;
169 }
170
William Roberts1b36ad02012-07-27 13:52:33 -0700171 /* Give precedence to a specified sebool= over an unspecified sebool=. */
172 if (s1->sebool && !s2->sebool)
173 return -1;
174 if (!s1->sebool && s2->sebool)
175 return 1;
176
Stephen Smalleyf0740362012-01-04 12:30:47 -0500177 /* Anything else has equal precedence. */
178 return 0;
179}
180
181static struct seapp_context **seapp_contexts = NULL;
182static int nspec = 0;
183
Stephen Smalley13319cf2014-04-04 15:44:23 -0400184static void free_seapp_contexts(void)
185{
186 int n;
187
188 if (!seapp_contexts)
189 return;
190
191 for (n = 0; n < nspec; n++)
192 free_seapp_context(seapp_contexts[n]);
193
194 free(seapp_contexts);
195 seapp_contexts = NULL;
196 nspec = 0;
197}
198
Stephen Smalley7446c912012-03-19 10:37:05 -0400199int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500200{
Stephen Smalley7446c912012-03-19 10:37:05 -0400201 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500202 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500203 char *token;
204 unsigned lineno;
205 struct seapp_context *cur;
206 char *p, *name = NULL, *value = NULL, *saveptr;
207 size_t len;
Stephen Smalley300bebb2013-04-16 15:33:16 -0400208 int i = 0, n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500209
Stephen Smalley7446c912012-03-19 10:37:05 -0400210 while ((fp==NULL) && seapp_contexts_file[i])
211 fp = fopen(seapp_contexts_file[i++], "r");
212
Stephen Smalleyf0740362012-01-04 12:30:47 -0500213 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400214 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
215 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500216 }
217
Stephen Smalley13319cf2014-04-04 15:44:23 -0400218 free_seapp_contexts();
Stephen Smalley300bebb2013-04-16 15:33:16 -0400219
Stephen Smalleyf0740362012-01-04 12:30:47 -0500220 nspec = 0;
221 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
222 p = line_buf;
223 while (isspace(*p))
224 p++;
225 if (*p == '#' || *p == 0)
226 continue;
227 nspec++;
228 }
229
Nick Kralevich833cba62013-11-19 11:24:33 -0800230 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500231 if (!seapp_contexts)
232 goto oom;
233
234 rewind(fp);
235 nspec = 0;
236 lineno = 1;
237 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
238 len = strlen(line_buf);
239 if (line_buf[len - 1] == '\n')
240 line_buf[len - 1] = 0;
241 p = line_buf;
242 while (isspace(*p))
243 p++;
244 if (*p == '#' || *p == 0)
245 continue;
246
Nick Kralevich833cba62013-11-19 11:24:33 -0800247 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500248 if (!cur)
249 goto oom;
250
251 token = strtok_r(p, " \t", &saveptr);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400252 if (!token) {
253 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500254 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400255 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500256
257 while (1) {
258 name = token;
259 value = strchr(name, '=');
Stephen Smalley13319cf2014-04-04 15:44:23 -0400260 if (!value) {
261 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500262 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400263 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500264 *value++ = 0;
265
266 if (!strcasecmp(name, "isSystemServer")) {
267 if (!strcasecmp(value, "true"))
268 cur->isSystemServer = 1;
269 else if (!strcasecmp(value, "false"))
270 cur->isSystemServer = 0;
271 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400272 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500273 goto err;
274 }
275 } else if (!strcasecmp(name, "user")) {
William Robertse3615f92013-09-11 20:35:53 -0700276 cur->user.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400277 if (!cur->user.str) {
278 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500279 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400280 }
William Robertse3615f92013-09-11 20:35:53 -0700281 cur->user.len = strlen(cur->user.str);
282 if (cur->user.str[cur->user.len-1] == '*')
283 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500284 } else if (!strcasecmp(name, "seinfo")) {
285 cur->seinfo = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400286 if (!cur->seinfo) {
287 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500288 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400289 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500290 } else if (!strcasecmp(name, "name")) {
William Robertse3615f92013-09-11 20:35:53 -0700291 cur->name.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400292 if (!cur->name.str) {
293 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500294 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400295 }
William Robertse3615f92013-09-11 20:35:53 -0700296 cur->name.len = strlen(cur->name.str);
297 if (cur->name.str[cur->name.len-1] == '*')
298 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500299 } else if (!strcasecmp(name, "domain")) {
300 cur->domain = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400301 if (!cur->domain) {
302 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500303 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400304 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500305 } else if (!strcasecmp(name, "type")) {
306 cur->type = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400307 if (!cur->type) {
308 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500309 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400310 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500311 } else if (!strcasecmp(name, "levelFromUid")) {
312 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500313 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500314 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500315 cur->levelFrom = LEVELFROM_NONE;
316 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400317 free_seapp_context(cur);
Stephen Smalleya8795982012-11-28 10:42:46 -0500318 goto err;
319 }
320 } else if (!strcasecmp(name, "levelFrom")) {
321 if (!strcasecmp(value, "none"))
322 cur->levelFrom = LEVELFROM_NONE;
323 else if (!strcasecmp(value, "app"))
324 cur->levelFrom = LEVELFROM_APP;
325 else if (!strcasecmp(value, "user"))
326 cur->levelFrom = LEVELFROM_USER;
327 else if (!strcasecmp(value, "all"))
328 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500329 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400330 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500331 goto err;
332 }
333 } else if (!strcasecmp(name, "level")) {
334 cur->level = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400335 if (!cur->level) {
336 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500337 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400338 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500339 } else if (!strcasecmp(name, "path")) {
340 cur->path.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400341 if (!cur->path.str) {
342 free_seapp_context(cur);
Stephen Smalley274e0f62014-02-19 10:53:09 -0500343 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400344 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500345 cur->path.len = strlen(cur->path.str);
346 if (cur->path.str[cur->path.len-1] == '*')
347 cur->path.is_prefix = 1;
William Roberts1b36ad02012-07-27 13:52:33 -0700348 } else if (!strcasecmp(name, "sebool")) {
349 cur->sebool = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400350 if (!cur->sebool) {
351 free_seapp_context(cur);
William Roberts1b36ad02012-07-27 13:52:33 -0700352 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400353 }
354 } else {
355 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500356 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400357 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500358
359 token = strtok_r(NULL, " \t", &saveptr);
360 if (!token)
361 break;
362 }
363
Stephen Smalley13319cf2014-04-04 15:44:23 -0400364 if (cur->name.str &&
365 (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
366 selinux_log(SELINUX_ERROR, "%s: No specific seinfo value specified with name=\"%s\", on line %u: insecure configuration!\n",
367 seapp_contexts_file[i - 1], cur->name.str, lineno);
368 free_seapp_context(cur);
369 goto err;
370 }
371
Stephen Smalleyf0740362012-01-04 12:30:47 -0500372 seapp_contexts[nspec] = cur;
373 nspec++;
374 lineno++;
375 }
376
377 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
378 seapp_context_cmp);
379
380#if DEBUG
381 {
382 int i;
383 for (i = 0; i < nspec; i++) {
384 cur = seapp_contexts[i];
Stephen Smalley274e0f62014-02-19 10:53:09 -0500385 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s user=%s seinfo=%s name=%s path=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s",
William Roberts1b36ad02012-07-27 13:52:33 -0700386 __FUNCTION__,
William Robertse3615f92013-09-11 20:35:53 -0700387 cur->isSystemServer ? "true" : "false", cur->user.str,
Stephen Smalley274e0f62014-02-19 10:53:09 -0500388 cur->seinfo, cur->name.str, cur->path.str, cur->sebool, cur->domain,
William Roberts1b36ad02012-07-27 13:52:33 -0700389 cur->type, cur->level,
Stephen Smalleya8795982012-11-28 10:42:46 -0500390 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500391 }
392 }
393#endif
394
Stephen Smalley7446c912012-03-19 10:37:05 -0400395 ret = 0;
396
Stephen Smalleyf0740362012-01-04 12:30:47 -0500397out:
398 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400399 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500400
401err:
Stephen Smalley13319cf2014-04-04 15:44:23 -0400402 selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n",
403 seapp_contexts_file[i - 1], lineno);
404 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400405 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500406 goto out;
407oom:
408 selinux_log(SELINUX_ERROR,
409 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400410 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400411 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500412 goto out;
413}
414
Stephen Smalley7446c912012-03-19 10:37:05 -0400415
416static void seapp_context_init(void)
417{
418 selinux_android_seapp_context_reload();
419}
420
Stephen Smalleyf0740362012-01-04 12:30:47 -0500421static pthread_once_t once = PTHREAD_ONCE_INIT;
422
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400423/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500424 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400425 * using the current scheme.
426 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500427#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400428
429enum seapp_kind {
430 SEAPP_TYPE,
431 SEAPP_DOMAIN
432};
433
434static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400435 uid_t uid,
436 int isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400437 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400438 const char *pkgname,
Stephen Smalley274e0f62014-02-19 10:53:09 -0500439 const char *path,
Stephen Smalley895b4462012-09-19 16:27:36 -0400440 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500441{
Stephen Smalley895b4462012-09-19 16:27:36 -0400442 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700443 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400444 int i;
445 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500446 uid_t userid;
447 uid_t appid;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500448
Stephen Smalleye183cec2014-02-05 16:41:47 -0500449 __selinux_once(once, seapp_context_init);
450
Stephen Smalleya8795982012-11-28 10:42:46 -0500451 userid = uid / AID_USER;
Stephen Smalley895b4462012-09-19 16:27:36 -0400452 appid = uid % AID_USER;
453 if (appid < AID_APP) {
454 for (n = 0; n < android_id_count; n++) {
455 if (android_ids[n].aid == appid) {
456 username = android_ids[n].name;
457 break;
458 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400459 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400460 if (!username)
461 goto err;
462 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400463 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400464 appid -= AID_APP;
465 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400466 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400467 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400468 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500469
Stephen Smalleya8795982012-11-28 10:42:46 -0500470 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400471 goto err;
472
Stephen Smalleyf0740362012-01-04 12:30:47 -0500473 for (i = 0; i < nspec; i++) {
474 cur = seapp_contexts[i];
475
Stephen Smalley895b4462012-09-19 16:27:36 -0400476 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500477 continue;
478
William Robertse3615f92013-09-11 20:35:53 -0700479 if (cur->user.str) {
480 if (cur->user.is_prefix) {
481 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500482 continue;
483 } else {
William Robertse3615f92013-09-11 20:35:53 -0700484 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500485 continue;
486 }
487 }
488
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400489 if (cur->seinfo) {
490 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
491 continue;
492 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500493
William Robertse3615f92013-09-11 20:35:53 -0700494 if (cur->name.str) {
495 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500496 continue;
William Robertse3615f92013-09-11 20:35:53 -0700497
498 if (cur->name.is_prefix) {
499 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
500 continue;
501 } else {
502 if (strcasecmp(pkgname, cur->name.str))
503 continue;
504 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500505 }
506
Stephen Smalley274e0f62014-02-19 10:53:09 -0500507 if (cur->path.str) {
508 if (!path)
509 continue;
510
511 if (cur->path.is_prefix) {
512 if (strncmp(path, cur->path.str, cur->path.len-1))
513 continue;
514 } else {
515 if (strcmp(path, cur->path.str))
516 continue;
517 }
518 }
519
Stephen Smalley895b4462012-09-19 16:27:36 -0400520 if (kind == SEAPP_TYPE && !cur->type)
521 continue;
522 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500523 continue;
524
William Roberts1b36ad02012-07-27 13:52:33 -0700525 if (cur->sebool) {
526 int value = security_get_boolean_active(cur->sebool);
527 if (value == 0)
528 continue;
529 else if (value == -1) {
530 selinux_log(SELINUX_ERROR, \
531 "Could not find boolean: %s ", cur->sebool);
532 goto err;
533 }
534 }
535
Stephen Smalley895b4462012-09-19 16:27:36 -0400536 if (kind == SEAPP_TYPE) {
537 if (context_type_set(ctx, cur->type))
538 goto oom;
539 } else if (kind == SEAPP_DOMAIN) {
540 if (context_type_set(ctx, cur->domain))
541 goto oom;
542 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500543
Stephen Smalleya8795982012-11-28 10:42:46 -0500544 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500545 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500546 switch (cur->levelFrom) {
547 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500548 snprintf(level, sizeof level, "s0:c%u,c%u",
549 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500550 256 + (appid>>8 & 0xff));
551 break;
552 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500553 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500554 512 + (userid & 0xff),
555 768 + (userid>>8 & 0xff));
556 break;
557 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500558 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
559 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500560 256 + (appid>>8 & 0xff),
561 512 + (userid & 0xff),
562 768 + (userid>>8 & 0xff));
563 break;
564 default:
565 goto err;
566 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500567 if (context_range_set(ctx, level))
568 goto oom;
569 } else if (cur->level) {
570 if (context_range_set(ctx, cur->level))
571 goto oom;
572 }
William Roberts1b36ad02012-07-27 13:52:33 -0700573
Stephen Smalleyf0740362012-01-04 12:30:47 -0500574 break;
575 }
576
Stephen Smalley895b4462012-09-19 16:27:36 -0400577 if (kind == SEAPP_DOMAIN && i == nspec) {
578 /*
579 * No match.
580 * Fail to prevent staying in the zygote's context.
581 */
582 selinux_log(SELINUX_ERROR,
583 "%s: No match for app with uid %d, seinfo %s, name %s\n",
584 __FUNCTION__, uid, seinfo, pkgname);
585
586 if (security_getenforce() == 1)
587 goto err;
588 }
589
590 return 0;
591err:
592 return -1;
593oom:
594 return -2;
595}
596
Stephen Smalley1b478ea2014-02-07 09:32:41 -0500597int selinux_android_setfilecon(const char *pkgdir,
Stephen Smalley895b4462012-09-19 16:27:36 -0400598 const char *pkgname,
599 const char *seinfo,
600 uid_t uid)
601{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700602 char *orig_ctx_str = NULL;
603 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400604 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700605 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400606
607 if (is_selinux_enabled() <= 0)
608 return 0;
609
Stephen Smalley895b4462012-09-19 16:27:36 -0400610 rc = getfilecon(pkgdir, &ctx_str);
611 if (rc < 0)
612 goto err;
613
614 ctx = context_new(ctx_str);
615 orig_ctx_str = ctx_str;
616 if (!ctx)
617 goto oom;
618
Stephen Smalley274e0f62014-02-19 10:53:09 -0500619 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400620 if (rc == -1)
621 goto err;
622 else if (rc == -2)
623 goto oom;
624
Stephen Smalleyf0740362012-01-04 12:30:47 -0500625 ctx_str = context_str(ctx);
626 if (!ctx_str)
627 goto oom;
628
629 rc = security_check_context(ctx_str);
630 if (rc < 0)
631 goto err;
632
633 if (strcmp(ctx_str, orig_ctx_str)) {
634 rc = setfilecon(pkgdir, ctx_str);
635 if (rc < 0)
636 goto err;
637 }
638
639 rc = 0;
640out:
641 freecon(orig_ctx_str);
642 context_free(ctx);
643 return rc;
644err:
645 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
646 __FUNCTION__, pkgdir, uid, strerror(errno));
647 rc = -1;
648 goto out;
649oom:
650 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
651 rc = -1;
652 goto out;
653}
654
655int selinux_android_setcontext(uid_t uid,
656 int isSystemServer,
657 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400658 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500659{
Stephen Smalley895b4462012-09-19 16:27:36 -0400660 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500661 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700662 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500663
664 if (is_selinux_enabled() <= 0)
665 return 0;
666
Stephen Smalleyf0740362012-01-04 12:30:47 -0500667 rc = getcon(&ctx_str);
668 if (rc)
669 goto err;
670
671 ctx = context_new(ctx_str);
672 orig_ctx_str = ctx_str;
673 if (!ctx)
674 goto oom;
675
Stephen Smalley274e0f62014-02-19 10:53:09 -0500676 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400677 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500678 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400679 else if (rc == -2)
680 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500681
682 ctx_str = context_str(ctx);
683 if (!ctx_str)
684 goto oom;
685
686 rc = security_check_context(ctx_str);
687 if (rc < 0)
688 goto err;
689
690 if (strcmp(ctx_str, orig_ctx_str)) {
691 rc = setcon(ctx_str);
692 if (rc < 0)
693 goto err;
694 }
695
696 rc = 0;
697out:
698 freecon(orig_ctx_str);
699 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400700 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500701 return rc;
702err:
703 if (isSystemServer)
704 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700705 "%s: Error setting context for system server: %s\n",
706 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500707 else
708 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700709 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
710 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500711
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400712 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500713 goto out;
714oom:
715 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
716 rc = -1;
717 goto out;
718}
719
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400720static struct selabel_handle *sehandle = NULL;
Stephen Smalley826cc292014-01-28 15:04:22 -0500721#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
722static uint8_t fc_digest[FC_DIGEST_SIZE];
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400723
Stephen Smalley826cc292014-01-28 15:04:22 -0500724static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[])
725{
726 struct selabel_handle *h;
727 unsigned int i = 0;
728 int fd;
729 struct stat sb;
730 void *map;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400731
Stephen Smalley826cc292014-01-28 15:04:22 -0500732 h = NULL;
733 while ((h == NULL) && opts[i].value) {
734 h = selabel_open(SELABEL_CTX_FILE, &opts[i], 1);
735 if (h)
736 break;
737 i++;
738 }
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400739
Stephen Smalley826cc292014-01-28 15:04:22 -0500740 if (!h)
741 return NULL;
742
743 fd = open(opts[i].value, O_RDONLY | O_NOFOLLOW);
744 if (fd < 0) {
745 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n",
746 opts[i].value, strerror(errno));
747 goto err;
748 }
749 if (fstat(fd, &sb) < 0) {
750 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
751 opts[i].value, strerror(errno));
752 close(fd);
753 goto err;
754 }
755 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
756 if (map == MAP_FAILED) {
757 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
758 opts[i].value, strerror(errno));
759 close(fd);
760 goto err;
761 }
762 SHA_hash(map, sb.st_size, fc_digest);
763 munmap(map, sb.st_size);
764 close(fd);
765
Stephen Smalley0a101042014-01-29 12:54:01 -0500766 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts from %s\n",
Stephen Smalley826cc292014-01-28 15:04:22 -0500767 opts[i].value);
Stephen Smalley826cc292014-01-28 15:04:22 -0500768
769 return h;
770
771err:
772 selabel_close(h);
773 return NULL;
Geremy Condra60646432013-04-10 17:58:48 -0700774}
775
776static struct selabel_handle *file_context_open(void)
777{
778 struct selabel_handle *h;
779
780 h = get_selabel_handle(seopts);
781
Stephen Smalley906742d2012-08-23 16:04:59 -0400782 if (!h)
Geremy Condra60646432013-04-10 17:58:48 -0700783 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
784 __FUNCTION__, strerror(errno));
785 return h;
786}
787
Stephen Smalley906742d2012-08-23 16:04:59 -0400788static void file_context_init(void)
789{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -0500790 if (!sehandle)
791 sehandle = file_context_open();
792}
793
Stephen Smalley08587cf2014-01-30 10:13:12 -0500794static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
795
Stephen Smalleye183cec2014-02-05 16:41:47 -0500796struct pkgInfo {
797 char *name;
798 uid_t uid;
799 bool debuggable;
800 char *dataDir;
801 char *seinfo;
802 struct pkgInfo *next;
803};
804
805#define PKGTAB_SIZE 256
806static struct pkgInfo *pkgTab[PKGTAB_SIZE];
807
808static unsigned int pkghash(const char *pkgname)
809{
810 unsigned int h = 7;
811 for (; *pkgname; pkgname++) {
812 h = h * 31 + *pkgname;
813 }
814 return h & (PKGTAB_SIZE - 1);
815}
816
817/* The file containing the list of installed packages on the system */
818#define PACKAGES_LIST_FILE "/data/system/packages.list"
819
820static void package_info_init(void)
821{
822 char *buf = NULL;
823 size_t buflen = 0;
824 ssize_t bytesread;
825 FILE *fp;
826 char *cur, *next;
827 struct pkgInfo *pkgInfo = NULL;
828 unsigned int hash;
829 unsigned long lineno = 1;
830
831 fp = fopen(PACKAGES_LIST_FILE, "r");
832 if (!fp) {
833 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s.\n",
834 PACKAGES_LIST_FILE, strerror(errno));
835 return;
836 }
837 while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
838 pkgInfo = calloc(1, sizeof(*pkgInfo));
839 if (!pkgInfo)
840 goto err;
841 next = buf;
842 cur = strsep(&next, " \t\n");
843 if (!cur)
844 goto err;
845 pkgInfo->name = strdup(cur);
846 if (!pkgInfo->name)
847 goto err;
848 cur = strsep(&next, " \t\n");
849 if (!cur)
850 goto err;
851 pkgInfo->uid = atoi(cur);
852 if (!pkgInfo->uid)
853 goto err;
854 cur = strsep(&next, " \t\n");
855 if (!cur)
856 goto err;
857 pkgInfo->debuggable = atoi(cur);
858 cur = strsep(&next, " \t\n");
859 if (!cur)
860 goto err;
861 pkgInfo->dataDir = strdup(cur);
862 if (!pkgInfo->dataDir)
863 goto err;
864 cur = strsep(&next, " \t\n");
865 if (!cur)
866 goto err;
867 pkgInfo->seinfo = strdup(cur);
868 if (!pkgInfo->seinfo)
869 goto err;
870
871 hash = pkghash(pkgInfo->name);
872 if (pkgTab[hash])
873 pkgInfo->next = pkgTab[hash];
874 pkgTab[hash] = pkgInfo;
875
876 lineno++;
877 }
878
879#if DEBUG
880 {
881 unsigned int buckets, entries, chainlen, longestchain;
882
883 buckets = entries = longestchain = 0;
884 for (hash = 0; hash < PKGTAB_SIZE; hash++) {
885 if (pkgTab[hash]) {
886 buckets++;
887 chainlen = 0;
888 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
889 chainlen++;
890 selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
891 __FUNCTION__,
892 pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo);
893 }
894 entries += chainlen;
895 if (longestchain < chainlen)
896 longestchain = chainlen;
897 }
898 }
899 selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
900 }
901#endif
902
903out:
904 free(buf);
905 fclose(fp);
906 return;
907
908err:
909 selinux_log(SELINUX_ERROR, "SELinux: Error reading %s on line %lu.\n",
910 PACKAGES_LIST_FILE, lineno);
911 if (pkgInfo) {
912 free(pkgInfo->name);
913 free(pkgInfo->dataDir);
914 free(pkgInfo->seinfo);
915 free(pkgInfo);
916 }
917 goto out;
918}
919
920static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
921
922struct pkgInfo *package_info_lookup(const char *name)
923{
924 struct pkgInfo *pkgInfo;
925 unsigned int hash;
926
927 __selinux_once(pkg_once, package_info_init);
928
929 hash = pkghash(name);
930 for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
931 if (!strcmp(name, pkgInfo->name))
932 return pkgInfo;
933 }
934 return NULL;
935}
936
937/* The path prefixes of package data directories. */
Stephen Smalley027670d2014-02-18 11:04:37 -0500938#define DATA_DATA_PATH "/data/data"
939#define DATA_USER_PATH "/data/user"
940#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
941#define DATA_USER_PREFIX DATA_USER_PATH "/"
Stephen Smalleye183cec2014-02-05 16:41:47 -0500942
Stephen Smalley1d66afb2014-03-27 08:47:15 -0400943static int pkgdir_selabel_lookup(const char *pathname,
944 const char *seinfo,
945 uid_t uid,
946 char **secontextp)
Stephen Smalleye183cec2014-02-05 16:41:47 -0500947{
948 char *pkgname = NULL, *end = NULL;
949 struct pkgInfo *pkgInfo = NULL;
950 char *secontext = *secontextp;
951 context_t ctx = NULL;
952 int rc = 0;
953
954 /* Skip directory prefix before package name. */
955 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
956 pathname += sizeof(DATA_DATA_PREFIX) - 1;
957 } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
958 pathname += sizeof(DATA_USER_PREFIX) - 1;
959 while (isdigit(*pathname))
960 pathname++;
961 if (*pathname == '/')
962 pathname++;
963 else
964 return 0;
965 } else
966 return 0;
967
968 if (!(*pathname))
969 return 0;
970
971 pkgname = strdup(pathname);
972 if (!pkgname)
973 return -1;
974
975 for (end = pkgname; *end && *end != '/'; end++)
976 ;
Stephen Smalley274e0f62014-02-19 10:53:09 -0500977 pathname = end;
978 if (*end)
979 pathname++;
Stephen Smalleye183cec2014-02-05 16:41:47 -0500980 *end = '\0';
981
Stephen Smalley1d66afb2014-03-27 08:47:15 -0400982 if (!seinfo) {
983 pkgInfo = package_info_lookup(pkgname);
984 if (!pkgInfo) {
985 selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
986 pkgname, pathname);
987 free(pkgname);
988 return -1;
989 }
Stephen Smalleye183cec2014-02-05 16:41:47 -0500990 }
991
992 ctx = context_new(secontext);
993 if (!ctx)
994 goto err;
995
Stephen Smalley1d66afb2014-03-27 08:47:15 -0400996 rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0,
997 pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx);
Stephen Smalleye183cec2014-02-05 16:41:47 -0500998 if (rc < 0)
999 goto err;
1000
1001 secontext = context_str(ctx);
1002 if (!secontext)
1003 goto err;
1004
1005 if (!strcmp(secontext, *secontextp))
1006 goto out;
1007
1008 rc = security_check_context(secontext);
1009 if (rc < 0)
1010 goto err;
1011
1012 freecon(*secontextp);
1013 *secontextp = strdup(secontext);
1014 if (!(*secontextp))
1015 goto err;
1016
1017 rc = 0;
1018
1019out:
1020 free(pkgname);
1021 context_free(ctx);
1022 return rc;
1023err:
1024 selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
1025 __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno));
1026 rc = -1;
1027 goto out;
1028}
1029
Stephen Smalley826cc292014-01-28 15:04:22 -05001030#define RESTORECON_LAST "security.restorecon_last"
1031
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001032static int restorecon_sb(const char *pathname, const struct stat *sb,
1033 bool setrestoreconlast, bool nochange, bool verbose,
1034 const char *seinfo, uid_t uid)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001035{
1036 char *secontext = NULL;
1037 char *oldsecontext = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001038 int rc = 0;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001039
1040 if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
Stephen Smalleyb77c0362014-02-04 13:22:28 -05001041 return -1;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001042
Stephen Smalleye183cec2014-02-05 16:41:47 -05001043 if (lgetfilecon(pathname, &oldsecontext) < 0)
1044 goto err;
1045
Stephen Smalley833cbd62014-02-27 13:08:40 -05001046 /*
1047 * Disable setting restorecon_last on /data/data or /data/user
1048 * since their labeling is based on seapp_contexts and seinfo
1049 * assignments rather than file_contexts and is managed by
1050 * installd rather than init.
1051 */
1052 if (!strcmp(pathname, DATA_DATA_PATH) || !strcmp(pathname, DATA_USER_PATH))
1053 setrestoreconlast = false;
1054
Stephen Smalleye183cec2014-02-05 16:41:47 -05001055 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
1056 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
Stephen Smalley833cbd62014-02-27 13:08:40 -05001057 /* Same as above for all children of /data/data and /data/user. */
1058 setrestoreconlast = false;
1059
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001060 if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001061 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001062 }
1063
1064 if (strcmp(oldsecontext, secontext) != 0) {
Stephen Smalley08587cf2014-01-30 10:13:12 -05001065 if (verbose)
1066 selinux_log(SELINUX_INFO,
1067 "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1068 if (!nochange) {
Stephen Smalleye183cec2014-02-05 16:41:47 -05001069 if (lsetfilecon(pathname, secontext) < 0)
1070 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001071 }
1072 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001073
Stephen Smalley08587cf2014-01-30 10:13:12 -05001074 if (setrestoreconlast && !nochange && S_ISDIR(sb->st_mode))
Stephen Smalley826cc292014-01-28 15:04:22 -05001075 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1076
Stephen Smalleye183cec2014-02-05 16:41:47 -05001077 rc = 0;
1078
1079out:
1080 freecon(oldsecontext);
1081 freecon(secontext);
1082 return rc;
1083
1084err:
1085 selinux_log(SELINUX_ERROR,
1086 "SELinux: Could not set context for %s: %s\n",
1087 pathname, strerror(errno));
1088 rc = -1;
1089 goto out;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001090}
1091
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001092static int selinux_android_restorecon_common(const char* pathname,
1093 const char *seinfo,
1094 uid_t uid,
1095 unsigned int flags)
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001096{
Stephen Smalley08587cf2014-01-30 10:13:12 -05001097 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1098 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1099 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1100 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
Stephen Smalley027670d2014-02-18 11:04:37 -05001101 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
Stephen Smalley0e7340f2014-04-30 15:13:30 -07001102 bool issys = strcmp(pathname, "/sys") == 0 ? true : false;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001103 struct stat sb;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001104 FTS *fts;
1105 FTSENT *ftsent;
1106 char *const paths[2] = { __UNCONST(pathname), NULL };
1107 int ftsflags = FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
1108 int error, sverrno;
Stephen Smalley826cc292014-01-28 15:04:22 -05001109 char xattr_value[FC_DIGEST_SIZE];
1110 ssize_t size;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001111
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001112 if (is_selinux_enabled() <= 0)
1113 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001114
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001115 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001116
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001117 if (!sehandle)
1118 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001119
Stephen Smalley08587cf2014-01-30 10:13:12 -05001120 if (!recurse) {
1121 if (lstat(pathname, &sb) < 0)
1122 return -1;
1123
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001124 return restorecon_sb(pathname, &sb, false, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001125 }
1126
Stephen Smalley833cbd62014-02-27 13:08:40 -05001127 /*
1128 * Ignore restorecon_last on /data/data or /data/user
1129 * since their labeling is based on seapp_contexts and seinfo
1130 * assignments rather than file_contexts and is managed by
1131 * installd rather than init.
1132 */
1133 if (!strcmp(pathname, DATA_DATA_PATH) || !strcmp(pathname, DATA_USER_PATH))
1134 force = true;
1135
Stephen Smalley826cc292014-01-28 15:04:22 -05001136 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001137 if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
Stephen Smalley826cc292014-01-28 15:04:22 -05001138 selinux_log(SELINUX_INFO,
1139 "SELinux: Skipping restorecon_recursive(%s)\n",
1140 pathname);
1141 return 0;
1142 }
1143
Stephen Smalley08587cf2014-01-30 10:13:12 -05001144 fts = fts_open(paths, ftsflags, NULL);
1145 if (!fts)
1146 return -1;
1147
1148 error = 0;
1149 while ((ftsent = fts_read(fts)) != NULL) {
1150 switch (ftsent->fts_info) {
1151 case FTS_DC:
1152 selinux_log(SELINUX_ERROR,
1153 "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
1154 errno = ELOOP;
1155 error = -1;
1156 goto out;
1157 case FTS_DP:
1158 continue;
1159 case FTS_DNR:
1160 selinux_log(SELINUX_ERROR,
1161 "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1162 fts_set(fts, ftsent, FTS_SKIP);
1163 continue;
1164 case FTS_NS:
1165 selinux_log(SELINUX_ERROR,
1166 "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1167 fts_set(fts, ftsent, FTS_SKIP);
1168 continue;
1169 case FTS_ERR:
1170 selinux_log(SELINUX_ERROR,
1171 "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1172 fts_set(fts, ftsent, FTS_SKIP);
1173 continue;
Stephen Smalley027670d2014-02-18 11:04:37 -05001174 case FTS_D:
1175 if (!datadata &&
1176 (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
1177 !strcmp(ftsent->fts_path, DATA_USER_PATH))) {
1178 fts_set(fts, ftsent, FTS_SKIP);
1179 continue;
1180 }
Stephen Smalley0e7340f2014-04-30 15:13:30 -07001181 if (issys && !selabel_partial_match(sehandle, ftsent->fts_path)) {
1182 fts_set(fts, ftsent, FTS_SKIP);
1183 continue;
1184 }
Stephen Smalley027670d2014-02-18 11:04:37 -05001185 /* fall through */
Stephen Smalley08587cf2014-01-30 10:13:12 -05001186 default:
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001187 (void) restorecon_sb(ftsent->fts_path, ftsent->fts_statp, true, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001188 break;
1189 }
1190 }
1191
1192out:
1193 sverrno = errno;
1194 (void) fts_close(fts);
1195 error = sverrno;
1196 return error;
1197}
1198
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001199int selinux_android_restorecon(const char *file, unsigned int flags)
1200{
1201 return selinux_android_restorecon_common(file, NULL, -1, flags);
1202}
1203
1204int selinux_android_restorecon_pkgdir(const char *pkgdir,
1205 const char *seinfo,
1206 uid_t uid,
1207 unsigned int flags)
1208{
1209 return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1210}
1211
rpcraigf1724a32012-08-01 15:35:37 -04001212struct selabel_handle* selinux_android_file_context_handle(void)
1213{
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001214 return file_context_open();
1215}
1216
1217void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1218{
1219 sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -04001220}
rpcraig9b100832012-07-27 06:36:59 -04001221
rpcraigf1724a32012-08-01 15:35:37 -04001222int selinux_android_reload_policy(void)
1223{
Stephen Smalley4a655ec2012-09-18 15:08:32 -04001224 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -04001225 struct stat sb;
1226 void *map = NULL;
1227 int i = 0;
1228
Stephen Smalley4a655ec2012-09-18 15:08:32 -04001229 while (fd < 0 && sepolicy_file[i]) {
Nick Kralevich9c30ac62013-05-06 12:03:07 -07001230 fd = open(sepolicy_file[i], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -04001231 i++;
1232 }
1233 if (fd < 0) {
1234 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
1235 strerror(errno));
1236 return -1;
1237 }
1238 if (fstat(fd, &sb) < 0) {
1239 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -04001240 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001241 close(fd);
1242 return -1;
1243 }
1244 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1245 if (map == MAP_FAILED) {
1246 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Stephen Smalleycb925042013-07-26 10:45:44 -04001247 sepolicy_file[i-1], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001248 close(fd);
1249 return -1;
1250 }
1251
1252 rc = security_load_policy(map, sb.st_size);
1253 if (rc < 0) {
1254 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
1255 strerror(errno));
1256 munmap(map, sb.st_size);
1257 close(fd);
1258 return -1;
1259 }
1260
1261 munmap(map, sb.st_size);
1262 close(fd);
Stephen Smalleycb925042013-07-26 10:45:44 -04001263 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[i-1]);
rpcraigf1724a32012-08-01 15:35:37 -04001264
1265 return 0;
1266}
1267
1268int selinux_android_load_policy(void)
1269{
Nick Kralevich833cba62013-11-19 11:24:33 -08001270 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001271 int rc;
1272 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1273 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001274 if (errno == ENODEV) {
1275 /* SELinux not enabled in kernel */
1276 return -1;
1277 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001278 if (errno == ENOENT) {
1279 /* Fall back to legacy mountpoint. */
1280 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -08001281 rc = mkdir(mnt, 0755);
1282 if (rc == -1 && errno != EEXIST) {
1283 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
1284 strerror(errno));
1285 return -1;
1286 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001287 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1288 }
1289 }
1290 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001291 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
1292 strerror(errno));
1293 return -1;
1294 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001295 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -04001296
1297 return selinux_android_reload_policy();
rpcraig9b100832012-07-27 06:36:59 -04001298}