context: move registry generation checks to context methods

Add registry generation checks to pw_context methods that find globals,
(pw_context_find_global, pw_context_for_each_global), so that they are
made everywhere where a client acquires globals.

In addition to previously covered registry bind/destroy, this also
covers link creation (port/node ids) and metadata (subject ids).
This commit is contained in:
Pauli Virtanen 2022-02-27 21:13:26 +02:00 committed by Wim Taymans
parent a59a551202
commit 651cb7bd71
3 changed files with 44 additions and 26 deletions

View file

@ -553,6 +553,19 @@ static bool global_can_read(struct pw_context *context, struct pw_global *global
return true;
}
static bool global_is_stale(struct pw_context *context, struct pw_global *global)
{
struct pw_impl_client *client = context->current_client;
if (!client)
return false;
if (client->recv_generation != 0 && global->generation > client->recv_generation)
return true;
return false;
}
SPA_EXPORT
int pw_context_for_each_global(struct pw_context *context,
int (*callback) (void *data, struct pw_global *global),
@ -562,7 +575,7 @@ int pw_context_for_each_global(struct pw_context *context,
int res;
spa_list_for_each_safe(g, t, &context->global_list, link) {
if (!global_can_read(context, g))
if (!global_can_read(context, g) || global_is_stale(context, g))
continue;
if ((res = callback(data, g)) != 0)
return res;
@ -581,6 +594,11 @@ struct pw_global *pw_context_find_global(struct pw_context *context, uint32_t id
return NULL;
}
if (global_is_stale(context, global)) {
errno = global_can_read(context, global) ? ESTALE : ENOENT;
return NULL;
}
if (!global_can_read(context, global)) {
errno = EACCES;
return NULL;

View file

@ -117,15 +117,16 @@ static int client_error(void *object, uint32_t id, int res, const char *error)
struct pw_impl_client *sender = resource->client;
struct pw_impl_client *client = data->client;
struct error_data d = { id, res, error };
struct pw_global *global;
/* Check the global id provided by sender refers to a registered global
* known to the sender.
*/
if ((global = pw_context_find_global(resource->context, id)) == NULL)
goto error_no_id;
if (sender->recv_generation != 0 && global->generation > sender->recv_generation)
goto error_stale_id;
if (pw_context_find_global(resource->context, id) == NULL) {
if (errno == ESTALE)
goto error_stale_id;
else
goto error_no_id;
}
pw_log_debug("%p: sender %p: error for global %u", client, sender, id);
pw_map_for_each(&client->objects, error_resource, &d);
@ -136,8 +137,8 @@ error_no_id:
pw_resource_errorf(resource, -ENOENT, "no global %u", id);
return -ENOENT;
error_stale_id:
pw_log_debug("%p: sender %p: error for stale global %u generation:%"PRIu64" recv-generation:%"PRIu64,
client, sender, id, global->generation, sender->recv_generation);
pw_log_debug("%p: sender %p: error for stale global %u recv-generation:%"PRIu64,
client, sender, id, sender->recv_generation);
pw_resource_errorf(resource, -ESTALE, "no global %u any more", id);
return -ESTALE;
}
@ -804,10 +805,7 @@ int pw_impl_client_check_permissions(struct pw_impl_client *client,
uint32_t perms;
if ((global = pw_context_find_global(context, global_id)) == NULL)
return -ENOENT;
if (client->recv_generation != 0 && global->generation > client->recv_generation)
return -ESTALE;
return (errno == ESTALE) ? -ESTALE : -ENOENT;
perms = pw_global_get_permissions(global, client);
if ((perms & permissions) != permissions)

View file

@ -33,17 +33,18 @@ static void * registry_bind(void *object, uint32_t id,
struct pw_global *global;
uint32_t permissions, new_id = user_data_size;
if ((global = pw_context_find_global(context, id)) == NULL)
goto error_no_id;
if ((global = pw_context_find_global(context, id)) == NULL) {
if (errno == ESTALE)
goto error_stale_id;
else
goto error_no_id;
}
permissions = pw_global_get_permissions(global, client);
if (!PW_PERM_IS_R(permissions))
goto error_no_id;
if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation)
goto error_stale_id;
if (!spa_streq(global->type, type))
goto error_wrong_interface;
@ -57,8 +58,8 @@ static void * registry_bind(void *object, uint32_t id,
error_stale_id:
pw_log_debug("registry %p: not binding stale global "
"id %u to %u, generation:%"PRIu64" recv-generation:%"PRIu64,
resource, id, new_id, global->generation, resource->client->recv_generation);
"id %u to %u recv-generation:%"PRIu64,
resource, id, new_id, resource->client->recv_generation);
pw_resource_errorf_id(resource, new_id, -ESTALE, "no global %u any more", id);
goto error_exit_clean;
error_no_id:
@ -88,17 +89,18 @@ static int registry_destroy(void *object, uint32_t id)
uint32_t permissions;
int res;
if ((global = pw_context_find_global(context, id)) == NULL)
goto error_no_id;
if ((global = pw_context_find_global(context, id)) == NULL) {
if (errno == ESTALE)
goto error_stale_id;
else
goto error_no_id;
}
permissions = pw_global_get_permissions(global, client);
if (!PW_PERM_IS_R(permissions))
goto error_no_id;
if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation)
goto error_stale_id;
if (id == PW_ID_CORE || !PW_PERM_IS_X(permissions))
goto error_not_allowed;
@ -109,8 +111,8 @@ static int registry_destroy(void *object, uint32_t id)
error_stale_id:
pw_log_debug("registry %p: not destroying stale global "
"id %u, generation:%"PRIu64" recv-generation:%"PRIu64,
resource, id, global->generation, resource->client->recv_generation);
"id %u, recv-generation:%"PRIu64,
resource, id, resource->client->recv_generation);
pw_resource_errorf(resource, -ESTALE, "no global %u any more", id);
res = -ESTALE;
goto error_exit;