xref: /aosp_15_r20/external/selinux/libselinux/src/android/android_device.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
2*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
3*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
4*2d543d20SAndroid Build Coastguard Worker #include <fnmatch.h>
5*2d543d20SAndroid Build Coastguard Worker #include <fts.h>
6*2d543d20SAndroid Build Coastguard Worker #include <libgen.h>
7*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
8*2d543d20SAndroid Build Coastguard Worker #include <linux/magic.h>
9*2d543d20SAndroid Build Coastguard Worker #include <stdbool.h>
10*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
11*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
12*2d543d20SAndroid Build Coastguard Worker #include <string.h>
13*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
14*2d543d20SAndroid Build Coastguard Worker #include <sys/system_properties.h>
15*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
16*2d543d20SAndroid Build Coastguard Worker #include <sys/vfs.h>
17*2d543d20SAndroid Build Coastguard Worker #include <sys/xattr.h>
18*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
19*2d543d20SAndroid Build Coastguard Worker 
20*2d543d20SAndroid Build Coastguard Worker #include <log/log.h>
21*2d543d20SAndroid Build Coastguard Worker #include <packagelistparser/packagelistparser.h>
22*2d543d20SAndroid Build Coastguard Worker #include <private/android_filesystem_config.h>
23*2d543d20SAndroid Build Coastguard Worker #include <selinux/android.h>
24*2d543d20SAndroid Build Coastguard Worker #include <selinux/context.h>
25*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
26*2d543d20SAndroid Build Coastguard Worker 
27*2d543d20SAndroid Build Coastguard Worker #include "android_internal.h"
28*2d543d20SAndroid Build Coastguard Worker #include "callbacks.h"
29*2d543d20SAndroid Build Coastguard Worker #include "label_internal.h"
30*2d543d20SAndroid Build Coastguard Worker #include "selinux_internal.h"
31*2d543d20SAndroid Build Coastguard Worker 
selinux_android_context_with_level(const char * context,char ** newContext,uid_t userid,uid_t appid)32*2d543d20SAndroid Build Coastguard Worker int selinux_android_context_with_level(const char * context,
33*2d543d20SAndroid Build Coastguard Worker 				       char ** newContext,
34*2d543d20SAndroid Build Coastguard Worker 				       uid_t userid,
35*2d543d20SAndroid Build Coastguard Worker 				       uid_t appid)
36*2d543d20SAndroid Build Coastguard Worker {
37*2d543d20SAndroid Build Coastguard Worker 	int rc = -2;
38*2d543d20SAndroid Build Coastguard Worker 
39*2d543d20SAndroid Build Coastguard Worker 	enum levelFrom levelFrom;
40*2d543d20SAndroid Build Coastguard Worker 	if (userid == (uid_t) -1) {
41*2d543d20SAndroid Build Coastguard Worker 		levelFrom = (appid == (uid_t) -1) ? LEVELFROM_NONE : LEVELFROM_APP;
42*2d543d20SAndroid Build Coastguard Worker 	} else {
43*2d543d20SAndroid Build Coastguard Worker 		levelFrom = (appid == (uid_t) -1) ? LEVELFROM_USER : LEVELFROM_ALL;
44*2d543d20SAndroid Build Coastguard Worker 	}
45*2d543d20SAndroid Build Coastguard Worker 
46*2d543d20SAndroid Build Coastguard Worker 	context_t ctx = context_new(context);
47*2d543d20SAndroid Build Coastguard Worker 	if (!ctx) {
48*2d543d20SAndroid Build Coastguard Worker 		goto out;
49*2d543d20SAndroid Build Coastguard Worker 	}
50*2d543d20SAndroid Build Coastguard Worker 
51*2d543d20SAndroid Build Coastguard Worker 	int res = set_range_from_level(ctx, levelFrom, userid, appid);
52*2d543d20SAndroid Build Coastguard Worker 	if (res != 0) {
53*2d543d20SAndroid Build Coastguard Worker 		rc = res;
54*2d543d20SAndroid Build Coastguard Worker 		goto out;
55*2d543d20SAndroid Build Coastguard Worker 	}
56*2d543d20SAndroid Build Coastguard Worker 
57*2d543d20SAndroid Build Coastguard Worker 	const char * newString = context_str(ctx);
58*2d543d20SAndroid Build Coastguard Worker 	if (!newString) {
59*2d543d20SAndroid Build Coastguard Worker 		goto out;
60*2d543d20SAndroid Build Coastguard Worker 	}
61*2d543d20SAndroid Build Coastguard Worker 
62*2d543d20SAndroid Build Coastguard Worker 	char * newCopied = strdup(newString);
63*2d543d20SAndroid Build Coastguard Worker 	if (!newCopied) {
64*2d543d20SAndroid Build Coastguard Worker 		goto out;
65*2d543d20SAndroid Build Coastguard Worker 	}
66*2d543d20SAndroid Build Coastguard Worker 
67*2d543d20SAndroid Build Coastguard Worker 	*newContext = newCopied;
68*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
69*2d543d20SAndroid Build Coastguard Worker 
70*2d543d20SAndroid Build Coastguard Worker out:
71*2d543d20SAndroid Build Coastguard Worker 	context_free(ctx);
72*2d543d20SAndroid Build Coastguard Worker 	return rc;
73*2d543d20SAndroid Build Coastguard Worker }
74*2d543d20SAndroid Build Coastguard Worker 
selinux_android_setcon(const char * con)75*2d543d20SAndroid Build Coastguard Worker int selinux_android_setcon(const char *con)
76*2d543d20SAndroid Build Coastguard Worker {
77*2d543d20SAndroid Build Coastguard Worker 	int ret = setcon(con);
78*2d543d20SAndroid Build Coastguard Worker 	if (ret)
79*2d543d20SAndroid Build Coastguard Worker 		return ret;
80*2d543d20SAndroid Build Coastguard Worker 	/*
81*2d543d20SAndroid Build Coastguard Worker 	  System properties must be reinitialized after setcon() otherwise the
82*2d543d20SAndroid Build Coastguard Worker 	  previous property files will be leaked since mmap()'ed regions are not
83*2d543d20SAndroid Build Coastguard Worker 	  closed as a result of setcon().
84*2d543d20SAndroid Build Coastguard Worker 	*/
85*2d543d20SAndroid Build Coastguard Worker 	return __system_properties_init();
86*2d543d20SAndroid Build Coastguard Worker }
87*2d543d20SAndroid Build Coastguard Worker 
selinux_android_setcontext(uid_t uid,bool isSystemServer,const char * seinfo,const char * pkgname)88*2d543d20SAndroid Build Coastguard Worker int selinux_android_setcontext(uid_t uid,
89*2d543d20SAndroid Build Coastguard Worker 			       bool isSystemServer,
90*2d543d20SAndroid Build Coastguard Worker 			       const char *seinfo,
91*2d543d20SAndroid Build Coastguard Worker 			       const char *pkgname)
92*2d543d20SAndroid Build Coastguard Worker {
93*2d543d20SAndroid Build Coastguard Worker 	char *orig_ctx_str = NULL;
94*2d543d20SAndroid Build Coastguard Worker 	const char *ctx_str = NULL;
95*2d543d20SAndroid Build Coastguard Worker 	context_t ctx = NULL;
96*2d543d20SAndroid Build Coastguard Worker 	int rc = -1;
97*2d543d20SAndroid Build Coastguard Worker 
98*2d543d20SAndroid Build Coastguard Worker 	if (is_selinux_enabled() <= 0)
99*2d543d20SAndroid Build Coastguard Worker 		return 0;
100*2d543d20SAndroid Build Coastguard Worker 
101*2d543d20SAndroid Build Coastguard Worker 	rc = getcon(&orig_ctx_str);
102*2d543d20SAndroid Build Coastguard Worker 	if (rc)
103*2d543d20SAndroid Build Coastguard Worker 		goto err;
104*2d543d20SAndroid Build Coastguard Worker 
105*2d543d20SAndroid Build Coastguard Worker 	ctx = context_new(orig_ctx_str);
106*2d543d20SAndroid Build Coastguard Worker 	if (!ctx)
107*2d543d20SAndroid Build Coastguard Worker 		goto oom;
108*2d543d20SAndroid Build Coastguard Worker 
109*2d543d20SAndroid Build Coastguard Worker 	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, ctx);
110*2d543d20SAndroid Build Coastguard Worker 	if (rc == -1)
111*2d543d20SAndroid Build Coastguard Worker 		goto err;
112*2d543d20SAndroid Build Coastguard Worker 	else if (rc == -2)
113*2d543d20SAndroid Build Coastguard Worker 		goto oom;
114*2d543d20SAndroid Build Coastguard Worker 
115*2d543d20SAndroid Build Coastguard Worker 	ctx_str = context_str(ctx);
116*2d543d20SAndroid Build Coastguard Worker 	if (!ctx_str)
117*2d543d20SAndroid Build Coastguard Worker 		goto oom;
118*2d543d20SAndroid Build Coastguard Worker 
119*2d543d20SAndroid Build Coastguard Worker 	rc = security_check_context(ctx_str);
120*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
121*2d543d20SAndroid Build Coastguard Worker 		goto err;
122*2d543d20SAndroid Build Coastguard Worker 
123*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(ctx_str, orig_ctx_str)) {
124*2d543d20SAndroid Build Coastguard Worker 		rc = selinux_android_setcon(ctx_str);
125*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0)
126*2d543d20SAndroid Build Coastguard Worker 			goto err;
127*2d543d20SAndroid Build Coastguard Worker 	}
128*2d543d20SAndroid Build Coastguard Worker 
129*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
130*2d543d20SAndroid Build Coastguard Worker out:
131*2d543d20SAndroid Build Coastguard Worker 	freecon(orig_ctx_str);
132*2d543d20SAndroid Build Coastguard Worker 	context_free(ctx);
133*2d543d20SAndroid Build Coastguard Worker 	return rc;
134*2d543d20SAndroid Build Coastguard Worker err:
135*2d543d20SAndroid Build Coastguard Worker 	if (isSystemServer)
136*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR,
137*2d543d20SAndroid Build Coastguard Worker 				"%s:  Error setting context for system server: %s\n",
138*2d543d20SAndroid Build Coastguard Worker 				__FUNCTION__, strerror(errno));
139*2d543d20SAndroid Build Coastguard Worker 	else
140*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR,
141*2d543d20SAndroid Build Coastguard Worker 				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
142*2d543d20SAndroid Build Coastguard Worker 				__FUNCTION__, uid, seinfo, strerror(errno));
143*2d543d20SAndroid Build Coastguard Worker 
144*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
145*2d543d20SAndroid Build Coastguard Worker 	goto out;
146*2d543d20SAndroid Build Coastguard Worker oom:
147*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
148*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
149*2d543d20SAndroid Build Coastguard Worker 	goto out;
150*2d543d20SAndroid Build Coastguard Worker }
151*2d543d20SAndroid Build Coastguard Worker 
152*2d543d20SAndroid Build Coastguard Worker static struct selabel_handle *fc_sehandle = NULL;
153*2d543d20SAndroid Build Coastguard Worker 
file_context_init(void)154*2d543d20SAndroid Build Coastguard Worker static void file_context_init(void)
155*2d543d20SAndroid Build Coastguard Worker {
156*2d543d20SAndroid Build Coastguard Worker 	if (!fc_sehandle)
157*2d543d20SAndroid Build Coastguard Worker 		fc_sehandle = selinux_android_file_context_handle();
158*2d543d20SAndroid Build Coastguard Worker }
159*2d543d20SAndroid Build Coastguard Worker 
160*2d543d20SAndroid Build Coastguard Worker static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
161*2d543d20SAndroid Build Coastguard Worker 
162*2d543d20SAndroid Build Coastguard Worker #define PKGTAB_SIZE 256
163*2d543d20SAndroid Build Coastguard Worker /* Hash table for pkg_info. It uses the package name as key. In case of
164*2d543d20SAndroid Build Coastguard Worker  * collision, the next entry is the private_data attribute */
165*2d543d20SAndroid Build Coastguard Worker static struct pkg_info *pkgTab[PKGTAB_SIZE];
166*2d543d20SAndroid Build Coastguard Worker 
167*2d543d20SAndroid Build Coastguard Worker /* Returns a hash based on the package name */
pkghash(const char * pkgname)168*2d543d20SAndroid Build Coastguard Worker static unsigned int pkghash(const char *pkgname)
169*2d543d20SAndroid Build Coastguard Worker {
170*2d543d20SAndroid Build Coastguard Worker 	unsigned int h = 7;
171*2d543d20SAndroid Build Coastguard Worker 	for (; *pkgname; pkgname++) {
172*2d543d20SAndroid Build Coastguard Worker 		h = h * 31 + *pkgname;
173*2d543d20SAndroid Build Coastguard Worker 	}
174*2d543d20SAndroid Build Coastguard Worker 	return h & (PKGTAB_SIZE - 1);
175*2d543d20SAndroid Build Coastguard Worker }
176*2d543d20SAndroid Build Coastguard Worker 
177*2d543d20SAndroid Build Coastguard Worker /* Adds the pkg_info entry to the hash table */
pkg_parse_callback(pkg_info * info,void * userdata)178*2d543d20SAndroid Build Coastguard Worker static bool pkg_parse_callback(pkg_info *info, void *userdata) {
179*2d543d20SAndroid Build Coastguard Worker 
180*2d543d20SAndroid Build Coastguard Worker 	(void) userdata;
181*2d543d20SAndroid Build Coastguard Worker 
182*2d543d20SAndroid Build Coastguard Worker 	unsigned int hash = pkghash(info->name);
183*2d543d20SAndroid Build Coastguard Worker 	if (pkgTab[hash])
184*2d543d20SAndroid Build Coastguard Worker 		/* Collision. Prepend the entry. */
185*2d543d20SAndroid Build Coastguard Worker 		info->private_data = pkgTab[hash];
186*2d543d20SAndroid Build Coastguard Worker 	pkgTab[hash] = info;
187*2d543d20SAndroid Build Coastguard Worker 	return true;
188*2d543d20SAndroid Build Coastguard Worker }
189*2d543d20SAndroid Build Coastguard Worker 
190*2d543d20SAndroid Build Coastguard Worker /* Initialize the pkg_info hash table */
package_info_init(void)191*2d543d20SAndroid Build Coastguard Worker static void package_info_init(void)
192*2d543d20SAndroid Build Coastguard Worker {
193*2d543d20SAndroid Build Coastguard Worker 
194*2d543d20SAndroid Build Coastguard Worker 	bool rc = packagelist_parse(pkg_parse_callback, NULL);
195*2d543d20SAndroid Build Coastguard Worker 	if (!rc) {
196*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_ERROR, "SELinux: Could NOT parse package list\n");
197*2d543d20SAndroid Build Coastguard Worker 		return;
198*2d543d20SAndroid Build Coastguard Worker 	}
199*2d543d20SAndroid Build Coastguard Worker 
200*2d543d20SAndroid Build Coastguard Worker #if DEBUG
201*2d543d20SAndroid Build Coastguard Worker 	{
202*2d543d20SAndroid Build Coastguard Worker 		unsigned int hash, buckets, entries, chainlen, longestchain;
203*2d543d20SAndroid Build Coastguard Worker 		struct pkg_info *info = NULL;
204*2d543d20SAndroid Build Coastguard Worker 
205*2d543d20SAndroid Build Coastguard Worker 		buckets = entries = longestchain = 0;
206*2d543d20SAndroid Build Coastguard Worker 		for (hash = 0; hash < PKGTAB_SIZE; hash++) {
207*2d543d20SAndroid Build Coastguard Worker 			if (pkgTab[hash]) {
208*2d543d20SAndroid Build Coastguard Worker 				buckets++;
209*2d543d20SAndroid Build Coastguard Worker 				chainlen = 0;
210*2d543d20SAndroid Build Coastguard Worker 				for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
211*2d543d20SAndroid Build Coastguard Worker 					chainlen++;
212*2d543d20SAndroid Build Coastguard Worker 					selinux_log(SELINUX_INFO, "%s:	name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
213*2d543d20SAndroid Build Coastguard Worker 								__FUNCTION__,
214*2d543d20SAndroid Build Coastguard Worker 								info->name, info->uid, info->debuggable ? "true" : "false", info->data_dir, info->seinfo);
215*2d543d20SAndroid Build Coastguard Worker 				}
216*2d543d20SAndroid Build Coastguard Worker 				entries += chainlen;
217*2d543d20SAndroid Build Coastguard Worker 				if (longestchain < chainlen)
218*2d543d20SAndroid Build Coastguard Worker 					longestchain = chainlen;
219*2d543d20SAndroid Build Coastguard Worker 			}
220*2d543d20SAndroid Build Coastguard Worker 		}
221*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_INFO, "SELinux:  %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
222*2d543d20SAndroid Build Coastguard Worker 	}
223*2d543d20SAndroid Build Coastguard Worker #endif
224*2d543d20SAndroid Build Coastguard Worker 
225*2d543d20SAndroid Build Coastguard Worker }
226*2d543d20SAndroid Build Coastguard Worker 
227*2d543d20SAndroid Build Coastguard Worker static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
228*2d543d20SAndroid Build Coastguard Worker 
229*2d543d20SAndroid Build Coastguard Worker /* Returns the pkg_info for a package with a specific name */
package_info_lookup(const char * name)230*2d543d20SAndroid Build Coastguard Worker struct pkg_info *package_info_lookup(const char *name)
231*2d543d20SAndroid Build Coastguard Worker {
232*2d543d20SAndroid Build Coastguard Worker 	struct pkg_info *info;
233*2d543d20SAndroid Build Coastguard Worker 	unsigned int hash;
234*2d543d20SAndroid Build Coastguard Worker 
235*2d543d20SAndroid Build Coastguard Worker 	__selinux_once(pkg_once, package_info_init);
236*2d543d20SAndroid Build Coastguard Worker 
237*2d543d20SAndroid Build Coastguard Worker 	hash = pkghash(name);
238*2d543d20SAndroid Build Coastguard Worker 	for (info = pkgTab[hash]; info; info = (pkg_info *)info->private_data) {
239*2d543d20SAndroid Build Coastguard Worker 		if (!strcmp(name, info->name))
240*2d543d20SAndroid Build Coastguard Worker 			return info;
241*2d543d20SAndroid Build Coastguard Worker 	}
242*2d543d20SAndroid Build Coastguard Worker 	return NULL;
243*2d543d20SAndroid Build Coastguard Worker }
244*2d543d20SAndroid Build Coastguard Worker 
245*2d543d20SAndroid Build Coastguard Worker #define USER_PROFILE_PATH "/data/misc/profiles/cur/*"
246*2d543d20SAndroid Build Coastguard Worker 
pkgdir_selabel_lookup(const char * pathname,const char * seinfo,uid_t uid,char ** secontextp)247*2d543d20SAndroid Build Coastguard Worker static int pkgdir_selabel_lookup(const char *pathname,
248*2d543d20SAndroid Build Coastguard Worker 				 const char *seinfo,
249*2d543d20SAndroid Build Coastguard Worker 				 uid_t uid,
250*2d543d20SAndroid Build Coastguard Worker 				 char **secontextp)
251*2d543d20SAndroid Build Coastguard Worker {
252*2d543d20SAndroid Build Coastguard Worker 	char *pkgname = NULL;
253*2d543d20SAndroid Build Coastguard Worker 	struct pkg_info *info = NULL;
254*2d543d20SAndroid Build Coastguard Worker 	const char *orig_ctx_str = *secontextp;
255*2d543d20SAndroid Build Coastguard Worker 	const char *ctx_str = NULL;
256*2d543d20SAndroid Build Coastguard Worker 	context_t ctx = NULL;
257*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
258*2d543d20SAndroid Build Coastguard Worker 	unsigned int userid_from_path = 0;
259*2d543d20SAndroid Build Coastguard Worker 
260*2d543d20SAndroid Build Coastguard Worker 	rc = extract_pkgname_and_userid(pathname, &pkgname, &userid_from_path);
261*2d543d20SAndroid Build Coastguard Worker 	if (rc) {
262*2d543d20SAndroid Build Coastguard Worker 		/* Invalid path, we skip it */
263*2d543d20SAndroid Build Coastguard Worker 		if (rc == -1) {
264*2d543d20SAndroid Build Coastguard Worker 			return 0;
265*2d543d20SAndroid Build Coastguard Worker 		}
266*2d543d20SAndroid Build Coastguard Worker 		return rc;
267*2d543d20SAndroid Build Coastguard Worker 	}
268*2d543d20SAndroid Build Coastguard Worker 
269*2d543d20SAndroid Build Coastguard Worker 	if (!seinfo) {
270*2d543d20SAndroid Build Coastguard Worker 		info = package_info_lookup(pkgname);
271*2d543d20SAndroid Build Coastguard Worker 		if (!info) {
272*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_WARNING, "SELinux:	Could not look up information for package %s, cannot restorecon %s.\n",
273*2d543d20SAndroid Build Coastguard Worker 						pkgname, pathname);
274*2d543d20SAndroid Build Coastguard Worker 			free(pkgname);
275*2d543d20SAndroid Build Coastguard Worker 			return -1;
276*2d543d20SAndroid Build Coastguard Worker 		}
277*2d543d20SAndroid Build Coastguard Worker 		// info->uid only contains the appid and not the userid.
278*2d543d20SAndroid Build Coastguard Worker 		info->uid += userid_from_path * AID_USER_OFFSET;
279*2d543d20SAndroid Build Coastguard Worker 	}
280*2d543d20SAndroid Build Coastguard Worker 
281*2d543d20SAndroid Build Coastguard Worker 	ctx = context_new(orig_ctx_str);
282*2d543d20SAndroid Build Coastguard Worker 	if (!ctx)
283*2d543d20SAndroid Build Coastguard Worker 		goto err;
284*2d543d20SAndroid Build Coastguard Worker 
285*2d543d20SAndroid Build Coastguard Worker 	rc = seapp_context_lookup(SEAPP_TYPE, info ? info->uid : uid, 0,
286*2d543d20SAndroid Build Coastguard Worker 				  info ? info->seinfo : seinfo, info ? info->name : pkgname, ctx);
287*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
288*2d543d20SAndroid Build Coastguard Worker 		goto err;
289*2d543d20SAndroid Build Coastguard Worker 
290*2d543d20SAndroid Build Coastguard Worker 	ctx_str = context_str(ctx);
291*2d543d20SAndroid Build Coastguard Worker 	if (!ctx_str)
292*2d543d20SAndroid Build Coastguard Worker 		goto err;
293*2d543d20SAndroid Build Coastguard Worker 
294*2d543d20SAndroid Build Coastguard Worker 	if (!strcmp(ctx_str, orig_ctx_str))
295*2d543d20SAndroid Build Coastguard Worker 		goto out;
296*2d543d20SAndroid Build Coastguard Worker 
297*2d543d20SAndroid Build Coastguard Worker 	rc = security_check_context(ctx_str);
298*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
299*2d543d20SAndroid Build Coastguard Worker 		goto err;
300*2d543d20SAndroid Build Coastguard Worker 
301*2d543d20SAndroid Build Coastguard Worker 	freecon(*secontextp);
302*2d543d20SAndroid Build Coastguard Worker 	*secontextp = strdup(ctx_str);
303*2d543d20SAndroid Build Coastguard Worker 	if (!(*secontextp))
304*2d543d20SAndroid Build Coastguard Worker 		goto err;
305*2d543d20SAndroid Build Coastguard Worker 
306*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
307*2d543d20SAndroid Build Coastguard Worker 
308*2d543d20SAndroid Build Coastguard Worker out:
309*2d543d20SAndroid Build Coastguard Worker 	free(pkgname);
310*2d543d20SAndroid Build Coastguard Worker 	context_free(ctx);
311*2d543d20SAndroid Build Coastguard Worker 	return rc;
312*2d543d20SAndroid Build Coastguard Worker err:
313*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "%s:  Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
314*2d543d20SAndroid Build Coastguard Worker 				__FUNCTION__, pathname, pkgname, info ? info->seinfo : seinfo,
315*2d543d20SAndroid Build Coastguard Worker 				info ? info->uid : uid, strerror(errno));
316*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
317*2d543d20SAndroid Build Coastguard Worker 	goto out;
318*2d543d20SAndroid Build Coastguard Worker }
319*2d543d20SAndroid Build Coastguard Worker 
320*2d543d20SAndroid Build Coastguard Worker #define RESTORECON_PARTIAL_MATCH_DIGEST  "security.sehash"
321*2d543d20SAndroid Build Coastguard Worker 
restorecon_sb(const char * pathname,const struct stat * sb,bool nochange,bool verbose,const char * seinfo,uid_t uid)322*2d543d20SAndroid Build Coastguard Worker static int restorecon_sb(const char *pathname,
323*2d543d20SAndroid Build Coastguard Worker 			 const struct stat *sb,
324*2d543d20SAndroid Build Coastguard Worker 			 bool nochange,
325*2d543d20SAndroid Build Coastguard Worker 			 bool verbose,
326*2d543d20SAndroid Build Coastguard Worker 			 const char *seinfo,
327*2d543d20SAndroid Build Coastguard Worker 			 uid_t uid)
328*2d543d20SAndroid Build Coastguard Worker {
329*2d543d20SAndroid Build Coastguard Worker 	char *secontext = NULL;
330*2d543d20SAndroid Build Coastguard Worker 	char *oldsecontext = NULL;
331*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
332*2d543d20SAndroid Build Coastguard Worker 
333*2d543d20SAndroid Build Coastguard Worker 	if (selabel_lookup(fc_sehandle, &secontext, pathname, sb->st_mode) < 0)
334*2d543d20SAndroid Build Coastguard Worker 		return 0;  /* no match, but not an error */
335*2d543d20SAndroid Build Coastguard Worker 
336*2d543d20SAndroid Build Coastguard Worker 	if (lgetfilecon(pathname, &oldsecontext) < 0)
337*2d543d20SAndroid Build Coastguard Worker 		goto err;
338*2d543d20SAndroid Build Coastguard Worker 
339*2d543d20SAndroid Build Coastguard Worker 	/*
340*2d543d20SAndroid Build Coastguard Worker 	 * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
341*2d543d20SAndroid Build Coastguard Worker 	 * and use pkgdir_selabel_lookup() instead. Files within those directories
342*2d543d20SAndroid Build Coastguard Worker 	 * have different labeling rules, based off of /seapp_contexts, and
343*2d543d20SAndroid Build Coastguard Worker 	 * installd is responsible for managing these labels instead of init.
344*2d543d20SAndroid Build Coastguard Worker 	 */
345*2d543d20SAndroid Build Coastguard Worker 	if (is_app_data_path(pathname)) {
346*2d543d20SAndroid Build Coastguard Worker 		if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
347*2d543d20SAndroid Build Coastguard Worker 			goto err;
348*2d543d20SAndroid Build Coastguard Worker 	}
349*2d543d20SAndroid Build Coastguard Worker 
350*2d543d20SAndroid Build Coastguard Worker 	if (strcmp(oldsecontext, secontext) != 0) {
351*2d543d20SAndroid Build Coastguard Worker 		if (verbose)
352*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_INFO,
353*2d543d20SAndroid Build Coastguard Worker 						"SELinux:  Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
354*2d543d20SAndroid Build Coastguard Worker 		if (!nochange) {
355*2d543d20SAndroid Build Coastguard Worker 			if (lsetfilecon(pathname, secontext) < 0)
356*2d543d20SAndroid Build Coastguard Worker 				goto err;
357*2d543d20SAndroid Build Coastguard Worker 		}
358*2d543d20SAndroid Build Coastguard Worker 	}
359*2d543d20SAndroid Build Coastguard Worker 
360*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
361*2d543d20SAndroid Build Coastguard Worker 
362*2d543d20SAndroid Build Coastguard Worker out:
363*2d543d20SAndroid Build Coastguard Worker 	freecon(oldsecontext);
364*2d543d20SAndroid Build Coastguard Worker 	freecon(secontext);
365*2d543d20SAndroid Build Coastguard Worker 	return rc;
366*2d543d20SAndroid Build Coastguard Worker 
367*2d543d20SAndroid Build Coastguard Worker err:
368*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR,
369*2d543d20SAndroid Build Coastguard Worker 				"SELinux: Could not set context for %s:  %s\n",
370*2d543d20SAndroid Build Coastguard Worker 				pathname, strerror(errno));
371*2d543d20SAndroid Build Coastguard Worker 	rc = -1;
372*2d543d20SAndroid Build Coastguard Worker 	goto out;
373*2d543d20SAndroid Build Coastguard Worker }
374*2d543d20SAndroid Build Coastguard Worker 
375*2d543d20SAndroid Build Coastguard Worker #define SYS_PATH "/sys"
376*2d543d20SAndroid Build Coastguard Worker #define SYS_PREFIX SYS_PATH "/"
377*2d543d20SAndroid Build Coastguard Worker 
378*2d543d20SAndroid Build Coastguard Worker struct dir_hash_node {
379*2d543d20SAndroid Build Coastguard Worker 	char* path;
380*2d543d20SAndroid Build Coastguard Worker 	uint8_t digest[SHA1_HASH_SIZE];
381*2d543d20SAndroid Build Coastguard Worker 	struct dir_hash_node *next;
382*2d543d20SAndroid Build Coastguard Worker };
383*2d543d20SAndroid Build Coastguard Worker 
384*2d543d20SAndroid Build Coastguard Worker // Returns true if the digest of all partial matched contexts is the same as the one
385*2d543d20SAndroid Build Coastguard Worker // saved by setxattr. Otherwise returns false and constructs a dir_hash_node with the
386*2d543d20SAndroid Build Coastguard Worker // newly calculated digest.
check_context_match_for_dir(const char * pathname,struct dir_hash_node ** new_node,bool force,int error)387*2d543d20SAndroid Build Coastguard Worker static bool check_context_match_for_dir(const char *pathname,
388*2d543d20SAndroid Build Coastguard Worker 					struct dir_hash_node **new_node,
389*2d543d20SAndroid Build Coastguard Worker 					bool force, int error)
390*2d543d20SAndroid Build Coastguard Worker {
391*2d543d20SAndroid Build Coastguard Worker 	uint8_t read_digest[SHA1_HASH_SIZE];
392*2d543d20SAndroid Build Coastguard Worker 	ssize_t read_size = getxattr(pathname, RESTORECON_PARTIAL_MATCH_DIGEST,
393*2d543d20SAndroid Build Coastguard Worker 					 read_digest, SHA1_HASH_SIZE);
394*2d543d20SAndroid Build Coastguard Worker 	uint8_t calculated_digest[SHA1_HASH_SIZE];
395*2d543d20SAndroid Build Coastguard Worker 	bool status = selabel_hash_all_partial_matches(fc_sehandle, pathname,
396*2d543d20SAndroid Build Coastguard Worker 						       calculated_digest);
397*2d543d20SAndroid Build Coastguard Worker 
398*2d543d20SAndroid Build Coastguard Worker 	if (!new_node) {
399*2d543d20SAndroid Build Coastguard Worker 		return false;
400*2d543d20SAndroid Build Coastguard Worker 	}
401*2d543d20SAndroid Build Coastguard Worker 	*new_node = NULL;
402*2d543d20SAndroid Build Coastguard Worker 	if (!force && status && read_size == SHA1_HASH_SIZE &&
403*2d543d20SAndroid Build Coastguard Worker 		memcmp(read_digest, calculated_digest, SHA1_HASH_SIZE) == 0) {
404*2d543d20SAndroid Build Coastguard Worker 		return true;
405*2d543d20SAndroid Build Coastguard Worker 	}
406*2d543d20SAndroid Build Coastguard Worker 
407*2d543d20SAndroid Build Coastguard Worker 	// Save the digest of all matched contexts for the current directory.
408*2d543d20SAndroid Build Coastguard Worker 	if (!error && status) {
409*2d543d20SAndroid Build Coastguard Worker 		*new_node = calloc(1, sizeof(struct dir_hash_node));
410*2d543d20SAndroid Build Coastguard Worker 		if (*new_node == NULL) {
411*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
412*2d543d20SAndroid Build Coastguard Worker 						"SELinux: %s: Out of memory\n", __func__);
413*2d543d20SAndroid Build Coastguard Worker 			return false;
414*2d543d20SAndroid Build Coastguard Worker 		}
415*2d543d20SAndroid Build Coastguard Worker 
416*2d543d20SAndroid Build Coastguard Worker 		(*new_node)->path = strdup(pathname);
417*2d543d20SAndroid Build Coastguard Worker 		if ((*new_node)->path == NULL) {
418*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
419*2d543d20SAndroid Build Coastguard Worker 						"SELinux: %s: Out of memory\n", __func__);
420*2d543d20SAndroid Build Coastguard Worker 			free(*new_node);
421*2d543d20SAndroid Build Coastguard Worker 			*new_node = NULL;
422*2d543d20SAndroid Build Coastguard Worker 			return false;
423*2d543d20SAndroid Build Coastguard Worker 		}
424*2d543d20SAndroid Build Coastguard Worker 		memcpy((*new_node)->digest, calculated_digest, SHA1_HASH_SIZE);
425*2d543d20SAndroid Build Coastguard Worker 		(*new_node)->next = NULL;
426*2d543d20SAndroid Build Coastguard Worker 	}
427*2d543d20SAndroid Build Coastguard Worker 
428*2d543d20SAndroid Build Coastguard Worker 	return false;
429*2d543d20SAndroid Build Coastguard Worker }
430*2d543d20SAndroid Build Coastguard Worker 
selinux_android_restorecon_common(const char * pathname_orig,const char * seinfo,uid_t uid,unsigned int flags)431*2d543d20SAndroid Build Coastguard Worker static int selinux_android_restorecon_common(const char* pathname_orig,
432*2d543d20SAndroid Build Coastguard Worker 					     const char *seinfo,
433*2d543d20SAndroid Build Coastguard Worker 					     uid_t uid,
434*2d543d20SAndroid Build Coastguard Worker 					     unsigned int flags)
435*2d543d20SAndroid Build Coastguard Worker {
436*2d543d20SAndroid Build Coastguard Worker 	bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
437*2d543d20SAndroid Build Coastguard Worker 	bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
438*2d543d20SAndroid Build Coastguard Worker 	bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
439*2d543d20SAndroid Build Coastguard Worker 	bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
440*2d543d20SAndroid Build Coastguard Worker 	bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
441*2d543d20SAndroid Build Coastguard Worker 	bool skipce = (flags & SELINUX_ANDROID_RESTORECON_SKIPCE) ? true : false;
442*2d543d20SAndroid Build Coastguard Worker 	bool cross_filesystems = (flags & SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS) ? true : false;
443*2d543d20SAndroid Build Coastguard Worker 	bool setrestoreconlast = (flags & SELINUX_ANDROID_RESTORECON_SKIP_SEHASH) ? false : true;
444*2d543d20SAndroid Build Coastguard Worker 	bool issys;
445*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
446*2d543d20SAndroid Build Coastguard Worker 	struct statfs sfsb;
447*2d543d20SAndroid Build Coastguard Worker 	FTS *fts;
448*2d543d20SAndroid Build Coastguard Worker 	FTSENT *ftsent;
449*2d543d20SAndroid Build Coastguard Worker 	char *pathname = NULL, *pathdnamer = NULL, *pathdname, *pathbname;
450*2d543d20SAndroid Build Coastguard Worker 	char * paths[2] = { NULL , NULL };
451*2d543d20SAndroid Build Coastguard Worker 	int ftsflags = FTS_NOCHDIR | FTS_PHYSICAL;
452*2d543d20SAndroid Build Coastguard Worker 	int error, sverrno;
453*2d543d20SAndroid Build Coastguard Worker 	struct dir_hash_node *current = NULL;
454*2d543d20SAndroid Build Coastguard Worker 	struct dir_hash_node *head = NULL;
455*2d543d20SAndroid Build Coastguard Worker 
456*2d543d20SAndroid Build Coastguard Worker 	if (!cross_filesystems) {
457*2d543d20SAndroid Build Coastguard Worker 		ftsflags |= FTS_XDEV;
458*2d543d20SAndroid Build Coastguard Worker 	}
459*2d543d20SAndroid Build Coastguard Worker 
460*2d543d20SAndroid Build Coastguard Worker 	if (is_selinux_enabled() <= 0) {
461*2d543d20SAndroid Build Coastguard Worker 		selinux_log(SELINUX_WARNING, "SELinux: SELinux is disabled, skipping restorecon");
462*2d543d20SAndroid Build Coastguard Worker 		return 0;
463*2d543d20SAndroid Build Coastguard Worker 	}
464*2d543d20SAndroid Build Coastguard Worker 
465*2d543d20SAndroid Build Coastguard Worker 	__selinux_once(fc_once, file_context_init);
466*2d543d20SAndroid Build Coastguard Worker 
467*2d543d20SAndroid Build Coastguard Worker 	if (!fc_sehandle)
468*2d543d20SAndroid Build Coastguard Worker 		return 0;
469*2d543d20SAndroid Build Coastguard Worker 
470*2d543d20SAndroid Build Coastguard Worker 	/*
471*2d543d20SAndroid Build Coastguard Worker 	 * Convert passed-in pathname to canonical pathname by resolving realpath of
472*2d543d20SAndroid Build Coastguard Worker 	 * containing dir, then appending last component name.
473*2d543d20SAndroid Build Coastguard Worker 	 */
474*2d543d20SAndroid Build Coastguard Worker 	pathbname = basename(pathname_orig);
475*2d543d20SAndroid Build Coastguard Worker 	if (!strcmp(pathbname, "/") || !strcmp(pathbname, ".") || !strcmp(pathbname, "..")) {
476*2d543d20SAndroid Build Coastguard Worker 		pathname = realpath(pathname_orig, NULL);
477*2d543d20SAndroid Build Coastguard Worker 		if (!pathname)
478*2d543d20SAndroid Build Coastguard Worker 			goto realpatherr;
479*2d543d20SAndroid Build Coastguard Worker 	} else {
480*2d543d20SAndroid Build Coastguard Worker 		pathdname = dirname(pathname_orig);
481*2d543d20SAndroid Build Coastguard Worker 		pathdnamer = realpath(pathdname, NULL);
482*2d543d20SAndroid Build Coastguard Worker 		if (!pathdnamer)
483*2d543d20SAndroid Build Coastguard Worker 			goto realpatherr;
484*2d543d20SAndroid Build Coastguard Worker 		if (!strcmp(pathdnamer, "/"))
485*2d543d20SAndroid Build Coastguard Worker 			error = asprintf(&pathname, "/%s", pathbname);
486*2d543d20SAndroid Build Coastguard Worker 		else
487*2d543d20SAndroid Build Coastguard Worker 			error = asprintf(&pathname, "%s/%s", pathdnamer, pathbname);
488*2d543d20SAndroid Build Coastguard Worker 		if (error < 0)
489*2d543d20SAndroid Build Coastguard Worker 			goto oom;
490*2d543d20SAndroid Build Coastguard Worker 	}
491*2d543d20SAndroid Build Coastguard Worker 
492*2d543d20SAndroid Build Coastguard Worker 	paths[0] = pathname;
493*2d543d20SAndroid Build Coastguard Worker 	issys = (!strcmp(pathname, SYS_PATH)
494*2d543d20SAndroid Build Coastguard Worker 			|| !strncmp(pathname, SYS_PREFIX, sizeof(SYS_PREFIX)-1)) ? true : false;
495*2d543d20SAndroid Build Coastguard Worker 
496*2d543d20SAndroid Build Coastguard Worker 	if (!recurse) {
497*2d543d20SAndroid Build Coastguard Worker 		if (lstat(pathname, &sb) < 0) {
498*2d543d20SAndroid Build Coastguard Worker 			error = -1;
499*2d543d20SAndroid Build Coastguard Worker 			goto cleanup;
500*2d543d20SAndroid Build Coastguard Worker 		}
501*2d543d20SAndroid Build Coastguard Worker 
502*2d543d20SAndroid Build Coastguard Worker 		error = restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
503*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
504*2d543d20SAndroid Build Coastguard Worker 	}
505*2d543d20SAndroid Build Coastguard Worker 
506*2d543d20SAndroid Build Coastguard Worker 	/*
507*2d543d20SAndroid Build Coastguard Worker 	 * Ignore saved partial match digest on /data/data or /data/user
508*2d543d20SAndroid Build Coastguard Worker 	 * since their labeling is based on seapp_contexts and seinfo
509*2d543d20SAndroid Build Coastguard Worker 	 * assignments rather than file_contexts and is managed by
510*2d543d20SAndroid Build Coastguard Worker 	 * installd rather than init.
511*2d543d20SAndroid Build Coastguard Worker 	 */
512*2d543d20SAndroid Build Coastguard Worker 	if (is_app_data_path(pathname))
513*2d543d20SAndroid Build Coastguard Worker 		setrestoreconlast = false;
514*2d543d20SAndroid Build Coastguard Worker 
515*2d543d20SAndroid Build Coastguard Worker 	/* Also ignore on /sys since it is regenerated on each boot regardless. */
516*2d543d20SAndroid Build Coastguard Worker 	if (issys)
517*2d543d20SAndroid Build Coastguard Worker 		setrestoreconlast = false;
518*2d543d20SAndroid Build Coastguard Worker 
519*2d543d20SAndroid Build Coastguard Worker 	/* Ignore files on in-memory filesystems */
520*2d543d20SAndroid Build Coastguard Worker 	if (statfs(pathname, &sfsb) == 0) {
521*2d543d20SAndroid Build Coastguard Worker 		if (sfsb.f_type == RAMFS_MAGIC || sfsb.f_type == TMPFS_MAGIC)
522*2d543d20SAndroid Build Coastguard Worker 			setrestoreconlast = false;
523*2d543d20SAndroid Build Coastguard Worker 	}
524*2d543d20SAndroid Build Coastguard Worker 
525*2d543d20SAndroid Build Coastguard Worker 	fts = fts_open(paths, ftsflags, NULL);
526*2d543d20SAndroid Build Coastguard Worker 	if (!fts) {
527*2d543d20SAndroid Build Coastguard Worker 		error = -1;
528*2d543d20SAndroid Build Coastguard Worker 		goto cleanup;
529*2d543d20SAndroid Build Coastguard Worker 	}
530*2d543d20SAndroid Build Coastguard Worker 
531*2d543d20SAndroid Build Coastguard Worker 	error = 0;
532*2d543d20SAndroid Build Coastguard Worker 	while ((ftsent = fts_read(fts)) != NULL) {
533*2d543d20SAndroid Build Coastguard Worker 		switch (ftsent->fts_info) {
534*2d543d20SAndroid Build Coastguard Worker 		case FTS_DC:
535*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
536*2d543d20SAndroid Build Coastguard Worker 						"SELinux:  Directory cycle on %s.\n", ftsent->fts_path);
537*2d543d20SAndroid Build Coastguard Worker 			errno = ELOOP;
538*2d543d20SAndroid Build Coastguard Worker 			error = -1;
539*2d543d20SAndroid Build Coastguard Worker 			goto out;
540*2d543d20SAndroid Build Coastguard Worker 		case FTS_DP:
541*2d543d20SAndroid Build Coastguard Worker 			continue;
542*2d543d20SAndroid Build Coastguard Worker 		case FTS_DNR:
543*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
544*2d543d20SAndroid Build Coastguard Worker 						"SELinux:  Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
545*2d543d20SAndroid Build Coastguard Worker 			fts_set(fts, ftsent, FTS_SKIP);
546*2d543d20SAndroid Build Coastguard Worker 			continue;
547*2d543d20SAndroid Build Coastguard Worker 		case FTS_NS:
548*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
549*2d543d20SAndroid Build Coastguard Worker 						"SELinux:  Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
550*2d543d20SAndroid Build Coastguard Worker 			fts_set(fts, ftsent, FTS_SKIP);
551*2d543d20SAndroid Build Coastguard Worker 			continue;
552*2d543d20SAndroid Build Coastguard Worker 		case FTS_ERR:
553*2d543d20SAndroid Build Coastguard Worker 			selinux_log(SELINUX_ERROR,
554*2d543d20SAndroid Build Coastguard Worker 						"SELinux:  Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
555*2d543d20SAndroid Build Coastguard Worker 			fts_set(fts, ftsent, FTS_SKIP);
556*2d543d20SAndroid Build Coastguard Worker 			continue;
557*2d543d20SAndroid Build Coastguard Worker 		case FTS_D:
558*2d543d20SAndroid Build Coastguard Worker 			if (issys && !selabel_partial_match(fc_sehandle, ftsent->fts_path)) {
559*2d543d20SAndroid Build Coastguard Worker 				fts_set(fts, ftsent, FTS_SKIP);
560*2d543d20SAndroid Build Coastguard Worker 				continue;
561*2d543d20SAndroid Build Coastguard Worker 			}
562*2d543d20SAndroid Build Coastguard Worker 
563*2d543d20SAndroid Build Coastguard Worker 			if (!datadata && !fnmatch(USER_PROFILE_PATH, ftsent->fts_path, FNM_PATHNAME)) {
564*2d543d20SAndroid Build Coastguard Worker 				// Don't label this directory, vold takes care of that, but continue below it.
565*2d543d20SAndroid Build Coastguard Worker 				continue;
566*2d543d20SAndroid Build Coastguard Worker 			}
567*2d543d20SAndroid Build Coastguard Worker 
568*2d543d20SAndroid Build Coastguard Worker 			if (setrestoreconlast) {
569*2d543d20SAndroid Build Coastguard Worker 				struct dir_hash_node* new_node = NULL;
570*2d543d20SAndroid Build Coastguard Worker 				if (check_context_match_for_dir(ftsent->fts_path, &new_node, force, error)) {
571*2d543d20SAndroid Build Coastguard Worker 					selinux_log(SELINUX_INFO,
572*2d543d20SAndroid Build Coastguard Worker 								"SELinux: Skipping restorecon on directory(%s)\n",
573*2d543d20SAndroid Build Coastguard Worker 								ftsent->fts_path);
574*2d543d20SAndroid Build Coastguard Worker 					fts_set(fts, ftsent, FTS_SKIP);
575*2d543d20SAndroid Build Coastguard Worker 					continue;
576*2d543d20SAndroid Build Coastguard Worker 				}
577*2d543d20SAndroid Build Coastguard Worker 				if (new_node) {
578*2d543d20SAndroid Build Coastguard Worker 					if (!current) {
579*2d543d20SAndroid Build Coastguard Worker 						current = new_node;
580*2d543d20SAndroid Build Coastguard Worker 						head = current;
581*2d543d20SAndroid Build Coastguard Worker 					} else {
582*2d543d20SAndroid Build Coastguard Worker 						current->next = new_node;
583*2d543d20SAndroid Build Coastguard Worker 						current = current->next;
584*2d543d20SAndroid Build Coastguard Worker 					}
585*2d543d20SAndroid Build Coastguard Worker 				}
586*2d543d20SAndroid Build Coastguard Worker 			}
587*2d543d20SAndroid Build Coastguard Worker 
588*2d543d20SAndroid Build Coastguard Worker 			if (skipce && is_credential_encrypted_path(ftsent->fts_path)) {
589*2d543d20SAndroid Build Coastguard Worker 				// Don't label anything below this directory.
590*2d543d20SAndroid Build Coastguard Worker 				fts_set(fts, ftsent, FTS_SKIP);
591*2d543d20SAndroid Build Coastguard Worker 				// but fall through and make sure we label the directory itself
592*2d543d20SAndroid Build Coastguard Worker 			}
593*2d543d20SAndroid Build Coastguard Worker 
594*2d543d20SAndroid Build Coastguard Worker 			if (!datadata && is_app_data_path(ftsent->fts_path)) {
595*2d543d20SAndroid Build Coastguard Worker 				// Don't label anything below this directory.
596*2d543d20SAndroid Build Coastguard Worker 				fts_set(fts, ftsent, FTS_SKIP);
597*2d543d20SAndroid Build Coastguard Worker 				// but fall through and make sure we label the directory itself
598*2d543d20SAndroid Build Coastguard Worker 			}
599*2d543d20SAndroid Build Coastguard Worker 			/* fall through */
600*2d543d20SAndroid Build Coastguard Worker 		default:
601*2d543d20SAndroid Build Coastguard Worker 			error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
602*2d543d20SAndroid Build Coastguard Worker 			break;
603*2d543d20SAndroid Build Coastguard Worker 		}
604*2d543d20SAndroid Build Coastguard Worker 	}
605*2d543d20SAndroid Build Coastguard Worker 
606*2d543d20SAndroid Build Coastguard Worker 	// Labeling successful. Write the partial match digests for subdirectories.
607*2d543d20SAndroid Build Coastguard Worker 	// TODO: Write the digest upon FTS_DP if no error occurs in its descents.
608*2d543d20SAndroid Build Coastguard Worker 	if (setrestoreconlast && !nochange && !error) {
609*2d543d20SAndroid Build Coastguard Worker 		current = head;
610*2d543d20SAndroid Build Coastguard Worker 		while (current != NULL) {
611*2d543d20SAndroid Build Coastguard Worker 			if (setxattr(current->path, RESTORECON_PARTIAL_MATCH_DIGEST, current->digest,
612*2d543d20SAndroid Build Coastguard Worker 					SHA1_HASH_SIZE, 0) < 0) {
613*2d543d20SAndroid Build Coastguard Worker 				selinux_log(SELINUX_ERROR,
614*2d543d20SAndroid Build Coastguard Worker 							"SELinux:  setxattr failed: %s:  %s\n",
615*2d543d20SAndroid Build Coastguard Worker 							current->path,
616*2d543d20SAndroid Build Coastguard Worker 							strerror(errno));
617*2d543d20SAndroid Build Coastguard Worker 			}
618*2d543d20SAndroid Build Coastguard Worker 			current = current->next;
619*2d543d20SAndroid Build Coastguard Worker 		}
620*2d543d20SAndroid Build Coastguard Worker 	}
621*2d543d20SAndroid Build Coastguard Worker 
622*2d543d20SAndroid Build Coastguard Worker out:
623*2d543d20SAndroid Build Coastguard Worker 	sverrno = errno;
624*2d543d20SAndroid Build Coastguard Worker 	(void) fts_close(fts);
625*2d543d20SAndroid Build Coastguard Worker 	errno = sverrno;
626*2d543d20SAndroid Build Coastguard Worker cleanup:
627*2d543d20SAndroid Build Coastguard Worker 	free(pathdnamer);
628*2d543d20SAndroid Build Coastguard Worker 	free(pathname);
629*2d543d20SAndroid Build Coastguard Worker 	current = head;
630*2d543d20SAndroid Build Coastguard Worker 	while (current != NULL) {
631*2d543d20SAndroid Build Coastguard Worker 		struct dir_hash_node *next = current->next;
632*2d543d20SAndroid Build Coastguard Worker 		free(current->path);
633*2d543d20SAndroid Build Coastguard Worker 		free(current);
634*2d543d20SAndroid Build Coastguard Worker 		current = next;
635*2d543d20SAndroid Build Coastguard Worker 	}
636*2d543d20SAndroid Build Coastguard Worker 	return error;
637*2d543d20SAndroid Build Coastguard Worker oom:
638*2d543d20SAndroid Build Coastguard Worker 	sverrno = errno;
639*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
640*2d543d20SAndroid Build Coastguard Worker 	errno = sverrno;
641*2d543d20SAndroid Build Coastguard Worker 	error = -1;
642*2d543d20SAndroid Build Coastguard Worker 	goto cleanup;
643*2d543d20SAndroid Build Coastguard Worker realpatherr:
644*2d543d20SAndroid Build Coastguard Worker 	sverrno = errno;
645*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "SELinux: Could not get canonical path for %s restorecon: %s.\n",
646*2d543d20SAndroid Build Coastguard Worker 			pathname_orig, strerror(errno));
647*2d543d20SAndroid Build Coastguard Worker 	errno = sverrno;
648*2d543d20SAndroid Build Coastguard Worker 	error = -1;
649*2d543d20SAndroid Build Coastguard Worker 	goto cleanup;
650*2d543d20SAndroid Build Coastguard Worker }
651*2d543d20SAndroid Build Coastguard Worker 
selinux_android_restorecon(const char * file,unsigned int flags)652*2d543d20SAndroid Build Coastguard Worker int selinux_android_restorecon(const char *file, unsigned int flags)
653*2d543d20SAndroid Build Coastguard Worker {
654*2d543d20SAndroid Build Coastguard Worker 	return selinux_android_restorecon_common(file, NULL, -1, flags);
655*2d543d20SAndroid Build Coastguard Worker }
656*2d543d20SAndroid Build Coastguard Worker 
selinux_android_restorecon_pkgdir(const char * pkgdir,const char * seinfo,uid_t uid,unsigned int flags)657*2d543d20SAndroid Build Coastguard Worker int selinux_android_restorecon_pkgdir(const char *pkgdir,
658*2d543d20SAndroid Build Coastguard Worker 				      const char *seinfo,
659*2d543d20SAndroid Build Coastguard Worker 				      uid_t uid,
660*2d543d20SAndroid Build Coastguard Worker 				      unsigned int flags)
661*2d543d20SAndroid Build Coastguard Worker {
662*2d543d20SAndroid Build Coastguard Worker 	return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
663*2d543d20SAndroid Build Coastguard Worker }
664*2d543d20SAndroid Build Coastguard Worker 
665*2d543d20SAndroid Build Coastguard Worker 
selinux_android_set_sehandle(const struct selabel_handle * hndl)666*2d543d20SAndroid Build Coastguard Worker void selinux_android_set_sehandle(const struct selabel_handle *hndl)
667*2d543d20SAndroid Build Coastguard Worker {
668*2d543d20SAndroid Build Coastguard Worker 	fc_sehandle = (struct selabel_handle *) hndl;
669*2d543d20SAndroid Build Coastguard Worker }
670*2d543d20SAndroid Build Coastguard Worker 
selinux_android_load_policy()671*2d543d20SAndroid Build Coastguard Worker int selinux_android_load_policy()
672*2d543d20SAndroid Build Coastguard Worker {
673*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "selinux_android_load_policy is not implemented\n");
674*2d543d20SAndroid Build Coastguard Worker 	return -1;
675*2d543d20SAndroid Build Coastguard Worker }
676*2d543d20SAndroid Build Coastguard Worker 
selinux_android_load_policy_from_fd(int fd,const char * description)677*2d543d20SAndroid Build Coastguard Worker int selinux_android_load_policy_from_fd(int fd __attribute__((unused)), const char *description __attribute__((unused)))
678*2d543d20SAndroid Build Coastguard Worker {
679*2d543d20SAndroid Build Coastguard Worker 	selinux_log(SELINUX_ERROR, "selinux_android_load_policy_from_fd is not implemented\n");
680*2d543d20SAndroid Build Coastguard Worker 	return -1;
681*2d543d20SAndroid Build Coastguard Worker }
682