impl-link: only check permission changes for owners

When the permissions change on a node for a client, only check the
link permissions if the nodes of the link belong to the client.

Otherwise, we might destroy a link when the permissions are removed
from a node for an unrelated client.
This commit is contained in:
Wim Taymans 2023-07-20 15:20:29 +02:00
parent 86a52ea7b5
commit be9c6b1842

View file

@ -1149,7 +1149,7 @@ static int check_owner_permissions(struct pw_context *context,
return -EIO; return -EIO;
if ((global = pw_context_find_global(context, client_id)) == NULL) if ((global = pw_context_find_global(context, client_id)) == NULL)
/* current client can't see the owner client */ /* current client can't see the owner client */
return -ENOENT; return -errno;
if (!pw_global_is_type(global, PW_TYPE_INTERFACE_Client) || if (!pw_global_is_type(global, PW_TYPE_INTERFACE_Client) ||
(client = global->object) == NULL) (client = global->object) == NULL)
/* not the right object, something wrong */ /* not the right object, something wrong */
@ -1157,7 +1157,7 @@ static int check_owner_permissions(struct pw_context *context,
if ((global = pw_context_find_global(context, id)) == NULL) if ((global = pw_context_find_global(context, id)) == NULL)
/* current client can't see node id */ /* current client can't see node id */
return -ENOENT; return -errno;
perms = pw_global_get_permissions(global, client); perms = pw_global_get_permissions(global, client);
if ((perms & permissions) != permissions) if ((perms & permissions) != permissions)
@ -1186,6 +1186,7 @@ check_permission(struct pw_context *context,
static void permissions_changed(struct pw_impl_link *this, struct pw_impl_port *other, static void permissions_changed(struct pw_impl_link *this, struct pw_impl_port *other,
struct pw_impl_client *client, uint32_t old, uint32_t new) struct pw_impl_client *client, uint32_t old, uint32_t new)
{ {
int res;
uint32_t perm; uint32_t perm;
perm = pw_global_get_permissions(other->global, client); perm = pw_global_get_permissions(other->global, client);
@ -1193,17 +1194,36 @@ static void permissions_changed(struct pw_impl_link *this, struct pw_impl_port *
new &= perm; new &= perm;
pw_log_debug("%p: permissions changed %08x -> %08x", this, old, new); pw_log_debug("%p: permissions changed %08x -> %08x", this, old, new);
if (check_permission(this->context, this->output, this->input, this->properties) < 0) { if ((res = check_permission(this->context, this->output, this->input, this->properties)) < 0) {
pw_log_info("%p: link permissions removed: %s", this, spa_strerror(res));
pw_impl_link_destroy(this); pw_impl_link_destroy(this);
} else if (this->global != NULL) { } else if (this->global != NULL) {
pw_global_update_permissions(this->global, client, old, new); pw_global_update_permissions(this->global, client, old, new);
} }
} }
static bool is_port_owner(struct pw_impl_client *client, struct pw_impl_port *port)
{
const char *str;
uint32_t client_id;
str = pw_properties_get(port->node->properties, PW_KEY_CLIENT_ID);
if (str == NULL)
return false;
if (!spa_atou32(str, &client_id, 0))
return false;
return client_id == client->info.id;
}
static void output_permissions_changed(void *data, static void output_permissions_changed(void *data,
struct pw_impl_client *client, uint32_t old, uint32_t new) struct pw_impl_client *client, uint32_t old, uint32_t new)
{ {
struct pw_impl_link *this = data; struct pw_impl_link *this = data;
if (!is_port_owner(client, this->output) &&
!is_port_owner(client, this->input))
return;
permissions_changed(this, this->input, client, old, new); permissions_changed(this, this->input, client, old, new);
} }
@ -1216,6 +1236,9 @@ static void input_permissions_changed(void *data,
struct pw_impl_client *client, uint32_t old, uint32_t new) struct pw_impl_client *client, uint32_t old, uint32_t new)
{ {
struct pw_impl_link *this = data; struct pw_impl_link *this = data;
if (!is_port_owner(client, this->output) &&
!is_port_owner(client, this->input))
return;
permissions_changed(this, this->output, client, old, new); permissions_changed(this, this->output, client, old, new);
} }