mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-04 13:30:12 -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;
|
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];
|
char path[256];
|
||||||
ssize_t len;
|
struct stat s1, s2;
|
||||||
int fd, res;
|
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];
|
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));
|
spa_json_init(&it[0], str, strlen(str));
|
||||||
if ((res = spa_json_enter_array(&it[0], &it[1])) <= 0)
|
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) {
|
while (spa_json_get_string(&it[1], key, sizeof(key)) > 0) {
|
||||||
if (spa_streq(path, key)) {
|
if (spa_streq(path, key))
|
||||||
res = 1;
|
return 1;
|
||||||
goto exit_close;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
res = 0;
|
return 0;
|
||||||
exit_close:
|
|
||||||
close(fd);
|
|
||||||
exit:
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -174,6 +190,7 @@ context_check_access(void *data, struct pw_impl_client *client)
|
||||||
struct impl *impl = data;
|
struct impl *impl = data;
|
||||||
struct pw_permission permissions[1];
|
struct pw_permission permissions[1];
|
||||||
struct spa_dict_item items[2];
|
struct spa_dict_item items[2];
|
||||||
|
char exe_path[PATH_MAX];
|
||||||
const struct pw_properties *props;
|
const struct pw_properties *props;
|
||||||
const char *str, *access;
|
const char *str, *access;
|
||||||
char *flatpak_app_id = NULL;
|
char *flatpak_app_id = NULL;
|
||||||
|
|
@ -195,10 +212,17 @@ context_check_access(void *data, struct pw_impl_client *client)
|
||||||
goto granted;
|
goto granted;
|
||||||
} else {
|
} else {
|
||||||
pw_log_info("client %p has trusted pid %d", client, pid);
|
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) {
|
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) {
|
if (res < 0) {
|
||||||
pw_log_warn("%p: client %p allowed check failed: %s",
|
pw_log_warn("%p: client %p allowed check failed: %s",
|
||||||
impl, client, spa_strerror(res));
|
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) {
|
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) {
|
if (res < 0) {
|
||||||
pw_log_warn("%p: client %p rejected check failed: %s",
|
pw_log_warn("%p: client %p rejected check failed: %s",
|
||||||
impl, client, spa_strerror(res));
|
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) {
|
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) {
|
if (res < 0) {
|
||||||
pw_log_warn("%p: client %p restricted check failed: %s",
|
pw_log_warn("%p: client %p restricted check failed: %s",
|
||||||
impl, client, spa_strerror(res));
|
impl, client, spa_strerror(res));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue