blob: 5206a9fe21df7d79311701b4217ea68374f5515a [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>
Elliott Hughes256ae122016-02-04 18:51:21 -080023#include <openssl/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"
Jeff Sharkey4766bfa2015-04-09 20:40:09 -070030#include <fnmatch.h>
dcashman06d45512015-06-12 14:38:54 -070031#include <limits.h>
William Robertsbe861662015-07-07 18:18:54 -070032#include <sys/vfs.h>
33#include <linux/magic.h>
Dan Cashman87ceb1e2015-09-10 09:42:15 -070034#include <libgen.h>
William Roberts6d5e6ed2015-07-31 13:05:47 -070035#include <packagelistparser/packagelistparser.h>
Stephen Smalleyf0740362012-01-04 12:30:47 -050036
Tom Cherry8b780782015-12-10 17:20:59 -080037#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
38#include <sys/_system_properties.h>
39
Stephen Smalleyf0740362012-01-04 12:30:47 -050040/*
41 * XXX Where should this configuration file be located?
42 * Needs to be accessible by zygote and installd when
43 * setting credentials for app processes and setting permissions
44 * on app data directories.
45 */
Stephen Smalley7446c912012-03-19 10:37:05 -040046static char const * const seapp_contexts_file[] = {
Stephen Smalley7446c912012-03-19 10:37:05 -040047 "/seapp_contexts",
Robert Craig5b5183f2014-03-17 20:53:06 -040048 "/data/security/current/seapp_contexts",
William Roberts8ed42422013-04-15 16:13:30 -070049 NULL };
Stephen Smalleyf0740362012-01-04 12:30:47 -050050
Stephen Smalley32ebfe82012-03-20 13:05:37 -040051static const struct selinux_opt seopts[] = {
Stephen Smalley25f659a2015-08-04 14:41:42 -040052 { SELABEL_OPT_PATH, "/file_contexts.bin" },
53 { SELABEL_OPT_PATH, "/data/security/current/file_contexts.bin" },
Stephen Smalley32ebfe82012-03-20 13:05:37 -040054 { 0, NULL } };
Stephen Smalley7446c912012-03-19 10:37:05 -040055
Stephen Smalley4a655ec2012-09-18 15:08:32 -040056static const char *const sepolicy_file[] = {
Robert Craig5b5183f2014-03-17 20:53:06 -040057 "/sepolicy",
58 "/data/security/current/sepolicy",
59 NULL };
rpcraigf1724a32012-08-01 15:35:37 -040060
dcashman965141a2014-12-03 12:51:50 -080061static const struct selinux_opt seopts_prop[] = {
62 { SELABEL_OPT_PATH, "/property_contexts" },
63 { SELABEL_OPT_PATH, "/data/security/current/property_contexts" },
64 { 0, NULL }
65};
66
Riley Spahnbad0ebb2014-06-11 16:07:53 -070067static const struct selinux_opt seopts_service[] = {
68 { SELABEL_OPT_PATH, "/service_contexts" },
69 { SELABEL_OPT_PATH, "/data/security/current/service_contexts" },
70 { 0, NULL }
71};
72
Stephen Smalleya8795982012-11-28 10:42:46 -050073enum levelFrom {
74 LEVELFROM_NONE,
75 LEVELFROM_APP,
76 LEVELFROM_USER,
77 LEVELFROM_ALL
78};
79
Robert Craig5b5183f2014-03-17 20:53:06 -040080#define POLICY_OVERRIDE_VERSION "/data/security/current/selinux_version"
81#define POLICY_BASE_VERSION "/selinux_version"
82static int policy_index = 0;
83
84static void set_policy_index(void)
85{
86 int fd_base = -1, fd_override = -1;
87 struct stat sb_base;
88 struct stat sb_override;
89 void *map_base, *map_override;
90
91 policy_index = 0;
92
93 fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW);
94 if (fd_base < 0)
95 return;
96
Stephen Smalley1e9d2762015-02-19 09:42:58 -050097 if (fstat(fd_base, &sb_base) < 0)
98 goto close_base;
Robert Craig5b5183f2014-03-17 20:53:06 -040099
100 fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500101 if (fd_override < 0)
102 goto close_base;
Robert Craig5b5183f2014-03-17 20:53:06 -0400103
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500104 if (fstat(fd_override, &sb_override) < 0)
105 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400106
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500107 if (sb_base.st_size != sb_override.st_size)
108 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400109
110 map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500111 if (map_base == MAP_FAILED)
112 goto close_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400113
114 map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500115 if (map_override == MAP_FAILED)
116 goto unmap_base;
Robert Craig5b5183f2014-03-17 20:53:06 -0400117
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500118 if (memcmp(map_base, map_override, sb_base.st_size) != 0)
119 goto unmap_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400120
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500121 if (access(sepolicy_file[1], R_OK) != 0)
122 goto unmap_override;
Robert Craig5b5183f2014-03-17 20:53:06 -0400123
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500124 if (access(seopts[1].value, R_OK) != 0)
125 goto unmap_override;
126
127 if (access(seopts_prop[1].value, R_OK) != 0)
128 goto unmap_override;
129
130 if (access(seopts_service[1].value, R_OK) != 0)
131 goto unmap_override;
132
133 if (access(seapp_contexts_file[1], R_OK) != 0)
134 goto unmap_override;
135
136 policy_index = 1;
137
138unmap_override:
Robert Craig5b5183f2014-03-17 20:53:06 -0400139 munmap(map_override, sb_override.st_size);
Stephen Smalley1e9d2762015-02-19 09:42:58 -0500140unmap_base:
141 munmap(map_base, sb_base.st_size);
142close_override:
143 close(fd_override);
144close_base:
145 close(fd_base);
146 return;
Robert Craig5b5183f2014-03-17 20:53:06 -0400147}
148
Stephen Smalleya8795982012-11-28 10:42:46 -0500149#if DEBUG
150static char const * const levelFromName[] = {
151 "none",
152 "app",
153 "user",
154 "all"
155};
156#endif
157
William Robertse3615f92013-09-11 20:35:53 -0700158struct prefix_str {
159 size_t len;
160 char *str;
161 char is_prefix;
162};
163
Stephen Smalley13319cf2014-04-04 15:44:23 -0400164static void free_prefix_str(struct prefix_str *p)
165{
166 if (!p)
167 return;
168 free(p->str);
169}
170
Stephen Smalleyf0740362012-01-04 12:30:47 -0500171struct seapp_context {
172 /* input selectors */
dcashmanab5e5fa2015-03-02 16:31:45 -0800173 bool isSystemServer;
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700174 bool isAutoPlayAppSet;
175 bool isAutoPlayApp;
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400176 bool isOwnerSet;
177 bool isOwner;
William Robertse3615f92013-09-11 20:35:53 -0700178 struct prefix_str user;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500179 char *seinfo;
William Robertse3615f92013-09-11 20:35:53 -0700180 struct prefix_str name;
Stephen Smalley274e0f62014-02-19 10:53:09 -0500181 struct prefix_str path;
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700182 bool isPrivAppSet;
183 bool isPrivApp;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500184 /* outputs */
185 char *domain;
186 char *type;
187 char *level;
Stephen Smalleya8795982012-11-28 10:42:46 -0500188 enum levelFrom levelFrom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500189};
190
Stephen Smalley13319cf2014-04-04 15:44:23 -0400191static void free_seapp_context(struct seapp_context *s)
192{
193 if (!s)
194 return;
195
196 free_prefix_str(&s->user);
197 free(s->seinfo);
198 free_prefix_str(&s->name);
199 free_prefix_str(&s->path);
200 free(s->domain);
201 free(s->type);
202 free(s->level);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400203}
204
Stephen Smalley76d51842015-02-13 15:29:46 -0500205static bool seapp_contexts_dup = false;
206
Stephen Smalleyf0740362012-01-04 12:30:47 -0500207static int seapp_context_cmp(const void *A, const void *B)
208{
Nick Kralevich833cba62013-11-19 11:24:33 -0800209 const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
210 const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500211 const struct seapp_context *s1 = *sp1, *s2 = *sp2;
Stephen Smalley76d51842015-02-13 15:29:46 -0500212 bool dup;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500213
214 /* Give precedence to isSystemServer=true. */
215 if (s1->isSystemServer != s2->isSystemServer)
216 return (s1->isSystemServer ? -1 : 1);
217
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700218 /* Give precedence to a specified isAutoPlayApp= over an
219 * unspecified isAutoPlayApp=. */
220 if (s1->isAutoPlayAppSet != s2->isAutoPlayAppSet)
221 return (s1->isAutoPlayAppSet ? -1 : 1);
222
223
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400224 /* Give precedence to a specified isOwner= over an unspecified isOwner=. */
225 if (s1->isOwnerSet != s2->isOwnerSet)
226 return (s1->isOwnerSet ? -1 : 1);
227
Stephen Smalleyf0740362012-01-04 12:30:47 -0500228 /* Give precedence to a specified user= over an unspecified user=. */
William Robertse3615f92013-09-11 20:35:53 -0700229 if (s1->user.str && !s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500230 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700231 if (!s1->user.str && s2->user.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500232 return 1;
233
William Robertse3615f92013-09-11 20:35:53 -0700234 if (s1->user.str) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500235 /* Give precedence to a fixed user= string over a prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700236 if (s1->user.is_prefix != s2->user.is_prefix)
237 return (s2->user.is_prefix ? -1 : 1);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500238
239 /* Give precedence to a longer prefix over a shorter prefix. */
William Robertse3615f92013-09-11 20:35:53 -0700240 if (s1->user.is_prefix && s1->user.len != s2->user.len)
241 return (s1->user.len > s2->user.len) ? -1 : 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500242 }
243
244 /* Give precedence to a specified seinfo= over an unspecified seinfo=. */
245 if (s1->seinfo && !s2->seinfo)
246 return -1;
247 if (!s1->seinfo && s2->seinfo)
248 return 1;
249
250 /* Give precedence to a specified name= over an unspecified name=. */
William Robertse3615f92013-09-11 20:35:53 -0700251 if (s1->name.str && !s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500252 return -1;
William Robertse3615f92013-09-11 20:35:53 -0700253 if (!s1->name.str && s2->name.str)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500254 return 1;
255
William Robertse3615f92013-09-11 20:35:53 -0700256 if (s1->name.str) {
257 /* Give precedence to a fixed name= string over a prefix. */
258 if (s1->name.is_prefix != s2->name.is_prefix)
259 return (s2->name.is_prefix ? -1 : 1);
260
261 /* Give precedence to a longer prefix over a shorter prefix. */
262 if (s1->name.is_prefix && s1->name.len != s2->name.len)
263 return (s1->name.len > s2->name.len) ? -1 : 1;
264 }
265
Stephen Smalley274e0f62014-02-19 10:53:09 -0500266 /* Give precedence to a specified path= over an unspecified path=. */
267 if (s1->path.str && !s2->path.str)
268 return -1;
269 if (!s1->path.str && s2->path.str)
270 return 1;
271
272 if (s1->path.str) {
273 /* Give precedence to a fixed path= string over a prefix. */
274 if (s1->path.is_prefix != s2->path.is_prefix)
275 return (s2->path.is_prefix ? -1 : 1);
276
277 /* Give precedence to a longer prefix over a shorter prefix. */
278 if (s1->path.is_prefix && s1->path.len != s2->path.len)
279 return (s1->path.len > s2->path.len) ? -1 : 1;
280 }
281
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700282 /* Give precedence to a specified isPrivApp= over an unspecified isPrivApp=. */
283 if (s1->isPrivAppSet != s2->isPrivAppSet)
284 return (s1->isPrivAppSet ? -1 : 1);
285
Stephen Smalley76d51842015-02-13 15:29:46 -0500286 /*
287 * Check for a duplicated entry on the input selectors.
288 * We already compared isSystemServer, isOwnerSet, and isOwner above.
289 * We also have already checked that both entries specify the same
290 * string fields, so if s1 has a non-NULL string, then so does s2.
291 */
292 dup = (!s1->user.str || !strcmp(s1->user.str, s2->user.str)) &&
293 (!s1->seinfo || !strcmp(s1->seinfo, s2->seinfo)) &&
294 (!s1->name.str || !strcmp(s1->name.str, s2->name.str)) &&
295 (!s1->path.str || !strcmp(s1->path.str, s2->path.str));
296 if (dup) {
297 seapp_contexts_dup = true;
298 selinux_log(SELINUX_ERROR, "seapp_contexts: Duplicated entry\n");
299 if (s1->user.str)
300 selinux_log(SELINUX_ERROR, " user=%s\n", s1->user.str);
301 if (s1->seinfo)
302 selinux_log(SELINUX_ERROR, " seinfo=%s\n", s1->seinfo);
303 if (s1->name.str)
304 selinux_log(SELINUX_ERROR, " name=%s\n", s1->name.str);
305 if (s1->path.str)
306 selinux_log(SELINUX_ERROR, " path=%s\n", s1->path.str);
307 }
308
Stephen Smalleyf0740362012-01-04 12:30:47 -0500309 /* Anything else has equal precedence. */
310 return 0;
311}
312
313static struct seapp_context **seapp_contexts = NULL;
314static int nspec = 0;
315
Stephen Smalley13319cf2014-04-04 15:44:23 -0400316static void free_seapp_contexts(void)
317{
318 int n;
319
320 if (!seapp_contexts)
321 return;
322
323 for (n = 0; n < nspec; n++)
324 free_seapp_context(seapp_contexts[n]);
325
326 free(seapp_contexts);
327 seapp_contexts = NULL;
328 nspec = 0;
329}
330
Stephen Smalley7446c912012-03-19 10:37:05 -0400331int selinux_android_seapp_context_reload(void)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500332{
Stephen Smalley7446c912012-03-19 10:37:05 -0400333 FILE *fp = NULL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500334 char line_buf[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500335 char *token;
336 unsigned lineno;
337 struct seapp_context *cur;
338 char *p, *name = NULL, *value = NULL, *saveptr;
339 size_t len;
Robert Craig5b5183f2014-03-17 20:53:06 -0400340 int n, ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500341
Robert Craig5b5183f2014-03-17 20:53:06 -0400342 set_policy_index();
Stephen Smalley7446c912012-03-19 10:37:05 -0400343
Robert Craig5b5183f2014-03-17 20:53:06 -0400344 fp = fopen(seapp_contexts_file[policy_index], "r");
Stephen Smalleyf0740362012-01-04 12:30:47 -0500345 if (!fp) {
Stephen Smalley7446c912012-03-19 10:37:05 -0400346 selinux_log(SELINUX_ERROR, "%s: could not open any seapp_contexts file", __FUNCTION__);
347 return -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500348 }
349
Stephen Smalley13319cf2014-04-04 15:44:23 -0400350 free_seapp_contexts();
Stephen Smalley300bebb2013-04-16 15:33:16 -0400351
Stephen Smalleyf0740362012-01-04 12:30:47 -0500352 nspec = 0;
353 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
354 p = line_buf;
355 while (isspace(*p))
356 p++;
357 if (*p == '#' || *p == 0)
358 continue;
359 nspec++;
360 }
361
Nick Kralevich833cba62013-11-19 11:24:33 -0800362 seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500363 if (!seapp_contexts)
364 goto oom;
365
366 rewind(fp);
367 nspec = 0;
368 lineno = 1;
369 while (fgets(line_buf, sizeof line_buf - 1, fp)) {
370 len = strlen(line_buf);
371 if (line_buf[len - 1] == '\n')
372 line_buf[len - 1] = 0;
373 p = line_buf;
374 while (isspace(*p))
375 p++;
376 if (*p == '#' || *p == 0)
377 continue;
378
Nick Kralevich833cba62013-11-19 11:24:33 -0800379 cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500380 if (!cur)
381 goto oom;
382
383 token = strtok_r(p, " \t", &saveptr);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400384 if (!token) {
385 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500386 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400387 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500388
389 while (1) {
390 name = token;
391 value = strchr(name, '=');
Stephen Smalley13319cf2014-04-04 15:44:23 -0400392 if (!value) {
393 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500394 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400395 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500396 *value++ = 0;
397
398 if (!strcasecmp(name, "isSystemServer")) {
399 if (!strcasecmp(value, "true"))
dcashmanab5e5fa2015-03-02 16:31:45 -0800400 cur->isSystemServer = true;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500401 else if (!strcasecmp(value, "false"))
dcashmanab5e5fa2015-03-02 16:31:45 -0800402 cur->isSystemServer = false;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500403 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400404 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500405 goto err;
406 }
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700407 } else if (!strcasecmp(name, "isAutoPlayApp")) {
408 cur->isAutoPlayAppSet = true;
409 if (!strcasecmp(value, "true"))
410 cur->isAutoPlayApp = true;
411 else if (!strcasecmp(value, "false"))
412 cur->isAutoPlayApp = false;
413 else {
414 free_seapp_context(cur);
415 goto err;
416 }
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400417 } else if (!strcasecmp(name, "isOwner")) {
418 cur->isOwnerSet = true;
419 if (!strcasecmp(value, "true"))
420 cur->isOwner = true;
421 else if (!strcasecmp(value, "false"))
422 cur->isOwner = false;
423 else {
424 free_seapp_context(cur);
425 goto err;
426 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500427 } else if (!strcasecmp(name, "user")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500428 if (cur->user.str) {
429 free_seapp_context(cur);
430 goto err;
431 }
William Robertse3615f92013-09-11 20:35:53 -0700432 cur->user.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400433 if (!cur->user.str) {
434 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500435 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400436 }
William Robertse3615f92013-09-11 20:35:53 -0700437 cur->user.len = strlen(cur->user.str);
438 if (cur->user.str[cur->user.len-1] == '*')
439 cur->user.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500440 } else if (!strcasecmp(name, "seinfo")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500441 if (cur->seinfo) {
442 free_seapp_context(cur);
443 goto err;
444 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500445 cur->seinfo = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400446 if (!cur->seinfo) {
447 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500448 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400449 }
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700450 if (strstr(value, ":")) {
451 free_seapp_context(cur);
452 goto err;
453 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500454 } else if (!strcasecmp(name, "name")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500455 if (cur->name.str) {
456 free_seapp_context(cur);
457 goto err;
458 }
William Robertse3615f92013-09-11 20:35:53 -0700459 cur->name.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400460 if (!cur->name.str) {
461 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500462 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400463 }
William Robertse3615f92013-09-11 20:35:53 -0700464 cur->name.len = strlen(cur->name.str);
465 if (cur->name.str[cur->name.len-1] == '*')
466 cur->name.is_prefix = 1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500467 } else if (!strcasecmp(name, "domain")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500468 if (cur->domain) {
469 free_seapp_context(cur);
470 goto err;
471 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500472 cur->domain = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400473 if (!cur->domain) {
474 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500475 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400476 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500477 } else if (!strcasecmp(name, "type")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500478 if (cur->type) {
479 free_seapp_context(cur);
480 goto err;
481 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500482 cur->type = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400483 if (!cur->type) {
484 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500485 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400486 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500487 } else if (!strcasecmp(name, "levelFromUid")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500488 if (cur->levelFrom) {
489 free_seapp_context(cur);
490 goto err;
491 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500492 if (!strcasecmp(value, "true"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500493 cur->levelFrom = LEVELFROM_APP;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500494 else if (!strcasecmp(value, "false"))
Stephen Smalleya8795982012-11-28 10:42:46 -0500495 cur->levelFrom = LEVELFROM_NONE;
496 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400497 free_seapp_context(cur);
Stephen Smalleya8795982012-11-28 10:42:46 -0500498 goto err;
499 }
500 } else if (!strcasecmp(name, "levelFrom")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500501 if (cur->levelFrom) {
502 free_seapp_context(cur);
503 goto err;
504 }
Stephen Smalleya8795982012-11-28 10:42:46 -0500505 if (!strcasecmp(value, "none"))
506 cur->levelFrom = LEVELFROM_NONE;
507 else if (!strcasecmp(value, "app"))
508 cur->levelFrom = LEVELFROM_APP;
509 else if (!strcasecmp(value, "user"))
510 cur->levelFrom = LEVELFROM_USER;
511 else if (!strcasecmp(value, "all"))
512 cur->levelFrom = LEVELFROM_ALL;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500513 else {
Stephen Smalley13319cf2014-04-04 15:44:23 -0400514 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500515 goto err;
516 }
517 } else if (!strcasecmp(name, "level")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500518 if (cur->level) {
519 free_seapp_context(cur);
520 goto err;
521 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500522 cur->level = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400523 if (!cur->level) {
524 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500525 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400526 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500527 } else if (!strcasecmp(name, "path")) {
Stephen Smalley0f912a12015-02-13 14:08:57 -0500528 if (cur->path.str) {
529 free_seapp_context(cur);
530 goto err;
531 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500532 cur->path.str = strdup(value);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400533 if (!cur->path.str) {
534 free_seapp_context(cur);
Stephen Smalley274e0f62014-02-19 10:53:09 -0500535 goto oom;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400536 }
Stephen Smalley274e0f62014-02-19 10:53:09 -0500537 cur->path.len = strlen(cur->path.str);
538 if (cur->path.str[cur->path.len-1] == '*')
539 cur->path.is_prefix = 1;
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700540 } else if (!strcasecmp(name, "isPrivApp")) {
541 cur->isPrivAppSet = true;
542 if (!strcasecmp(value, "true"))
543 cur->isPrivApp = true;
544 else if (!strcasecmp(value, "false"))
545 cur->isPrivApp = false;
546 else {
547 free_seapp_context(cur);
548 goto err;
549 }
Stephen Smalley13319cf2014-04-04 15:44:23 -0400550 } else {
551 free_seapp_context(cur);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500552 goto err;
Stephen Smalley13319cf2014-04-04 15:44:23 -0400553 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500554
555 token = strtok_r(NULL, " \t", &saveptr);
556 if (!token)
557 break;
558 }
559
Stephen Smalley13319cf2014-04-04 15:44:23 -0400560 if (cur->name.str &&
561 (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
562 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 -0400563 seapp_contexts_file[policy_index], cur->name.str, lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400564 free_seapp_context(cur);
565 goto err;
566 }
567
Stephen Smalleyf0740362012-01-04 12:30:47 -0500568 seapp_contexts[nspec] = cur;
569 nspec++;
570 lineno++;
571 }
572
573 qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
574 seapp_context_cmp);
575
Stephen Smalley76d51842015-02-13 15:29:46 -0500576 if (seapp_contexts_dup)
577 goto err;
578
Stephen Smalleyf0740362012-01-04 12:30:47 -0500579#if DEBUG
580 {
581 int i;
582 for (i = 0; i < nspec; i++) {
583 cur = seapp_contexts[i];
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700584 selinux_log(SELINUX_INFO, "%s: isSystemServer=%s isAutoPlayApp=%s isOwner=%s user=%s seinfo=%s "
585 "name=%s path=%s isPrivApp=%s -> domain=%s type=%s level=%s levelFrom=%s",
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700586 __FUNCTION__,
587 cur->isSystemServer ? "true" : "false",
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700588 cur->isAutoPlayAppSet ? (cur->isAutoPlayApp ? "true" : "false") : "null",
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700589 cur->isOwnerSet ? (cur->isOwner ? "true" : "false") : "null",
590 cur->user.str,
591 cur->seinfo, cur->name.str, cur->path.str,
592 cur->isPrivAppSet ? (cur->isPrivApp ? "true" : "false") : "null",
593 cur->domain, cur->type, cur->level,
594 levelFromName[cur->levelFrom]);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500595 }
596 }
597#endif
598
Stephen Smalley7446c912012-03-19 10:37:05 -0400599 ret = 0;
600
Stephen Smalleyf0740362012-01-04 12:30:47 -0500601out:
602 fclose(fp);
Stephen Smalley7446c912012-03-19 10:37:05 -0400603 return ret;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500604
605err:
Stephen Smalley13319cf2014-04-04 15:44:23 -0400606 selinux_log(SELINUX_ERROR, "%s: Invalid entry on line %u\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400607 seapp_contexts_file[policy_index], lineno);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400608 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400609 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500610 goto out;
611oom:
612 selinux_log(SELINUX_ERROR,
613 "%s: Out of memory\n", __FUNCTION__);
Stephen Smalley13319cf2014-04-04 15:44:23 -0400614 free_seapp_contexts();
Stephen Smalley7446c912012-03-19 10:37:05 -0400615 ret = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500616 goto out;
617}
618
Stephen Smalley7446c912012-03-19 10:37:05 -0400619
620static void seapp_context_init(void)
621{
622 selinux_android_seapp_context_reload();
623}
624
Stephen Smalleyf0740362012-01-04 12:30:47 -0500625static pthread_once_t once = PTHREAD_ONCE_INIT;
626
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400627/*
Stephen Smalleya8795982012-11-28 10:42:46 -0500628 * Max id that can be mapped to category set uniquely
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400629 * using the current scheme.
630 */
Stephen Smalleya8795982012-11-28 10:42:46 -0500631#define CAT_MAPPING_MAX_ID (0x1<<16)
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400632
633enum seapp_kind {
634 SEAPP_TYPE,
635 SEAPP_DOMAIN
636};
637
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700638#define PRIVILEGED_APP_STR ":privapp"
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700639#define AUTOPLAY_APP_STR ":autoplayapp"
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700640
641static int seinfo_parse(char *dest, const char *src, size_t size)
642{
643 size_t len;
644 char *p;
645
646 if ((p = strchr(src, ':')) != NULL)
647 len = p - src;
648 else
649 len = strlen(src);
650
651 if (len > size - 1)
652 return -1;
653
654 strncpy(dest, src, len);
655 dest[len] = '\0';
656
657 return 0;
658}
659
Stephen Smalleyd23b9e02012-09-21 10:45:39 -0400660static int seapp_context_lookup(enum seapp_kind kind,
Stephen Smalley895b4462012-09-19 16:27:36 -0400661 uid_t uid,
dcashmanab5e5fa2015-03-02 16:31:45 -0800662 bool isSystemServer,
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400663 const char *seinfo,
Stephen Smalley895b4462012-09-19 16:27:36 -0400664 const char *pkgname,
Stephen Smalley274e0f62014-02-19 10:53:09 -0500665 const char *path,
Stephen Smalley895b4462012-09-19 16:27:36 -0400666 context_t ctx)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500667{
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400668 bool isOwner;
Stephen Smalley895b4462012-09-19 16:27:36 -0400669 const char *username = NULL;
Nick Kralevichb1ae15a2013-07-11 17:35:53 -0700670 struct seapp_context *cur = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400671 int i;
672 size_t n;
Stephen Smalleya8795982012-11-28 10:42:46 -0500673 uid_t userid;
674 uid_t appid;
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700675 bool isPrivApp = false;
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700676 bool isAutoPlayApp = false;
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700677 char parsedseinfo[BUFSIZ];
Stephen Smalleyf0740362012-01-04 12:30:47 -0500678
Stephen Smalleye183cec2014-02-05 16:41:47 -0500679 __selinux_once(once, seapp_context_init);
680
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700681 if (seinfo) {
682 if (seinfo_parse(parsedseinfo, seinfo, BUFSIZ))
683 goto err;
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700684 isPrivApp = strstr(seinfo, PRIVILEGED_APP_STR) ? true : false;
685 isAutoPlayApp = strstr(seinfo, AUTOPLAY_APP_STR) ? true : false;
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700686 seinfo = parsedseinfo;
687 }
688
Stephen Smalleya8795982012-11-28 10:42:46 -0500689 userid = uid / AID_USER;
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400690 isOwner = (userid == 0);
Stephen Smalley895b4462012-09-19 16:27:36 -0400691 appid = uid % AID_USER;
692 if (appid < AID_APP) {
693 for (n = 0; n < android_id_count; n++) {
694 if (android_ids[n].aid == appid) {
695 username = android_ids[n].name;
696 break;
697 }
Stephen Smalleyce4e2e62012-08-23 12:20:42 -0400698 }
Stephen Smalley895b4462012-09-19 16:27:36 -0400699 if (!username)
700 goto err;
701 } else if (appid < AID_ISOLATED_START) {
Stephen Smalley525a2242012-09-24 10:22:45 -0400702 username = "_app";
Stephen Smalley895b4462012-09-19 16:27:36 -0400703 appid -= AID_APP;
704 } else {
Stephen Smalley525a2242012-09-24 10:22:45 -0400705 username = "_isolated";
Stephen Smalley895b4462012-09-19 16:27:36 -0400706 appid -= AID_ISOLATED_START;
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400707 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500708
Stephen Smalleya8795982012-11-28 10:42:46 -0500709 if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
Stephen Smalley895b4462012-09-19 16:27:36 -0400710 goto err;
711
Stephen Smalleyf0740362012-01-04 12:30:47 -0500712 for (i = 0; i < nspec; i++) {
713 cur = seapp_contexts[i];
714
Stephen Smalley895b4462012-09-19 16:27:36 -0400715 if (cur->isSystemServer != isSystemServer)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500716 continue;
717
Jeff Vander Stoep6f612a02015-10-30 13:08:08 -0700718 if (cur->isAutoPlayAppSet && cur->isAutoPlayApp != isAutoPlayApp)
719 continue;
720
Stephen Smalleyf76c30b2014-09-15 15:06:46 -0400721 if (cur->isOwnerSet && cur->isOwner != isOwner)
722 continue;
723
William Robertse3615f92013-09-11 20:35:53 -0700724 if (cur->user.str) {
725 if (cur->user.is_prefix) {
726 if (strncasecmp(username, cur->user.str, cur->user.len-1))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500727 continue;
728 } else {
William Robertse3615f92013-09-11 20:35:53 -0700729 if (strcasecmp(username, cur->user.str))
Stephen Smalleyf0740362012-01-04 12:30:47 -0500730 continue;
731 }
732 }
733
Stephen Smalleyedfaad82012-07-12 11:30:24 -0400734 if (cur->seinfo) {
735 if (!seinfo || strcasecmp(seinfo, cur->seinfo))
736 continue;
737 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500738
William Robertse3615f92013-09-11 20:35:53 -0700739 if (cur->name.str) {
740 if(!pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500741 continue;
William Robertse3615f92013-09-11 20:35:53 -0700742
743 if (cur->name.is_prefix) {
744 if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
745 continue;
746 } else {
747 if (strcasecmp(pkgname, cur->name.str))
748 continue;
749 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500750 }
751
Jeff Vander Stoep2857a7e2015-10-12 08:37:00 -0700752 if (cur->isPrivAppSet && cur->isPrivApp != isPrivApp)
753 continue;
754
Stephen Smalley274e0f62014-02-19 10:53:09 -0500755 if (cur->path.str) {
756 if (!path)
757 continue;
758
759 if (cur->path.is_prefix) {
760 if (strncmp(path, cur->path.str, cur->path.len-1))
761 continue;
762 } else {
763 if (strcmp(path, cur->path.str))
764 continue;
765 }
766 }
767
Stephen Smalley895b4462012-09-19 16:27:36 -0400768 if (kind == SEAPP_TYPE && !cur->type)
769 continue;
770 else if (kind == SEAPP_DOMAIN && !cur->domain)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500771 continue;
772
Stephen Smalley895b4462012-09-19 16:27:36 -0400773 if (kind == SEAPP_TYPE) {
774 if (context_type_set(ctx, cur->type))
775 goto oom;
776 } else if (kind == SEAPP_DOMAIN) {
777 if (context_type_set(ctx, cur->domain))
778 goto oom;
779 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500780
Stephen Smalleya8795982012-11-28 10:42:46 -0500781 if (cur->levelFrom != LEVELFROM_NONE) {
Stephen Smalleyf0740362012-01-04 12:30:47 -0500782 char level[255];
Stephen Smalleya8795982012-11-28 10:42:46 -0500783 switch (cur->levelFrom) {
784 case LEVELFROM_APP:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500785 snprintf(level, sizeof level, "s0:c%u,c%u",
786 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500787 256 + (appid>>8 & 0xff));
788 break;
789 case LEVELFROM_USER:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500790 snprintf(level, sizeof level, "s0:c%u,c%u",
Stephen Smalleya8795982012-11-28 10:42:46 -0500791 512 + (userid & 0xff),
792 768 + (userid>>8 & 0xff));
793 break;
794 case LEVELFROM_ALL:
Stephen Smalleydf1ece22013-12-02 10:07:48 -0500795 snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
796 appid & 0xff,
Stephen Smalleya8795982012-11-28 10:42:46 -0500797 256 + (appid>>8 & 0xff),
798 512 + (userid & 0xff),
799 768 + (userid>>8 & 0xff));
800 break;
801 default:
802 goto err;
803 }
Stephen Smalleyf0740362012-01-04 12:30:47 -0500804 if (context_range_set(ctx, level))
805 goto oom;
806 } else if (cur->level) {
807 if (context_range_set(ctx, cur->level))
808 goto oom;
809 }
William Roberts1b36ad02012-07-27 13:52:33 -0700810
Stephen Smalleyf0740362012-01-04 12:30:47 -0500811 break;
812 }
813
Stephen Smalley895b4462012-09-19 16:27:36 -0400814 if (kind == SEAPP_DOMAIN && i == nspec) {
815 /*
816 * No match.
817 * Fail to prevent staying in the zygote's context.
818 */
819 selinux_log(SELINUX_ERROR,
820 "%s: No match for app with uid %d, seinfo %s, name %s\n",
821 __FUNCTION__, uid, seinfo, pkgname);
822
823 if (security_getenforce() == 1)
824 goto err;
825 }
826
827 return 0;
828err:
829 return -1;
830oom:
831 return -2;
832}
833
Stephen Smalley1b478ea2014-02-07 09:32:41 -0500834int selinux_android_setfilecon(const char *pkgdir,
Stephen Smalley895b4462012-09-19 16:27:36 -0400835 const char *pkgname,
836 const char *seinfo,
837 uid_t uid)
838{
Nick Kralevich9ca40882013-07-11 16:58:44 -0700839 char *orig_ctx_str = NULL;
840 char *ctx_str = NULL;
Stephen Smalley895b4462012-09-19 16:27:36 -0400841 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700842 int rc = -1;
Stephen Smalley895b4462012-09-19 16:27:36 -0400843
844 if (is_selinux_enabled() <= 0)
845 return 0;
846
Stephen Smalley895b4462012-09-19 16:27:36 -0400847 rc = getfilecon(pkgdir, &ctx_str);
848 if (rc < 0)
849 goto err;
850
851 ctx = context_new(ctx_str);
852 orig_ctx_str = ctx_str;
853 if (!ctx)
854 goto oom;
855
Stephen Smalley274e0f62014-02-19 10:53:09 -0500856 rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400857 if (rc == -1)
858 goto err;
859 else if (rc == -2)
860 goto oom;
861
Stephen Smalleyf0740362012-01-04 12:30:47 -0500862 ctx_str = context_str(ctx);
863 if (!ctx_str)
864 goto oom;
865
866 rc = security_check_context(ctx_str);
867 if (rc < 0)
868 goto err;
869
870 if (strcmp(ctx_str, orig_ctx_str)) {
871 rc = setfilecon(pkgdir, ctx_str);
872 if (rc < 0)
873 goto err;
874 }
875
876 rc = 0;
877out:
878 freecon(orig_ctx_str);
879 context_free(ctx);
880 return rc;
881err:
882 selinux_log(SELINUX_ERROR, "%s: Error setting context for pkgdir %s, uid %d: %s\n",
883 __FUNCTION__, pkgdir, uid, strerror(errno));
884 rc = -1;
885 goto out;
886oom:
887 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
888 rc = -1;
889 goto out;
890}
891
Tom Cherry8b780782015-12-10 17:20:59 -0800892int selinux_android_setcon(const char *con)
893{
894 int ret = setcon(con);
895 if (ret)
896 return ret;
897 /*
898 System properties must be reinitialized after setcon() otherwise the
899 previous property files will be leaked since mmap()'ed regions are not
900 closed as a result of setcon().
901 */
902 return __system_properties_init();
903}
904
Stephen Smalleyf0740362012-01-04 12:30:47 -0500905int selinux_android_setcontext(uid_t uid,
dcashmanab5e5fa2015-03-02 16:31:45 -0800906 bool isSystemServer,
Stephen Smalleyf0740362012-01-04 12:30:47 -0500907 const char *seinfo,
Stephen Smalleyba70ee42012-07-10 15:49:04 -0400908 const char *pkgname)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500909{
Stephen Smalley895b4462012-09-19 16:27:36 -0400910 char *orig_ctx_str = NULL, *ctx_str;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500911 context_t ctx = NULL;
Nick Kralevich9ca40882013-07-11 16:58:44 -0700912 int rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500913
914 if (is_selinux_enabled() <= 0)
915 return 0;
916
Stephen Smalleyf0740362012-01-04 12:30:47 -0500917 rc = getcon(&ctx_str);
918 if (rc)
919 goto err;
920
921 ctx = context_new(ctx_str);
922 orig_ctx_str = ctx_str;
923 if (!ctx)
924 goto oom;
925
Stephen Smalley274e0f62014-02-19 10:53:09 -0500926 rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
Stephen Smalley895b4462012-09-19 16:27:36 -0400927 if (rc == -1)
Stephen Smalleyf0740362012-01-04 12:30:47 -0500928 goto err;
Stephen Smalley895b4462012-09-19 16:27:36 -0400929 else if (rc == -2)
930 goto oom;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500931
932 ctx_str = context_str(ctx);
933 if (!ctx_str)
934 goto oom;
935
936 rc = security_check_context(ctx_str);
937 if (rc < 0)
938 goto err;
939
940 if (strcmp(ctx_str, orig_ctx_str)) {
Tom Cherry8b780782015-12-10 17:20:59 -0800941 rc = selinux_android_setcon(ctx_str);
Stephen Smalleyf0740362012-01-04 12:30:47 -0500942 if (rc < 0)
943 goto err;
944 }
945
946 rc = 0;
947out:
948 freecon(orig_ctx_str);
949 context_free(ctx);
Stephen Smalleye8b0fd82012-07-31 09:12:53 -0400950 avc_netlink_close();
Stephen Smalleyf0740362012-01-04 12:30:47 -0500951 return rc;
952err:
953 if (isSystemServer)
954 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700955 "%s: Error setting context for system server: %s\n",
956 __FUNCTION__, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500957 else
958 selinux_log(SELINUX_ERROR,
Geremy Condra60646432013-04-10 17:58:48 -0700959 "%s: Error setting context for app with uid %d, seinfo %s: %s\n",
960 __FUNCTION__, uid, seinfo, strerror(errno));
Stephen Smalleyf0740362012-01-04 12:30:47 -0500961
Stephen Smalleyf77e60d2012-07-27 15:41:10 -0400962 rc = -1;
Stephen Smalleyf0740362012-01-04 12:30:47 -0500963 goto out;
964oom:
965 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
966 rc = -1;
967 goto out;
968}
969
dcashman965141a2014-12-03 12:51:50 -0800970static struct selabel_handle *fc_sehandle = NULL;
Elliott Hughes256ae122016-02-04 18:51:21 -0800971#define FC_DIGEST_SIZE SHA_DIGEST_LENGTH
Stephen Smalley826cc292014-01-28 15:04:22 -0500972static uint8_t fc_digest[FC_DIGEST_SIZE];
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400973
dcashman965141a2014-12-03 12:51:50 -0800974static bool compute_contexts_hash(const struct selinux_opt opts[], uint8_t c_digest[])
Stephen Smalley826cc292014-01-28 15:04:22 -0500975{
Stephen Smalley826cc292014-01-28 15:04:22 -0500976 int fd;
977 struct stat sb;
978 void *map;
Stephen Smalley0ca91b32012-03-19 10:25:53 -0400979
dcashman965141a2014-12-03 12:51:50 -0800980 fd = open(opts[policy_index].value, O_CLOEXEC | O_RDONLY | O_NOFOLLOW);
Stephen Smalley826cc292014-01-28 15:04:22 -0500981 if (fd < 0) {
982 selinux_log(SELINUX_ERROR, "SELinux: Could not open %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400983 opts[policy_index].value, strerror(errno));
dcashman965141a2014-12-03 12:51:50 -0800984 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500985 }
986 if (fstat(fd, &sb) < 0) {
987 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400988 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500989 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800990 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500991 }
992 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
993 if (map == MAP_FAILED) {
994 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -0400995 opts[policy_index].value, strerror(errno));
Stephen Smalley826cc292014-01-28 15:04:22 -0500996 close(fd);
dcashman965141a2014-12-03 12:51:50 -0800997 return false;
Stephen Smalley826cc292014-01-28 15:04:22 -0500998 }
Elliott Hughes256ae122016-02-04 18:51:21 -0800999 SHA1(map, sb.st_size, c_digest);
Stephen Smalley826cc292014-01-28 15:04:22 -05001000 munmap(map, sb.st_size);
1001 close(fd);
1002
dcashman965141a2014-12-03 12:51:50 -08001003 return true;
Geremy Condra60646432013-04-10 17:58:48 -07001004}
1005
Stephen Smalley906742d2012-08-23 16:04:59 -04001006static void file_context_init(void)
1007{
dcashman965141a2014-12-03 12:51:50 -08001008 if (!fc_sehandle)
1009 fc_sehandle = selinux_android_file_context_handle();
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001010}
1011
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001012
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001013
Stephen Smalley08587cf2014-01-30 10:13:12 -05001014static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
1015
Stephen Smalleye183cec2014-02-05 16:41:47 -05001016#define PKGTAB_SIZE 256
William Roberts6d5e6ed2015-07-31 13:05:47 -07001017static struct pkg_info *pkgTab[PKGTAB_SIZE];
Stephen Smalleye183cec2014-02-05 16:41:47 -05001018
1019static unsigned int pkghash(const char *pkgname)
1020{
1021 unsigned int h = 7;
1022 for (; *pkgname; pkgname++) {
1023 h = h * 31 + *pkgname;
1024 }
1025 return h & (PKGTAB_SIZE - 1);
1026}
1027
William Roberts6d5e6ed2015-07-31 13:05:47 -07001028static bool pkg_parse_callback(pkg_info *info, void *userdata) {
1029
1030 (void) userdata;
1031
1032 unsigned int hash = pkghash(info->name);
1033 if (pkgTab[hash])
1034 info->private_data = pkgTab[hash];
1035 pkgTab[hash] = info;
1036 return true;
1037}
Stephen Smalleye183cec2014-02-05 16:41:47 -05001038
1039static void package_info_init(void)
1040{
Stephen Smalleye183cec2014-02-05 16:41:47 -05001041
William Roberts6d5e6ed2015-07-31 13:05:47 -07001042 bool rc = packagelist_parse(pkg_parse_callback, NULL);
1043 if (!rc) {
1044 selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n");
Stephen Smalleye183cec2014-02-05 16:41:47 -05001045 return;
1046 }
Stephen Smalleye183cec2014-02-05 16:41:47 -05001047
1048#if DEBUG
1049 {
William Roberts6d5e6ed2015-07-31 13:05:47 -07001050 unsigned int hash, buckets, entries, chainlen, longestchain;
1051 struct pkg_info *info = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001052
1053 buckets = entries = longestchain = 0;
1054 for (hash = 0; hash < PKGTAB_SIZE; hash++) {
1055 if (pkgTab[hash]) {
1056 buckets++;
1057 chainlen = 0;
William Roberts6d5e6ed2015-07-31 13:05:47 -07001058 for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
Stephen Smalleye183cec2014-02-05 16:41:47 -05001059 chainlen++;
1060 selinux_log(SELINUX_INFO, "%s: name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
1061 __FUNCTION__,
William Roberts6d5e6ed2015-07-31 13:05:47 -07001062 info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo);
Stephen Smalleye183cec2014-02-05 16:41:47 -05001063 }
1064 entries += chainlen;
1065 if (longestchain < chainlen)
1066 longestchain = chainlen;
1067 }
1068 }
1069 selinux_log(SELINUX_INFO, "SELinux: %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
1070 }
1071#endif
1072
Stephen Smalleye183cec2014-02-05 16:41:47 -05001073}
1074
1075static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
1076
William Roberts6d5e6ed2015-07-31 13:05:47 -07001077struct pkg_info *package_info_lookup(const char *name)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001078{
William Roberts6d5e6ed2015-07-31 13:05:47 -07001079 struct pkg_info *info;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001080 unsigned int hash;
1081
1082 __selinux_once(pkg_once, package_info_init);
1083
1084 hash = pkghash(name);
William Roberts6d5e6ed2015-07-31 13:05:47 -07001085 for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
1086 if (!strcmp(name, info->name))
1087 return info;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001088 }
1089 return NULL;
1090}
1091
Jeff Sharkey9d7eba12016-07-15 16:21:06 -06001092/* The contents of these paths are encrypted on FBE devices until user
1093 * credentials are presented (filenames inside are mangled), so we need
1094 * to delay restorecon of those until vold explicitly requests it. */
1095// NOTE: these paths need to be kept in sync with vold
1096#define DATA_SYSTEM_CE_PREFIX "/data/system_ce/"
1097#define DATA_MISC_CE_PREFIX "/data/misc_ce/"
1098
Stephen Smalleye183cec2014-02-05 16:41:47 -05001099/* The path prefixes of package data directories. */
Stephen Smalley027670d2014-02-18 11:04:37 -05001100#define DATA_DATA_PATH "/data/data"
1101#define DATA_USER_PATH "/data/user"
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001102#define DATA_USER_DE_PATH "/data/user_de"
Nick Kralevichd601f822015-04-13 18:09:33 -07001103#define EXPAND_USER_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user"
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001104#define EXPAND_USER_DE_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?/user_de"
Stephen Smalley027670d2014-02-18 11:04:37 -05001105#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
1106#define DATA_USER_PREFIX DATA_USER_PATH "/"
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001107#define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
Stephen Smalleye183cec2014-02-05 16:41:47 -05001108
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001109static int pkgdir_selabel_lookup(const char *pathname,
1110 const char *seinfo,
1111 uid_t uid,
1112 char **secontextp)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001113{
1114 char *pkgname = NULL, *end = NULL;
William Roberts6d5e6ed2015-07-31 13:05:47 -07001115 struct pkg_info *info = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001116 char *secontext = *secontextp;
1117 context_t ctx = NULL;
1118 int rc = 0;
1119
1120 /* Skip directory prefix before package name. */
1121 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
1122 pathname += sizeof(DATA_DATA_PREFIX) - 1;
1123 } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
1124 pathname += sizeof(DATA_USER_PREFIX) - 1;
1125 while (isdigit(*pathname))
1126 pathname++;
1127 if (*pathname == '/')
1128 pathname++;
1129 else
1130 return 0;
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001131 } else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) {
1132 pathname += sizeof(DATA_USER_DE_PREFIX) - 1;
1133 while (isdigit(*pathname))
1134 pathname++;
1135 if (*pathname == '/')
1136 pathname++;
1137 else
1138 return 0;
Jeff Sharkey4766bfa2015-04-09 20:40:09 -07001139 } else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
1140 pathname += sizeof(EXPAND_USER_PATH);
1141 while (isdigit(*pathname))
1142 pathname++;
1143 if (*pathname == '/')
1144 pathname++;
1145 else
1146 return 0;
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001147 } else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
1148 pathname += sizeof(EXPAND_USER_DE_PATH);
1149 while (isdigit(*pathname))
1150 pathname++;
1151 if (*pathname == '/')
1152 pathname++;
1153 else
1154 return 0;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001155 } else
1156 return 0;
1157
1158 if (!(*pathname))
1159 return 0;
1160
1161 pkgname = strdup(pathname);
1162 if (!pkgname)
1163 return -1;
1164
1165 for (end = pkgname; *end && *end != '/'; end++)
1166 ;
Stephen Smalley274e0f62014-02-19 10:53:09 -05001167 pathname = end;
1168 if (*end)
1169 pathname++;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001170 *end = '\0';
1171
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001172 if (!seinfo) {
William Roberts6d5e6ed2015-07-31 13:05:47 -07001173 info = package_info_lookup(pkgname);
1174 if (!info) {
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001175 selinux_log(SELINUX_WARNING, "SELinux: Could not look up information for package %s, cannot restorecon %s.\n",
1176 pkgname, pathname);
1177 free(pkgname);
1178 return -1;
1179 }
Stephen Smalleye183cec2014-02-05 16:41:47 -05001180 }
1181
1182 ctx = context_new(secontext);
1183 if (!ctx)
1184 goto err;
1185
William Roberts6d5e6ed2015-07-31 13:05:47 -07001186 rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0,
1187 info ? info->seinfo : seinfo, info ? info->name : pkgname, pathname, ctx);
Stephen Smalleye183cec2014-02-05 16:41:47 -05001188 if (rc < 0)
1189 goto err;
1190
1191 secontext = context_str(ctx);
1192 if (!secontext)
1193 goto err;
1194
1195 if (!strcmp(secontext, *secontextp))
1196 goto out;
1197
1198 rc = security_check_context(secontext);
1199 if (rc < 0)
1200 goto err;
1201
1202 freecon(*secontextp);
1203 *secontextp = strdup(secontext);
1204 if (!(*secontextp))
1205 goto err;
1206
1207 rc = 0;
1208
1209out:
1210 free(pkgname);
1211 context_free(ctx);
1212 return rc;
1213err:
1214 selinux_log(SELINUX_ERROR, "%s: Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
William Roberts6d5e6ed2015-07-31 13:05:47 -07001215 __FUNCTION__, pathname, pkgname, info->seinfo, info->uid, strerror(errno));
Stephen Smalleye183cec2014-02-05 16:41:47 -05001216 rc = -1;
1217 goto out;
1218}
1219
Stephen Smalley826cc292014-01-28 15:04:22 -05001220#define RESTORECON_LAST "security.restorecon_last"
1221
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001222static int restorecon_sb(const char *pathname, const struct stat *sb,
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001223 bool nochange, bool verbose,
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001224 const char *seinfo, uid_t uid)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001225{
1226 char *secontext = NULL;
1227 char *oldsecontext = NULL;
Stephen Smalleye183cec2014-02-05 16:41:47 -05001228 int rc = 0;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001229
dcashman965141a2014-12-03 12:51:50 -08001230 if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001231 return 0; /* no match, but not an error */
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001232
Stephen Smalleye183cec2014-02-05 16:41:47 -05001233 if (lgetfilecon(pathname, &oldsecontext) < 0)
1234 goto err;
1235
Stephen Smalley833cbd62014-02-27 13:08:40 -05001236 /*
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001237 * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
1238 * and use pkgdir_selabel_lookup() instead. Files within those directories
1239 * have different labeling rules, based off of /seapp_contexts, and
1240 * installd is responsible for managing these labels instead of init.
Stephen Smalley833cbd62014-02-27 13:08:40 -05001241 */
Stephen Smalleye183cec2014-02-05 16:41:47 -05001242 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
Jeff Sharkey4766bfa2015-04-09 20:40:09 -07001243 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001244 !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1245 !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
1246 !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001247 if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
Stephen Smalleye183cec2014-02-05 16:41:47 -05001248 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001249 }
1250
1251 if (strcmp(oldsecontext, secontext) != 0) {
Stephen Smalley08587cf2014-01-30 10:13:12 -05001252 if (verbose)
1253 selinux_log(SELINUX_INFO,
1254 "SELinux: Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
1255 if (!nochange) {
Stephen Smalleye183cec2014-02-05 16:41:47 -05001256 if (lsetfilecon(pathname, secontext) < 0)
1257 goto err;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001258 }
1259 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001260
Stephen Smalleye183cec2014-02-05 16:41:47 -05001261 rc = 0;
1262
1263out:
1264 freecon(oldsecontext);
1265 freecon(secontext);
1266 return rc;
1267
1268err:
1269 selinux_log(SELINUX_ERROR,
1270 "SELinux: Could not set context for %s: %s\n",
1271 pathname, strerror(errno));
1272 rc = -1;
1273 goto out;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001274}
1275
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001276#define SYS_PATH "/sys"
1277#define SYS_PREFIX SYS_PATH "/"
1278
dcashman06d45512015-06-12 14:38:54 -07001279static int selinux_android_restorecon_common(const char* pathname_orig,
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001280 const char *seinfo,
1281 uid_t uid,
1282 unsigned int flags)
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001283{
Stephen Smalley08587cf2014-01-30 10:13:12 -05001284 bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
1285 bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
1286 bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
1287 bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
Stephen Smalley027670d2014-02-18 11:04:37 -05001288 bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
Jeff Sharkey9d7eba12016-07-15 16:21:06 -06001289 bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false;
dcashman06d45512015-06-12 14:38:54 -07001290 bool issys;
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001291 bool setrestoreconlast = true;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001292 struct stat sb;
William Robertsbe861662015-07-07 18:18:54 -07001293 struct statfs sfsb;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001294 FTS *fts;
1295 FTSENT *ftsent;
Dan Cashman87ceb1e2015-09-10 09:42:15 -07001296 char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
dcashman06d45512015-06-12 14:38:54 -07001297 char * paths[2] = { NULL , NULL };
Stephen Smalleydfb9fe22014-09-02 12:52:57 -04001298 int ftsflags = FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001299 int error, sverrno;
Stephen Smalley826cc292014-01-28 15:04:22 -05001300 char xattr_value[FC_DIGEST_SIZE];
1301 ssize_t size;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001302
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001303 if (is_selinux_enabled() <= 0)
1304 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001305
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001306 __selinux_once(fc_once, file_context_init);
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001307
dcashman965141a2014-12-03 12:51:50 -08001308 if (!fc_sehandle)
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001309 return 0;
Stephen Smalley0ca91b32012-03-19 10:25:53 -04001310
Dan Cashman87ceb1e2015-09-10 09:42:15 -07001311 /*
1312 * Convert passed-in pathname to canonical pathname by resolving realpath of
1313 * containing dir, then appending last component name.
1314 */
1315 pathbname = basename(pathname_orig);
1316 if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) {
1317 pathname = realpath(pathname_orig, NULL);
1318 if (!pathname)
1319 goto realpatherr;
1320 } else {
1321 pathdname = dirname(pathname_orig);
1322 pathdnamer = realpath(pathdname, NULL);
1323 if (!pathdnamer)
1324 goto realpatherr;
1325 if (!strcmp(pathdnamer, "/"))
1326 error = asprintf(&pathname, "/%s", pathbname);
1327 else
1328 error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname);
1329 if (error < 0)
1330 goto oom;
dcashman06d45512015-06-12 14:38:54 -07001331 }
Dan Cashman87ceb1e2015-09-10 09:42:15 -07001332
dcashman06d45512015-06-12 14:38:54 -07001333 paths[0] = pathname;
1334 issys = (!strcmp(pathname, SYS_PATH)
1335 || !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001336
dcashman06d45512015-06-12 14:38:54 -07001337 if (!recurse) {
1338 if (lstat(pathname, &sb) < 0) {
1339 error = -1;
1340 goto cleanup;
1341 }
1342
1343 error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
1344 goto cleanup;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001345 }
1346
Stephen Smalley833cbd62014-02-27 13:08:40 -05001347 /*
1348 * Ignore restorecon_last on /data/data or /data/user
1349 * since their labeling is based on seapp_contexts and seinfo
1350 * assignments rather than file_contexts and is managed by
1351 * installd rather than init.
1352 */
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001353 if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
Jeff Sharkey4766bfa2015-04-09 20:40:09 -07001354 !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001355 !strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1356 !fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME) ||
1357 !fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME))
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001358 setrestoreconlast = false;
Stephen Smalley833cbd62014-02-27 13:08:40 -05001359
Stephen Smalleyda4208c2014-07-07 14:59:06 -04001360 /* Also ignore on /sys since it is regenerated on each boot regardless. */
1361 if (issys)
1362 setrestoreconlast = false;
1363
William Robertsbe861662015-07-07 18:18:54 -07001364 /* Ignore files on in-memory filesystems */
1365 if (statfs(pathname, &sfsb) == 0) {
1366 if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
1367 setrestoreconlast = false;
1368 }
1369
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001370 if (setrestoreconlast) {
1371 size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
1372 if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
1373 selinux_log(SELINUX_INFO,
1374 "SELinux: Skipping restorecon_recursive(%s)\n",
1375 pathname);
dcashman06d45512015-06-12 14:38:54 -07001376 error = 0;
1377 goto cleanup;
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001378 }
Stephen Smalley826cc292014-01-28 15:04:22 -05001379 }
1380
Stephen Smalley08587cf2014-01-30 10:13:12 -05001381 fts = fts_open(paths, ftsflags, NULL);
dcashman06d45512015-06-12 14:38:54 -07001382 if (!fts) {
1383 error = -1;
1384 goto cleanup;
1385 }
Stephen Smalley08587cf2014-01-30 10:13:12 -05001386
1387 error = 0;
1388 while ((ftsent = fts_read(fts)) != NULL) {
1389 switch (ftsent->fts_info) {
1390 case FTS_DC:
1391 selinux_log(SELINUX_ERROR,
1392 "SELinux: Directory cycle on %s.\n", ftsent->fts_path);
1393 errno = ELOOP;
1394 error = -1;
1395 goto out;
1396 case FTS_DP:
1397 continue;
1398 case FTS_DNR:
1399 selinux_log(SELINUX_ERROR,
1400 "SELinux: Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
1401 fts_set(fts, ftsent, FTS_SKIP);
1402 continue;
1403 case FTS_NS:
1404 selinux_log(SELINUX_ERROR,
1405 "SELinux: Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
1406 fts_set(fts, ftsent, FTS_SKIP);
1407 continue;
1408 case FTS_ERR:
1409 selinux_log(SELINUX_ERROR,
1410 "SELinux: Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
1411 fts_set(fts, ftsent, FTS_SKIP);
1412 continue;
Stephen Smalley027670d2014-02-18 11:04:37 -05001413 case FTS_D:
dcashman965141a2014-12-03 12:51:50 -08001414 if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
Stephen Smalley0e7340f2014-04-30 15:13:30 -07001415 fts_set(fts, ftsent, FTS_SKIP);
1416 continue;
1417 }
Jeff Sharkey4766bfa2015-04-09 20:40:09 -07001418
Jeff Sharkey9d7eba12016-07-15 16:21:06 -06001419 if (skipce &&
1420 (!strncmp(ftsent->fts_path, DATA_SYSTEM_CE_PREFIX, sizeof(DATA_SYSTEM_CE_PREFIX)-1) ||
1421 !strncmp(ftsent->fts_path, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1))) {
1422 // Don't label anything below this directory.
1423 fts_set(fts, ftsent, FTS_SKIP);
1424 // but fall through and make sure we label the directory itself
1425 }
1426
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001427 if (!datadata &&
Nick Kralevichd601f822015-04-13 18:09:33 -07001428 (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
Jeff Sharkey4766bfa2015-04-09 20:40:09 -07001429 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
Jeff Sharkeyc821cc22015-11-09 13:16:55 -08001430 !strncmp(ftsent->fts_path, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
1431 !fnmatch(EXPAND_USER_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME) ||
1432 !fnmatch(EXPAND_USER_DE_PATH, ftsent->fts_path, FNM_LEADING_DIR|FNM_PATHNAME))) {
Nick Kralevich4b130cc2014-05-16 17:31:31 -07001433 // Don't label anything below this directory.
1434 fts_set(fts, ftsent, FTS_SKIP);
1435 // but fall through and make sure we label the directory itself
1436 }
Stephen Smalley027670d2014-02-18 11:04:37 -05001437 /* fall through */
Stephen Smalley08587cf2014-01-30 10:13:12 -05001438 default:
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001439 error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001440 break;
1441 }
1442 }
1443
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001444 // Labeling successful. Mark the top level directory as completed.
1445 if (setrestoreconlast && !nochange && !error)
1446 setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
1447
Stephen Smalley08587cf2014-01-30 10:13:12 -05001448out:
1449 sverrno = errno;
1450 (void) fts_close(fts);
Nick Kralevicha8e4ad32014-05-19 13:45:59 -07001451 errno = sverrno;
dcashman06d45512015-06-12 14:38:54 -07001452cleanup:
Dan Cashman87ceb1e2015-09-10 09:42:15 -07001453 free(pathdnamer);
dcashman06d45512015-06-12 14:38:54 -07001454 free(pathname);
Stephen Smalley08587cf2014-01-30 10:13:12 -05001455 return error;
Dan Cashman87ceb1e2015-09-10 09:42:15 -07001456oom:
1457 sverrno = errno;
1458 selinux_log(SELINUX_ERROR, "%s: Out of memory\n", __FUNCTION__);
1459 errno = sverrno;
1460 error = -1;
1461 goto cleanup;
1462realpatherr:
1463 sverrno = errno;
1464 selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n",
1465 pathname_orig, strerror(errno));
1466 errno = sverrno;
1467 error = -1;
1468 goto cleanup;
Stephen Smalley08587cf2014-01-30 10:13:12 -05001469}
1470
Stephen Smalley1d66afb2014-03-27 08:47:15 -04001471int selinux_android_restorecon(const char *file, unsigned int flags)
1472{
1473 return selinux_android_restorecon_common(file, NULL, -1, flags);
1474}
1475
1476int selinux_android_restorecon_pkgdir(const char *pkgdir,
1477 const char *seinfo,
1478 uid_t uid,
1479 unsigned int flags)
1480{
1481 return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
1482}
1483
rpcraigf1724a32012-08-01 15:35:37 -04001484struct selabel_handle* selinux_android_file_context_handle(void)
1485{
Richard Haines91b7d912015-08-24 11:18:06 +01001486 char *path = NULL;
dcashman965141a2014-12-03 12:51:50 -08001487 struct selabel_handle *sehandle;
Richard Haines91b7d912015-08-24 11:18:06 +01001488 struct selinux_opt fc_opts[] = {
1489 { SELABEL_OPT_PATH, path },
1490 { SELABEL_OPT_BASEONLY, (char *)1 }
1491 };
dcashman965141a2014-12-03 12:51:50 -08001492
1493 set_policy_index();
Richard Haines91b7d912015-08-24 11:18:06 +01001494 fc_opts[0].value = seopts[policy_index].value;
1495
1496 sehandle = selabel_open(SELABEL_CTX_FILE, fc_opts, 2);
dcashman965141a2014-12-03 12:51:50 -08001497
1498 if (!sehandle) {
1499 selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
1500 __FUNCTION__, strerror(errno));
1501 return NULL;
1502 }
1503 if (!compute_contexts_hash(seopts, fc_digest)) {
1504 selabel_close(sehandle);
1505 return NULL;
1506 }
1507 selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts contexts from %s.\n",
Richard Haines91b7d912015-08-24 11:18:06 +01001508 fc_opts[0].value);
dcashman965141a2014-12-03 12:51:50 -08001509
1510 return sehandle;
1511}
1512
1513struct selabel_handle* selinux_android_prop_context_handle(void)
1514{
1515 struct selabel_handle* sehandle;
1516
1517 set_policy_index();
1518 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1519 &seopts_prop[policy_index], 1);
1520 if (!sehandle) {
1521 selinux_log(SELINUX_ERROR, "%s: Error getting property context handle (%s)\n",
1522 __FUNCTION__, strerror(errno));
1523 return NULL;
1524 }
1525 selinux_log(SELINUX_INFO, "SELinux: Loaded property_contexts from %s.\n",
1526 seopts_prop[policy_index].value);
1527
1528 return sehandle;
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001529}
1530
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001531struct selabel_handle* selinux_android_service_context_handle(void)
1532{
dcashman965141a2014-12-03 12:51:50 -08001533 struct selabel_handle* sehandle;
1534
1535 set_policy_index();
1536 sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP,
1537 &seopts_service[policy_index], 1);
1538
1539 if (!sehandle) {
1540 selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
1541 __FUNCTION__, strerror(errno));
1542 return NULL;
1543 }
1544 selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s.\n",
1545 seopts_service[policy_index].value);
1546
1547 return sehandle;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001548}
1549
Stephen Smalley7fc97fb2014-01-28 10:37:58 -05001550void selinux_android_set_sehandle(const struct selabel_handle *hndl)
1551{
dcashman965141a2014-12-03 12:51:50 -08001552 fc_sehandle = (struct selabel_handle *) hndl;
rpcraigf1724a32012-08-01 15:35:37 -04001553}
rpcraig9b100832012-07-27 06:36:59 -04001554
Robert Craig5b5183f2014-03-17 20:53:06 -04001555static int selinux_android_load_policy_helper(bool reload)
rpcraigf1724a32012-08-01 15:35:37 -04001556{
Stephen Smalley4a655ec2012-09-18 15:08:32 -04001557 int fd = -1, rc;
rpcraigf1724a32012-08-01 15:35:37 -04001558 struct stat sb;
1559 void *map = NULL;
Stephen Smalley818815e2015-02-18 17:32:13 -05001560 int old_policy_index = policy_index;
rpcraigf1724a32012-08-01 15:35:37 -04001561
Robert Craig5b5183f2014-03-17 20:53:06 -04001562 /*
1563 * If reloading policy and there is no /data policy or
Stephen Smalley818815e2015-02-18 17:32:13 -05001564 * that /data policy has the wrong version and our prior
1565 * load was from the / policy, then just return.
Robert Craig5b5183f2014-03-17 20:53:06 -04001566 * There is no point in reloading policy from / a second time.
1567 */
dcashman965141a2014-12-03 12:51:50 -08001568 set_policy_index();
Stephen Smalley818815e2015-02-18 17:32:13 -05001569 if (reload && !policy_index && !old_policy_index)
Robert Craig5b5183f2014-03-17 20:53:06 -04001570 return 0;
1571
1572 fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
rpcraigf1724a32012-08-01 15:35:37 -04001573 if (fd < 0) {
1574 selinux_log(SELINUX_ERROR, "SELinux: Could not open sepolicy: %s\n",
1575 strerror(errno));
1576 return -1;
1577 }
1578 if (fstat(fd, &sb) < 0) {
1579 selinux_log(SELINUX_ERROR, "SELinux: Could not stat %s: %s\n",
Robert Craig5b5183f2014-03-17 20:53:06 -04001580 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001581 close(fd);
1582 return -1;
1583 }
1584 map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
1585 if (map == MAP_FAILED) {
1586 selinux_log(SELINUX_ERROR, "SELinux: Could not map %s: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001587 sepolicy_file[policy_index], strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001588 close(fd);
1589 return -1;
1590 }
1591
1592 rc = security_load_policy(map, sb.st_size);
1593 if (rc < 0) {
1594 selinux_log(SELINUX_ERROR, "SELinux: Could not load policy: %s\n",
dcashman965141a2014-12-03 12:51:50 -08001595 strerror(errno));
rpcraigf1724a32012-08-01 15:35:37 -04001596 munmap(map, sb.st_size);
1597 close(fd);
1598 return -1;
1599 }
1600
1601 munmap(map, sb.st_size);
1602 close(fd);
Robert Craig5b5183f2014-03-17 20:53:06 -04001603 selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
rpcraigf1724a32012-08-01 15:35:37 -04001604
1605 return 0;
1606}
1607
Robert Craig5b5183f2014-03-17 20:53:06 -04001608int selinux_android_reload_policy(void)
1609{
1610 return selinux_android_load_policy_helper(true);
1611}
1612
rpcraigf1724a32012-08-01 15:35:37 -04001613int selinux_android_load_policy(void)
1614{
Nick Kralevich833cba62013-11-19 11:24:33 -08001615 const char *mnt = SELINUXMNT;
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001616 int rc;
1617 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1618 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001619 if (errno == ENODEV) {
1620 /* SELinux not enabled in kernel */
1621 return -1;
1622 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001623 if (errno == ENOENT) {
1624 /* Fall back to legacy mountpoint. */
1625 mnt = OLDSELINUXMNT;
Alice Chud2302ca2013-01-04 16:02:46 -08001626 rc = mkdir(mnt, 0755);
1627 if (rc == -1 && errno != EEXIST) {
1628 selinux_log(SELINUX_ERROR,"SELinux: Could not mkdir: %s\n",
1629 strerror(errno));
1630 return -1;
1631 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001632 rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
1633 }
1634 }
1635 if (rc < 0) {
rpcraigf1724a32012-08-01 15:35:37 -04001636 selinux_log(SELINUX_ERROR,"SELinux: Could not mount selinuxfs: %s\n",
1637 strerror(errno));
1638 return -1;
1639 }
Stephen Smalleyd10c3432012-11-05 11:49:35 -05001640 set_selinuxmnt(mnt);
rpcraigf1724a32012-08-01 15:35:37 -04001641
Robert Craig5b5183f2014-03-17 20:53:06 -04001642 return selinux_android_load_policy_helper(false);
rpcraig9b100832012-07-27 06:36:59 -04001643}
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001644
1645int selinux_log_callback(int type, const char *fmt, ...)
1646{
1647 va_list ap;
1648 int priority;
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001649 char *strp;
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001650
1651 switch(type) {
1652 case SELINUX_WARNING:
1653 priority = ANDROID_LOG_WARN;
1654 break;
1655 case SELINUX_INFO:
1656 priority = ANDROID_LOG_INFO;
1657 break;
1658 default:
1659 priority = ANDROID_LOG_ERROR;
1660 break;
1661 }
1662
1663 va_start(ap, fmt);
Nick Kralevichf58dbdd2014-07-01 11:01:13 -07001664 if (vasprintf(&strp, fmt, ap) != -1) {
1665 LOG_PRI(priority, "SELinux", "%s", strp);
1666 LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
1667 free(strp);
1668 }
Riley Spahnbad0ebb2014-06-11 16:07:53 -07001669 va_end(ap);
1670 return 0;
1671}