Commit graph

14784 commits

Author SHA1 Message Date
Barnabás Pőcze
bf57911b83 spa: alsa: pcm: log_write(): return early if log level is disabled
If the "debug" log level is not enabled for the "spa.alsa" log topic,
then there is no point in going into the loop and splitting the data
into lines, so skip that.
2026-05-11 09:36:29 +02:00
Barnabás Pőcze
320fe9a6a0 spa: alsa: pcm: log_write(): don't use strcspn()
Do not use `strcspn()` because it assumes a null terminated string,
but the `fopencookie()` write callback receives a (ptr, length) pair.

So use `memchr()` instead to find the `\n`.
2026-05-11 09:36:20 +02:00
Barnabás Pőcze
892d2cb54e spa: alsa: pcm: log_write(): fix return value
The `fopencookie()` write callback should return the number of consumed
bytes, but it currently only ever returns 0, which signals an error
condition according to the documentation.

Fix that by not overwriting `size`.

Fixes: 73073eb33f ("alsa: redirect alsa output to log file")
2026-05-11 09:36:13 +02:00
Barnabás Pőcze
5ea19f5fca treewide: mark fopencookie() vtable const
`fopencookie()` takes the vtable by value, so it can be marked `const`, so do that.
2026-05-11 09:36:00 +02:00
Martin Geier
6affbf9cf2 audioconvert: update rate also for nodes with disabled resampler
When the graph rate changes it is possible that the follower node can
renegotiate to the new suggested audioconvert rate without requiring
resampling and so the extra check for the disabled resampler is not
required.

Fixes #4933
2026-05-08 15:53:17 +02:00
Wim Taymans
3730528419 bluez5: fix wrong use of F_GETFL and F_SETFL
The pattern is to F_GETFL the flags, then clear the NONBLOCK flag and
then F_SETFL the new flags.
2026-05-08 14:53:01 +02:00
Wim Taymans
d8a4cbc005 modules: avoid useless props copy
We can use the properties we passed to the node.
2026-05-08 14:53:01 +02:00
Barnabás Pőcze
e5b741732d treewide: make more file descriptors cloexec
Avoid file descriptor leakage into child processes by marking them `O_CLOEXEC`.
2026-05-08 14:53:01 +02:00
Wim Taymans
6ef23a1a9a stream: check buffer_id in reuse_buffer 2026-05-08 14:53:01 +02:00
Wim Taymans
099a76227f midifile: reject midi files with invalid values
>64 tracks will overflow the track array and a division of 0 will cause
a division by zero later.
2026-05-08 14:53:01 +02:00
Wim Taymans
f75db29656 jack-tunnel: pass bytes to jack_to_midi
When the buffer has n_samples, we have n_samples * sizeof(float) bytes
to fill with midi.
2026-05-08 14:53:01 +02:00
Wim Taymans
2bfdc36954 filter-graph: guard against overflow of graph input/output 2026-05-08 14:52:54 +02:00
Wim Taymans
2c1a990a4d modules: unset buffer and size after alloc failure
Set the buffer_data to NULL and the size to 0 after we free the
buffer in realloc failure to avoid problems later.
2026-05-08 14:31:49 +02:00
Wim Taymans
e3065fde55 filter-chain: limit the number of graph in/out
There is no limit on the number of inputs/outputs of a graph but the
filter-chain assumes it is at most 128 and also that there are at most
128 buffer datas.

Increase the limit (1024) and clamp and log an error when the
filter-graph has more channels. Also clamp the buffer datas so that we
don't overflow the stack allocated buffers.
2026-05-08 14:31:08 +02:00
Wim Taymans
dc839f86f3 security: reject path traversal in echo-cancel aec_method parameter
The aec_method parameter is interpolated into a SPA library path
as "aec/libspa-aec-%s". A client could use "../" sequences to
load arbitrary SPA plugins. Reject values containing ".." or "/".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:29:03 +02:00
Wim Taymans
92a174ff1e security: limit blocklist regex length in switch-on-connect module
A PulseAudio client can load this module with an arbitrarily complex
blocklist regex, causing catastrophic backtracking in regexec on
every new device. Cap the regex string at 1024 characters.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:28:43 +02:00
Wim Taymans
a585b117da pulse: handle wraparound near the end correctly
If offset is near MAXLENGTH, we can read past the end of the
buffer. Use the ringbuffer API to correctly wraparound.
2026-05-08 14:24:51 +02:00
Wim Taymans
e5dda30b38 security: fix potential buffer over-read in combine-sink name encoding
spa_json_encode_string was called with sizeof(name)-1, which would
not write a null terminator on truncation. Use sizeof(name) and skip
sink names that don't fit in the buffer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:06:57 +02:00
Wim Taymans
0372b4437a security: fix OOB read in IEC958 format enum parsing
In the SPA_CHOICE_Enum case, values[index+1] was used to skip the
default value at index 0, but the bounds check only validated index,
not index+1. Move bounds checks into each case with the correct limit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:04:45 +02:00
Wim Taymans
cefeac7a37 security: reject unknown tags in message_get to prevent va_arg desync
The switch in message_get had no default case. An unrecognized tag byte
from a malicious client would skip the switch body without consuming
the va_arg parameter, desynchronizing all subsequent argument reads
and causing undefined behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:03:42 +02:00
Wim Taymans
886be20b29 security: add missing create_tag checks in stream command handlers
do_cork_stream, do_flush_trigger_prebuf_stream, and do_set_stream_name
did not check whether the stream had completed format negotiation.
Add create_tag guards matching the pattern in do_set_stream_buffer_attr.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:03:33 +02:00
Wim Taymans
a36849189d security: fix one-byte OOB read in module_args_add_props
A trailing backslash in a module argument string would cause the
escape handling to advance past the null terminator, reading one
byte out of bounds on the next loop iteration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:03:04 +02:00
Wim Taymans
d9df3602dd security: add missing create_tag check in update_stream_sample_rate
If a client sends UPDATE_PLAYBACK_STREAM_SAMPLE_RATE before format
negotiation completes, stream->ss.rate could be 0, causing a
floating-point division by zero. Add the same create_tag guard used
in do_set_stream_buffer_attr.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:02:41 +02:00
Wim Taymans
f567041f4d security: fix create_tag check to allow upload stream memblocks
The create_tag guard added in a2de6c886 also rejected memblocks for
upload streams, which never clear create_tag. Upload streams allocate
their buffer immediately, so the NULL deref risk does not apply to
them. Exempt STREAM_TYPE_UPLOAD from the check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:02:18 +02:00
Wim Taymans
a853d3832e security: reject zero-channel volume in PulseAudio message parsing
read_cvolume accepted channels=0, creating a degenerate zero-length
volume array that is passed to pw_stream_set_control and SPA pod
building. Reject zero channels alongside the existing CHANNELS_MAX
upper bound check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:00:53 +02:00
Wim Taymans
5709f05597 security: fix division by zero in PulseAudio set_stream_buffer_attr
A client can create a stream with invalid sample_spec (rate=0) via
format_info negotiation, then send SET_STREAM_BUFFER_ATTR before
negotiation completes. fix_playback_buffer_attr divides by ss.rate,
crashing the daemon. Reject buffer attr changes on streams that
have not completed format negotiation.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:59:45 +02:00
Wim Taymans
e5968c00b1 security: validate sample rate in PulseAudio update_stream_sample_rate
The client-provided rate was used without validation. A zero or
excessively large rate produces extreme correction values passed
to pw_stream_set_control. Reject rates that are zero or exceed
RATE_MAX.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:59:31 +02:00
Wim Taymans
1fd45861c1 security: fix NULL dereference in PulseAudio handle_memblock
A client can send memblock data to a playback stream channel before
format negotiation completes and the stream buffer is allocated,
causing a NULL pointer dereference crash. Reject memblock data for
streams that are still being created (create_tag != SPA_ID_INVALID).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:58:06 +02:00
Wim Taymans
0b564a69cc security: fix stack buffer overflow in PulseAudio channel map parsing
format_info_to_spec parses the format.channel_map property without
checking against CHANNELS_MAX (64) before writing to map->map[].
A client supplying more than 64 channel names overflows the stack-
allocated channel_map buffer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:57:14 +02:00
Wim Taymans
89bf33c1d8 security: fix file descriptor leak in PulseAudio server on_connect error path
File and Resource Handling: Medium

In on_connect(), if client_new() fails or pw_loop_add_io() fails, the
accepted client_fd is never closed. The error path only calls
client_free() which relies on pw_loop_destroy_source() to close the fd,
but if the source was never created, the fd leaks.

Fix by closing client_fd in the error path when it has not been
transferred to a loop source.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:57:04 +02:00
Wim Taymans
e8bf06ea56 security: add missing O_CLOEXEC flag to V4L2 device open
File and Resource Handling: Medium

The V4L2 device file descriptor was opened without the O_CLOEXEC flag.
If a child process is subsequently spawned (e.g., via fork+exec), the
video device fd would be inherited, potentially allowing the child
process unauthorized access to the camera device.

Fixed by adding O_CLOEXEC to the open() flags.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:53:17 +02:00
Wim Taymans
c2cb5d00db security: fix integer overflow in PulseAudio message read_arbitrary
Memory Safety: High

The read_arbitrary() bounds check used `m->offset + len > m->length`
where len is an attacker-controlled uint32_t read from the PulseAudio
protocol message. When m->offset is small and len is close to
UINT32_MAX, the addition wraps around to a small value, bypassing
the bounds check. This allows read_arbitrary() to return a pointer
within the message buffer but report an enormous length to the caller,
leading to out-of-bounds memory reads.

Fixed by rearranging the arithmetic to use subtraction:
`len > m->length - m->offset`, which cannot overflow since
m->offset <= m->length is maintained as an invariant.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:53:04 +02:00
Wim Taymans
4d7c448150 security: add missing O_CLOEXEC/SOCK_CLOEXEC flags
File and Resource Handling: Medium

Several file and socket operations were missing the close-on-exec flag,
which causes file descriptors to leak to child processes created via
fork+exec. This could allow child processes unintended access to
privileged resources.

- node-driver.c: SOCK_DGRAM socket for SIOCETHTOOL ioctl leaked to
  child processes
- pw-container.c: Unix domain listen socket leaked to spawned
  container processes
- compress-offload-api.c: ALSA compress-offload device fd leaked to
  child processes

Added O_CLOEXEC to open() calls and SOCK_CLOEXEC to socket() calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:52:53 +02:00
Wim Taymans
32f969324b security: clamp channel count in PulseAudio volume control handler
Memory Safety: High

The stream_control_info() callback copied control->n_values floats
into stream->volume.values without checking bounds. The source allows
up to MAX_VALUES (256) entries but the destination volume array is
only CHANNELS_MAX (64) entries, so a stream with more than 64 channel
volumes would overflow the buffer. Clamp n_values to CHANNELS_MAX
before the copy.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:49:00 +02:00
Wim Taymans
c066780e52 security: fix integer overflow in pw_reallocarray fallback path
Memory Safety: High

When the system does not provide reallocarray(), pw_reallocarray()
falls back to realloc(ptr, nmemb * size). The multiplication
nmemb * size can silently overflow, causing a smaller-than-expected
allocation. Subsequent writes to the allocation then overflow the
heap buffer.

This function is used extensively throughout PipeWire for allocating
arrays from protocol data, making it a wide attack surface.

Fix by adding an explicit overflow check before the multiplication
in the fallback path, matching the behavior of the real
reallocarray().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:43:10 +02:00
Wim Taymans
1b1c5bda98 security: fix integer overflow in PulseAudio message buffer allocation
Memory Safety: High

In ensure_size(), the check `m->length + size <= m->allocated` could
overflow when both m->length and size are large uint32_t values,
wrapping around to a small number and incorrectly passing the bounds
check. This could allow writing past the end of the allocated buffer.

Rewrite the check as `size <= m->allocated - m->length` which cannot
overflow since we already verified m->length <= m->allocated. Also add
an explicit overflow check for the new allocation size calculation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:41:56 +02:00
Wim Taymans
00a2fcbceb security: fix missing fdopen() NULL check in conf.c
Memory Safety: Medium

In pw_conf_save_state(), the return value of fdopen() was not checked
for NULL. If fdopen() fails, subsequent fprintf() and fclose() calls
would operate on a NULL FILE pointer, causing a crash. Additionally,
the file descriptor would be leaked since fclose() would not be called.

Added a NULL check after fdopen() that closes the raw fd and returns
an error on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-08 13:41:50 +02:00
Wim Taymans
0b11792194 filter-graph: error when there are no valid nodes
The nodes might have failed to load or there was an empty array or the
array did not contain objects.
2026-05-08 13:28:28 +02:00
Wim Taymans
c91e9ded7d modules: handle more stream setup failures
Instead of silently ignoring things.
2026-05-08 13:23:32 +02:00
Wim Taymans
3ad062247d loopback: handle stream setup failure
Instead of silently failing.
Also when we do the cleanup, make sure we don't free the props twice.
2026-05-08 13:23:25 +02:00
Wim Taymans
1d3eb1025c impl-link: use the right port direction string
We might swap input and output so make sure we use the right one in the
debug log to avoid confusion.
2026-05-08 13:22:57 +02:00
Wim Taymans
3eb7315bda connection: reject too large messages
Instead of silently truncating the message size in the header, simply
reject the complete message.
2026-05-08 12:37:40 +02:00
Wim Taymans
08f7fef820 fix capture rate assignment using logical NOT instead of copy
Three modules had "impl->capture_info.rate = !impl->playback_info.rate"
which evaluates to 0 (logical NOT of a non-zero rate) instead of
copying the playback rate. This is a copy-paste typo from the line
above which correctly uses "= impl->capture_info.rate".

Affects module-filter-chain, module-loopback, module-example-filter.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 12:36:44 +02:00
Wim Taymans
9b04249f37 filter: avoid losing buffers in some cases
If the filter process doesn't dequeue/queue a buffer (as can be the
case in jack-tunnel-sink under xrun cases), pw-filter will set the
io to NEED_DATA with ID_INVALID.

This will then make the mixer in the next cycle not recycle any buffers
and it won't be able to produce any new ones either.
If the filter the dequeues/queues a buffer in the next process, it won't
dequeue a buffer for recycle because io is NEED_DATA/INVALID from the
previous cycle (io != HAVE_DATA -> continue).

This will the continue in an infinite loop producing "out of buffers"
forever.

Also check that we actually have a buffer to recycle, if we don't we can
try to dequeue one and place that in the io. This will then unlock the
loop, make the mixer recycle the buffer and produce a new one.

This is the same logic as is present in pw-stream for the same reason.

Fixes #5246
Maybe also #3547
2026-05-08 12:23:36 +02:00
Wim Taymans
4a303edb9e spa: limit the number of buffer blocks
Unbounded values might overflow the stack.
2026-05-08 12:17:50 +02:00
Wim Taymans
3a503ea4b6 filter-graph: remove the pipe filter
It's a terrible idea, doesn't work so well (locks up the data-loop when
read is blocked) and a security mightmare. If you really need to pipe
samples through some program, do that somewhere else, like from the
command line with pw-cat and pw-record.
2026-05-08 12:03:37 +02:00
Wim Taymans
82dbfd558f acp: partially revert f76327e076
The Line Out mute seems to break things.

See #5246
2026-04-28 12:11:53 +02:00
Wim Taymans
8bf7ae5e74 audiomixer: rate limit the "out of buffers" debug
See #5249
2026-04-28 12:11:42 +02:00
Wim Taymans
1825bf696e roc-source: handle some errors better 2026-04-28 12:11:27 +02:00
Wim Taymans
30a77456fc roc-source: start/stop receiving in streaming/pause
Only start receiving packets when we are streaming.

Otherwise the ROC source will start receiving and queueing packets and
consume a lot of memory while we don't read the packets from the queue.

Likewise, stop receiving packets when we pause.

Fixes #5250
2026-04-28 12:10:54 +02:00