pipewire/src/modules/module-protocol-pulse/operation.c
Wim Taymans 3a3579ed68 security: fix operation counter leak in operation_complete
operation_complete removed the operation from the list and freed it
but never decremented client->n_operations. After 64 completed
operations the client would be permanently locked out.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:15:22 +02:00

79 lines
1.6 KiB
C

/* PipeWire */
/* SPDX-FileCopyrightText: Copyright © 2020 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include <stdlib.h>
#include <spa/utils/list.h>
#include <pipewire/log.h>
#include "client.h"
#include "defs.h"
#include "log.h"
#include "manager.h"
#include "operation.h"
#include "reply.h"
int operation_new_cb(struct client *client, uint32_t tag,
void (*callback)(void *data, struct client *client, uint32_t tag),
void *data)
{
struct operation *o;
if (client->n_operations >= MAX_OPERATIONS)
return -ENOSPC;
if ((o = calloc(1, sizeof(*o))) == NULL)
return -errno;
o->client = client;
o->tag = tag;
o->callback = callback;
o->data = data;
spa_list_append(&client->operations, &o->link);
client->n_operations++;
pw_manager_sync(client->manager);
pw_log_debug("client %p [%s]: new operation tag:%u", client, client->name, tag);
return 0;
}
int operation_new(struct client *client, uint32_t tag)
{
return operation_new_cb(client, tag, NULL, NULL);
}
void operation_free(struct operation *o)
{
o->client->n_operations--;
spa_list_remove(&o->link);
free(o);
}
struct operation *operation_find(struct client *client, uint32_t tag)
{
struct operation *o;
spa_list_for_each(o, &client->operations, link) {
if (o->tag == tag)
return o;
}
return NULL;
}
void operation_complete(struct operation *o)
{
struct client *client = o->client;
pw_log_info("[%s]: tag:%u complete", client->name, o->tag);
spa_list_remove(&o->link);
client->n_operations--;
if (o->callback)
o->callback(o->data, client, o->tag);
else
reply_simple_ack(client, o->tag);
free(o);
}