xref: /aosp_15_r20/external/selinux/libselinux/src/android/android.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1 #include <errno.h>
2 #include <fnmatch.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 
7 #include <log/log.h>
8 #include <selinux/android.h>
9 #include <selinux/label.h>
10 
11 #include "android_internal.h"
12 #include "callbacks.h"
13 
14 #ifdef __ANDROID_VNDK__
15 #ifndef LOG_EVENT_STRING
16 #define LOG_EVENT_STRING(...)
17 #endif  // LOG_EVENT_STRING
18 #endif  // __ANDROID_VNDK__
19 
20 static const path_alts_t service_context_paths = { .paths = {
21 	{
22 		"/system/etc/selinux/plat_service_contexts",
23 		"/plat_service_contexts"
24 	},
25 	{
26 		"/system_ext/etc/selinux/system_ext_service_contexts",
27 		"/system_ext_service_contexts"
28 	},
29 	{
30 		"/product/etc/selinux/product_service_contexts",
31 		"/product_service_contexts"
32 	},
33 	{
34 		"/vendor/etc/selinux/vendor_service_contexts",
35 		"/vendor_service_contexts"
36 	},
37 	{
38 		"/odm/etc/selinux/odm_service_contexts",
39 	}
40 }};
41 
42 static const path_alts_t hwservice_context_paths = { .paths = {
43 	{
44 		"/system/etc/selinux/plat_hwservice_contexts",
45 		"/plat_hwservice_contexts"
46 	},
47 	{
48 		"/system_ext/etc/selinux/system_ext_hwservice_contexts",
49 		"/system_ext_hwservice_contexts"
50 	},
51 	{
52 		"/product/etc/selinux/product_hwservice_contexts",
53 		"/product_hwservice_contexts"
54 	},
55 	{
56 		"/vendor/etc/selinux/vendor_hwservice_contexts",
57 		"/vendor_hwservice_contexts"
58 	},
59 	{
60 		"/odm/etc/selinux/odm_hwservice_contexts",
61 		"/odm_hwservice_contexts"
62 	},
63 }};
64 
65 static const path_alts_t vndservice_context_paths = { .paths = {
66 	{
67 		"/vendor/etc/selinux/vndservice_contexts",
68 		"/vndservice_contexts"
69 	}
70 }};
71 
72 static const path_alts_t keystore2_context_paths = { .paths = {
73 	{
74 		"/system/etc/selinux/plat_keystore2_key_contexts",
75 		"/plat_keystore2_key_contexts"
76 	},
77 	{
78 		"/system_ext/etc/selinux/system_ext_keystore2_key_contexts",
79 		"/system_ext_keystore2_key_contexts"
80 	},
81 	{
82 		"/product/etc/selinux/product_keystore2_key_contexts",
83 		"/product_keystore2_key_contexts"
84 	},
85 	{
86 		"/vendor/etc/selinux/vendor_keystore2_key_contexts",
87 		"/vendor_keystore2_key_contexts"
88 	}
89 }};
90 
91 static const path_alts_t tee_service_context_paths = { .paths = {
92 	{
93 		"/system/etc/selinux/plat_tee_service_contexts",
94 		"/plat_tee_service_contexts"
95 	},
96 	{
97 		"/system_ext/etc/selinux/system_ext_tee_service_contexts",
98 		"/system_ext_tee_service_contexts"
99 	},
100 	{
101 		"/product/etc/selinux/product_tee_service_contexts",
102 		"/product_tee_service_contexts"
103 	},
104 	{
105 		"/vendor/etc/selinux/vendor_tee_service_contexts",
106 		"/vendor_tee_service_contexts"
107 	}
108 }};
109 
find_existing_files(const path_alts_t * path_sets,const char * paths[MAX_CONTEXT_PATHS])110 size_t find_existing_files(
111 		const path_alts_t *path_sets,
112 		const char* paths[MAX_CONTEXT_PATHS])
113 {
114 	return find_existing_files_with_partitions(
115 		path_sets,
116 		paths,
117 		NULL
118 	);
119 }
120 
find_existing_files_with_partitions(const path_alts_t * path_sets,const char * paths[MAX_CONTEXT_PATHS],const char * partitions[MAX_CONTEXT_PATHS])121 size_t find_existing_files_with_partitions(
122 		const path_alts_t *path_sets,
123 		const char* paths[MAX_CONTEXT_PATHS],
124 		const char* partitions[MAX_CONTEXT_PATHS])
125 {
126 	size_t i, j, len = 0;
127 	for (i = 0; i < MAX_CONTEXT_PATHS; i++) {
128 		for (j = 0; j < MAX_ALT_CONTEXT_PATHS; j++) {
129 			const char* file = path_sets->paths[i][j];
130 			if (file && access(file, R_OK) != -1) {
131 				if (partitions) {
132 					partitions[len] = path_sets->partitions[i];
133 				}
134 				paths[len++] = file;
135 				/* Within each set, only the first valid entry is used */
136 				break;
137 			}
138 		}
139 	}
140 	return len;
141 }
142 
paths_to_opts(const char * paths[MAX_CONTEXT_PATHS],size_t npaths,struct selinux_opt * const opts)143 void paths_to_opts(const char* paths[MAX_CONTEXT_PATHS],
144 		size_t npaths,
145 		struct selinux_opt* const opts)
146 {
147 	for (size_t i = 0; i < npaths; i++) {
148 		opts[i].type = SELABEL_OPT_PATH;
149 		opts[i].value = paths[i];
150 	}
151 }
152 
initialize_backend(unsigned int backend,const char * name,const struct selinux_opt * opts,size_t nopts)153 struct selabel_handle* initialize_backend(
154 		unsigned int backend,
155 		const char* name,
156 		const struct selinux_opt* opts,
157 		size_t nopts)
158 {
159 		struct selabel_handle* sehandle;
160 
161 		sehandle = selabel_open(backend, opts, nopts);
162 
163 		if (!sehandle) {
164 				selinux_log(SELINUX_ERROR, "%s: Error getting %s handle (%s)\n",
165 								__FUNCTION__, name, strerror(errno));
166 				return NULL;
167 		}
168 		selinux_log(SELINUX_INFO, "SELinux: Loaded %s context from:\n", name);
169 		for (unsigned i = 0; i < nopts; i++) {
170 			if (opts[i].type == SELABEL_OPT_PATH)
171 				selinux_log(SELINUX_INFO, "		%s\n", opts[i].value);
172 		}
173 		return sehandle;
174 }
175 
context_handle(unsigned int backend,const path_alts_t * context_paths,const char * name)176 struct selabel_handle* context_handle(
177 		unsigned int backend,
178 		const path_alts_t *context_paths,
179 		const char *name)
180 {
181 	const char* existing_paths[MAX_CONTEXT_PATHS];
182 	struct selinux_opt opts[MAX_CONTEXT_PATHS];
183 	int size = 0;
184 
185 	size = find_existing_files(context_paths, existing_paths);
186 	paths_to_opts(existing_paths, size, opts);
187 
188 	return initialize_backend(backend, name, opts, size);
189 }
190 
selinux_android_service_context_handle(void)191 struct selabel_handle* selinux_android_service_context_handle(void)
192 {
193 	return context_handle(SELABEL_CTX_ANDROID_SERVICE, &service_context_paths, "service");
194 }
195 
selinux_android_hw_service_context_handle(void)196 struct selabel_handle* selinux_android_hw_service_context_handle(void)
197 {
198 	return context_handle(SELABEL_CTX_ANDROID_SERVICE, &hwservice_context_paths, "hwservice");
199 }
200 
selinux_android_vendor_service_context_handle(void)201 struct selabel_handle* selinux_android_vendor_service_context_handle(void)
202 {
203 	return context_handle(SELABEL_CTX_ANDROID_SERVICE, &vndservice_context_paths, "vndservice");
204 }
205 
selinux_android_keystore2_key_context_handle(void)206 struct selabel_handle* selinux_android_keystore2_key_context_handle(void)
207 {
208 	return context_handle(SELABEL_CTX_ANDROID_KEYSTORE2_KEY, &keystore2_context_paths, "keystore2");
209 }
210 
selinux_android_tee_service_context_handle(void)211 struct selabel_handle* selinux_android_tee_service_context_handle(void)
212 {
213 	return context_handle(SELABEL_CTX_ANDROID_SERVICE, &tee_service_context_paths, "tee_service");
214 }
215 
216 /* The contents of these paths are encrypted on FBE devices until user
217  * credentials are presented (filenames inside are mangled), so we need
218  * to delay restorecon of those until vold explicitly requests it. */
219 // NOTE: these paths need to be kept in sync with vold
220 #define DATA_SYSTEM_CE_PATH "/data/system_ce"
221 #define DATA_VENDOR_CE_PATH "/data/vendor_ce"
222 #define DATA_MISC_CE_PATH "/data/misc_ce"
223 
224 /* The path prefixes of package data directories. */
225 #define DATA_DATA_PATH "/data/data"
226 #define DATA_USER_PATH "/data/user"
227 #define DATA_USER_DE_PATH "/data/user_de"
228 #define DATA_MISC_DE_PATH "/data/misc_de"
229 #define DATA_STORAGE_AREA_PATH "/data/storage_area"
230 #define SDK_SANDBOX_DATA_CE_PATH "/data/misc_ce/*/sdksandbox"
231 #define SDK_SANDBOX_DATA_DE_PATH "/data/misc_de/*/sdksandbox"
232 
233 #define EXPAND_MNT_PATH "/mnt/expand/\?\?\?\?\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?-\?\?\?\?\?\?\?\?\?\?\?\?"
234 #define EXPAND_USER_PATH EXPAND_MNT_PATH "/user"
235 #define EXPAND_USER_DE_PATH EXPAND_MNT_PATH "/user_de"
236 #define EXPAND_SDK_CE_PATH EXPAND_MNT_PATH "/misc_ce/*/sdksandbox"
237 #define EXPAND_SDK_DE_PATH EXPAND_MNT_PATH "/misc_de/*/sdksandbox"
238 
239 #define DATA_DATA_PREFIX DATA_DATA_PATH "/"
240 #define DATA_USER_PREFIX DATA_USER_PATH "/"
241 #define DATA_USER_DE_PREFIX DATA_USER_DE_PATH "/"
242 #define DATA_STORAGE_AREA_PREFIX DATA_STORAGE_AREA_PATH "/"
243 #define DATA_MISC_CE_PREFIX DATA_MISC_CE_PATH "/"
244 #define DATA_MISC_DE_PREFIX DATA_MISC_DE_PATH "/"
245 #define EXPAND_MNT_PATH_PREFIX EXPAND_MNT_PATH "/"
246 
is_app_data_path(const char * pathname)247 bool is_app_data_path(const char *pathname) {
248 	int flags = FNM_LEADING_DIR|FNM_PATHNAME;
249 #ifdef SELINUX_FLAGS_DATA_DATA_IGNORE
250 	if (!strcmp(pathname, DATA_DATA_PATH)) {
251 		return true;
252 	}
253 #endif
254 	return (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
255 		!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1) ||
256 		!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1) ||
257 		!strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1) ||
258 		!fnmatch(EXPAND_USER_PATH, pathname, flags) ||
259 		!fnmatch(EXPAND_USER_DE_PATH, pathname, flags) ||
260 		!fnmatch(SDK_SANDBOX_DATA_CE_PATH, pathname, flags) ||
261 		!fnmatch(SDK_SANDBOX_DATA_DE_PATH, pathname, flags) ||
262 		!fnmatch(EXPAND_SDK_CE_PATH, pathname, flags) ||
263 		!fnmatch(EXPAND_SDK_DE_PATH, pathname, flags));
264 }
265 
is_credential_encrypted_path(const char * pathname)266 bool is_credential_encrypted_path(const char *pathname) {
267 	return !strncmp(pathname, DATA_SYSTEM_CE_PATH, sizeof(DATA_SYSTEM_CE_PATH)-1) ||
268 	       !strncmp(pathname, DATA_MISC_CE_PATH, sizeof(DATA_MISC_CE_PATH)-1) ||
269 	       !strncmp(pathname, DATA_VENDOR_CE_PATH, sizeof(DATA_VENDOR_CE_PATH)-1);
270 }
271 
272 /*
273  * Extract the userid from a path.
274  * On success, pathname is updated past the userid.
275  * Returns 0 on success, -1 on error
276  */
extract_userid(const char ** pathname,unsigned int * userid)277 static int extract_userid(const char **pathname, unsigned int *userid)
278 {
279 	char *end = NULL;
280 
281 	errno = 0;
282 	*userid = strtoul(*pathname, &end, 10);
283 	if (errno) {
284 		selinux_log(SELINUX_ERROR, "SELinux: Could not parse userid %s: %s.\n",
285 			*pathname, strerror(errno));
286 		return -1;
287 	}
288 	if (*pathname == end) {
289 		return -1;
290 	}
291 	if (*userid > 1000) {
292 		return -1;
293 	}
294 	*pathname = end;
295 	return 0;
296 }
297 
extract_pkgname_and_userid(const char * pathname,char ** pkgname,unsigned int * userid)298 int extract_pkgname_and_userid(const char *pathname, char **pkgname, unsigned int *userid)
299 {
300 	char *end = NULL;
301 
302 	if (pkgname == NULL || *pkgname != NULL || userid == NULL) {
303 		errno = EINVAL;
304 		return -2;
305 	}
306 
307 	/* Skip directory prefix before package name. */
308 	if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
309 		pathname += sizeof(DATA_DATA_PREFIX) - 1;
310 	} else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
311 		pathname += sizeof(DATA_USER_PREFIX) - 1;
312 		int rc = extract_userid(&pathname, userid);
313 		if (rc)
314 			return -1;
315 		if (*pathname == '/')
316 			pathname++;
317 		else
318 			return -1;
319 	} else if (!strncmp(pathname, DATA_USER_DE_PREFIX, sizeof(DATA_USER_DE_PREFIX)-1)) {
320 		pathname += sizeof(DATA_USER_DE_PREFIX) - 1;
321 		int rc = extract_userid(&pathname, userid);
322 		if (rc)
323 			return -1;
324 		if (*pathname == '/')
325 			pathname++;
326 		else
327 			return -1;
328 	} else if (!strncmp(pathname, DATA_STORAGE_AREA_PREFIX, sizeof(DATA_STORAGE_AREA_PREFIX)-1)) {
329 		pathname += sizeof(DATA_STORAGE_AREA_PREFIX) - 1;
330 		int rc = extract_userid(&pathname, userid);
331 		if (rc)
332 			return -1;
333 		if (*pathname == '/')
334 			pathname++;
335 		else
336 			return -1;
337 	} else if (!fnmatch(EXPAND_USER_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
338 		pathname += sizeof(EXPAND_USER_PATH);
339 		int rc = extract_userid(&pathname, userid);
340 		if (rc)
341 			return -1;
342 		if (*pathname == '/')
343 			pathname++;
344 		else
345 			return -1;
346 	} else if (!fnmatch(EXPAND_USER_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
347 		pathname += sizeof(EXPAND_USER_DE_PATH);
348 		int rc = extract_userid(&pathname, userid);
349 		if (rc)
350 			return -1;
351 		if (*pathname == '/')
352 			pathname++;
353 		else
354 			return -1;
355 	} else if (!strncmp(pathname, DATA_MISC_CE_PREFIX, sizeof(DATA_MISC_CE_PREFIX)-1)) {
356 		pathname += sizeof(DATA_MISC_CE_PREFIX) - 1;
357 		int rc = extract_userid(&pathname, userid);
358 		if (rc)
359 			return -1;
360 		if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
361 			pathname += sizeof("/sdksandbox/") - 1;
362 		else
363 			return -1;
364 	} else if (!strncmp(pathname, DATA_MISC_DE_PREFIX, sizeof(DATA_MISC_DE_PREFIX)-1)) {
365 		pathname += sizeof(DATA_MISC_DE_PREFIX) - 1;
366 		int rc = extract_userid(&pathname, userid);
367 		if (rc)
368 			return -1;
369 		if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
370 			pathname += sizeof("/sdksandbox/") - 1;
371 		else
372 			return -1;
373 	} else if (!fnmatch(EXPAND_SDK_CE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
374 		pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
375 		pathname += sizeof("misc_ce/") - 1;
376 		int rc = extract_userid(&pathname, userid);
377 		if (rc)
378 			return -1;
379 		if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
380 			pathname += sizeof("/sdksandbox/") - 1;
381 		else
382 			return -1;
383 	} else if (!fnmatch(EXPAND_SDK_DE_PATH, pathname, FNM_LEADING_DIR|FNM_PATHNAME)) {
384 		pathname += sizeof(EXPAND_MNT_PATH_PREFIX) - 1;
385 		pathname += sizeof("misc_de/") - 1;
386 		int rc = extract_userid(&pathname, userid);
387 		if (rc)
388 			return -1;
389 		if (!strncmp(pathname, "/sdksandbox/", sizeof("/sdksandbox/")-1))
390 			pathname += sizeof("/sdksandbox/") - 1;
391 		else
392 			return -1;
393 	} else
394 		return -1;
395 
396 	if (!(*pathname))
397 		return -1;
398 
399 	*pkgname = strdup(pathname);
400 	if (!(*pkgname))
401 		return -2;
402 
403 	// Trim pkgname.
404 	for (end = *pkgname; *end && *end != '/'; end++);
405 	*end = '\0';
406 
407 	return 0;
408 }
409 
__selinux_log_callback(bool add_to_event_log,int type,const char * fmt,va_list ap)410 static void __selinux_log_callback(bool add_to_event_log, int type, const char *fmt, va_list ap) {
411 	int priority;
412 	char *strp;
413 
414 	switch(type) {
415 	case SELINUX_WARNING:
416 		priority = ANDROID_LOG_WARN;
417 		break;
418 	case SELINUX_INFO:
419 		priority = ANDROID_LOG_INFO;
420 		break;
421 	default:
422 		priority = ANDROID_LOG_ERROR;
423 		break;
424 	}
425 
426 	int len = vasprintf(&strp, fmt, ap);
427 	if (len < 0) {
428 		return;
429 	}
430 
431 	/* libselinux log messages usually contain a new line character, while
432 	 * Android LOG() does not expect it. Remove it to avoid empty lines in
433 	 * the log buffers.
434 	 */
435 	if (len > 0 && strp[len - 1] == '\n') {
436 		strp[len - 1] = '\0';
437 	}
438 	LOG_PRI(priority, "SELinux", "%s", strp);
439 	if (add_to_event_log) {
440 		LOG_EVENT_STRING(AUDITD_LOG_TAG, strp);
441 	}
442 	free(strp);
443 }
444 
selinux_log_callback(int type,const char * fmt,...)445 int selinux_log_callback(int type, const char *fmt, ...)
446 {
447 	va_list ap;
448 	va_start(ap, fmt);
449 	__selinux_log_callback(true, type, fmt, ap);
450 	va_end(ap);
451 	return 0;
452 }
453 
selinux_vendor_log_callback(int type,const char * fmt,...)454 int selinux_vendor_log_callback(int type, const char *fmt, ...)
455 {
456 	va_list ap;
457 	va_start(ap, fmt);
458 	__selinux_log_callback(false, type, fmt, ap);
459 	va_end(ap);
460 	return 0;
461 }
462