Keep the flag dont_inhibit_auto_suspend around and use it do decide when
to send suspend messages to the client.
We don't always want to send suspend messages when the stream state changes
because that could happen because the stream was, for example, relinked.
The intention of the suspend message is mostly for monitor streams that
use the dont-inhibit flag and want to follow the suspend state of the
sink.
See #5273
Instead of just setting the port state directly, go through the
port_update_state() function. This will make suspend_node() also
emit the port state change event to the links. This then causes
the link to reset to INIT, which cancels pending complete_ready work
items and prevents them from changing the port to READY without a
valid format.
One possible situation where this could happen is when a suspend
happens while the port was waiting for a set_param(Format) reply from
the client-node.
See #3547
Setting the volume control ports with a volume param also initializes
the controls. This ensures the controls are not restored to their
default value when the graph is activated.
Fixes#5192
When we are asked to add noise bits, don't call the clear function.
Make the passthrough and clear-on-empty flags available with a new flag
field to make it more extensible.
Fixes#5260
Make a new library.filter-path for the filter-graph that will filter and
restrict the dlopen filenames (used for the LADSPA plugin only).
By default this is false and so filter-chain can load from absolute
paths without extra checks.
Enable the extra checks for the pulse LADSPA modules and the
audioconvert filter graphs because these allow loading LADSPA plugins
into other processes.
Fixes#5222
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.
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`.
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")
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
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.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>