From 5ccaf29793100c00ed16d54dabc5651cfbf782cc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 Oct 2025 13:17:00 +0200 Subject: [PATCH] stream: only mmap buffers when not already mapped Don't just blindly mmap the buffer but only when the data pointer is NULL. If it was mapped already by the peer or the adapter or the buffer allocation, we don't want to mmap it again and override the buffer data pointer. Also mmap with the permissions on the data. There is not much point in limiting the permissions for an input port (to read only). We could do this but then we would not be allowed to modify the existing data pointer. The problem is that when the stream mmaps the data as READ only and set the data pointer, if it is then handed to the mixer, it would assume it is mapped with the permissions and then segfault when it tries to write to the memory. It's just better to only mmap when the data is NULL. --- src/pipewire/filter.c | 11 +++++++---- src/pipewire/stream.c | 12 +++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/pipewire/filter.c b/src/pipewire/filter.c index d51338b32..ea3e74cd2 100644 --- a/src/pipewire/filter.c +++ b/src/pipewire/filter.c @@ -885,8 +885,7 @@ static int impl_port_use_buffers(void *object, struct port *port; struct pw_filter *filter = &impl->this; uint32_t i, j, impl_flags; - int prot, res; - int size = 0; + int res, size = 0; pw_log_debug("%p: port:%d.%d buffers:%u disconnecting:%d", impl, direction, port_id, n_buffers, impl->disconnecting); @@ -900,7 +899,6 @@ static int impl_port_use_buffers(void *object, clear_buffers(port); impl_flags = port->flags; - prot = PROT_READ | (direction == SPA_DIRECTION_OUTPUT ? PROT_WRITE : 0); if (n_buffers > MAX_BUFFERS) return -ENOSPC; @@ -915,7 +913,12 @@ static int impl_port_use_buffers(void *object, if (SPA_FLAG_IS_SET(impl_flags, PW_FILTER_PORT_FLAG_MAP_BUFFERS)) { for (j = 0; j < buffers[i]->n_datas; j++) { struct spa_data *d = &buffers[i]->datas[j]; - if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE)) { + if (d->data == NULL && SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE)) { + int prot = 0; + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_READABLE)) + prot |= PROT_READ; + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_WRITABLE)) + prot |= PROT_WRITE; if ((res = map_data(impl, d, prot)) < 0) return res; SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index c4b785017..46c0822a6 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -979,8 +979,7 @@ static int impl_port_use_buffers(void *object, struct stream *impl = object; struct pw_stream *stream = &impl->this; uint32_t i, j, impl_flags = impl->flags; - int prot, res; - int size = 0; + int res, size = 0; pw_log_debug("%p: port:%d.%d buffers:%u disconnecting:%d", impl, direction, port_id, n_buffers, impl->disconnecting); @@ -988,8 +987,6 @@ static int impl_port_use_buffers(void *object, if (impl->disconnecting && n_buffers > 0) return -EIO; - prot = PROT_READ | (direction == SPA_DIRECTION_OUTPUT ? PROT_WRITE : 0); - clear_buffers(stream); if (n_buffers > MAX_BUFFERS) @@ -1005,7 +1002,12 @@ static int impl_port_use_buffers(void *object, if (SPA_FLAG_IS_SET(impl_flags, PW_STREAM_FLAG_MAP_BUFFERS)) { for (j = 0; j < buffers[i]->n_datas; j++) { struct spa_data *d = &buffers[i]->datas[j]; - if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE)) { + if (d->data == NULL && SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_MAPPABLE)) { + int prot = 0; + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_READABLE)) + prot |= PROT_READ; + if (SPA_FLAG_IS_SET(d->flags, SPA_DATA_FLAG_WRITABLE)) + prot |= PROT_WRITE; if ((res = map_data(impl, d, prot)) < 0) return res; SPA_FLAG_SET(b->flags, BUFFER_FLAG_MAPPED);