mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	module-access: determine trusted application executable
Determine application executable file so that the result can be trusted, and the file exists in the current namespace. Don't use /proc/pid/cmdline, since that contains whatever was specified by the exec() call.
This commit is contained in:
		
							parent
							
								
									64235419a6
								
							
						
					
					
						commit
						0e831c52d8
					
				
					 1 changed files with 54 additions and 30 deletions
				
			
		| 
						 | 
				
			
			@ -131,41 +131,57 @@ struct impl {
 | 
			
		|||
	struct spa_hook module_listener;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int check_cmdline(struct pw_impl_client *client, int pid, const char *str)
 | 
			
		||||
static int get_exe_name(int pid, char *buf, size_t buf_size)
 | 
			
		||||
{
 | 
			
		||||
	char path[2048], key[1024];
 | 
			
		||||
	ssize_t len;
 | 
			
		||||
	int fd, res;
 | 
			
		||||
	char path[256];
 | 
			
		||||
	struct stat s1, s2;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Find executable name, checking it is an existing file
 | 
			
		||||
	 * (in the current namespace).
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
#if defined(__linux__)
 | 
			
		||||
	spa_scnprintf(path, sizeof(path), "/proc/%u/exe", pid);
 | 
			
		||||
#elif defined(__FreeBSD__) || defined(__MidnightBSD__)
 | 
			
		||||
	spa_scnprintf(path, sizeof(path), "/proc/%u/file", pid);
 | 
			
		||||
#else
 | 
			
		||||
	return -ENOTSUP;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	res = readlink(path, buf, buf_size);
 | 
			
		||||
	if (res < 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	if ((size_t)res >= buf_size)
 | 
			
		||||
		return -E2BIG;
 | 
			
		||||
	buf[res] = '\0';
 | 
			
		||||
 | 
			
		||||
	/* Check the file exists (= not deleted, and is in current namespace) */
 | 
			
		||||
	if (stat(path, &s1) != 0 || stat(buf, &s2) != 0)
 | 
			
		||||
		return -errno;
 | 
			
		||||
	if (s1.st_dev != s2.st_dev || s1.st_ino != s2.st_ino)
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int check_exe(struct pw_impl_client *client, const char *path, const char *str)
 | 
			
		||||
{
 | 
			
		||||
	char key[1024];
 | 
			
		||||
	int res;
 | 
			
		||||
	struct spa_json it[2];
 | 
			
		||||
 | 
			
		||||
	sprintf(path, "/proc/%u/cmdline", pid);
 | 
			
		||||
 | 
			
		||||
	fd = open(path, O_RDONLY);
 | 
			
		||||
	if (fd < 0) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto exit;
 | 
			
		||||
	}
 | 
			
		||||
	if ((len = read(fd, path, sizeof(path)-1)) < 0) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto exit_close;
 | 
			
		||||
	}
 | 
			
		||||
	path[len] = '\0';
 | 
			
		||||
 | 
			
		||||
	spa_json_init(&it[0], str, strlen(str));
 | 
			
		||||
	if ((res = spa_json_enter_array(&it[0], &it[1])) <= 0)
 | 
			
		||||
		goto exit_close;
 | 
			
		||||
		return res;
 | 
			
		||||
 | 
			
		||||
	while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
 | 
			
		||||
		if (spa_streq(path, key)) {
 | 
			
		||||
			res = 1;
 | 
			
		||||
			goto exit_close;
 | 
			
		||||
		}
 | 
			
		||||
		if (spa_streq(path, key))
 | 
			
		||||
			return 1;
 | 
			
		||||
	}
 | 
			
		||||
	res = 0;
 | 
			
		||||
exit_close:
 | 
			
		||||
	close(fd);
 | 
			
		||||
exit:
 | 
			
		||||
	return res;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -174,6 +190,7 @@ context_check_access(void *data, struct pw_impl_client *client)
 | 
			
		|||
	struct impl *impl = data;
 | 
			
		||||
	struct pw_permission permissions[1];
 | 
			
		||||
	struct spa_dict_item items[2];
 | 
			
		||||
	char exe_path[PATH_MAX];
 | 
			
		||||
	const struct pw_properties *props;
 | 
			
		||||
	const char *str, *access;
 | 
			
		||||
	char *flatpak_app_id = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -195,10 +212,17 @@ context_check_access(void *data, struct pw_impl_client *client)
 | 
			
		|||
		goto granted;
 | 
			
		||||
	} else {
 | 
			
		||||
		pw_log_info("client %p has trusted pid %d", client, pid);
 | 
			
		||||
		if ((res = get_exe_name(pid, exe_path, sizeof(exe_path))) >= 0) {
 | 
			
		||||
			pw_log_info("client %p has trusted exe path '%s'", client, exe_path);
 | 
			
		||||
		} else {
 | 
			
		||||
			pw_log_info("client %p has no trusted exe path: %s",
 | 
			
		||||
					client, spa_strerror(res));
 | 
			
		||||
			exe_path[0] = '\0';
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (impl->properties && (str = pw_properties_get(impl->properties, "access.allowed")) != NULL) {
 | 
			
		||||
		res = check_cmdline(client, pid, str);
 | 
			
		||||
		res = check_exe(client, exe_path, str);
 | 
			
		||||
		if (res < 0) {
 | 
			
		||||
			pw_log_warn("%p: client %p allowed check failed: %s",
 | 
			
		||||
				impl, client, spa_strerror(res));
 | 
			
		||||
| 
						 | 
				
			
			@ -209,7 +233,7 @@ context_check_access(void *data, struct pw_impl_client *client)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (impl->properties && (str = pw_properties_get(impl->properties, "access.rejected")) != NULL) {
 | 
			
		||||
		res = check_cmdline(client, pid, str);
 | 
			
		||||
		res = check_exe(client, exe_path, str);
 | 
			
		||||
		if (res < 0) {
 | 
			
		||||
			pw_log_warn("%p: client %p rejected check failed: %s",
 | 
			
		||||
				impl, client, spa_strerror(res));
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +245,7 @@ context_check_access(void *data, struct pw_impl_client *client)
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	if (impl->properties && (str = pw_properties_get(impl->properties, "access.restricted")) != NULL) {
 | 
			
		||||
		res = check_cmdline(client, pid, str);
 | 
			
		||||
		res = check_exe(client, exe_path, str);
 | 
			
		||||
		if (res < 0) {
 | 
			
		||||
			pw_log_warn("%p: client %p restricted check failed: %s",
 | 
			
		||||
				impl, client, spa_strerror(res));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue