Commit graph

593 commits

Author SHA1 Message Date
Wim Taymans
aa36fd5a17 pulse-server: avoid double free of props
Use spa_steal_ptr to transfer props ownership when we can.

This fixes a problem in the upload stream where the props would be freed
twice when buffer allocation failed, once with properties_free and
then with stream_free.
2026-05-07 10:30:35 +02:00
Wim Taymans
99a89f8bd4 security: fix stack overflow via strndupa on long device names
A client-supplied device name ending in ".monitor" was stack-allocated
via strndupa without any size limit. Since protocol messages can be up
to 16MB, a malicious client could send a very long device name and
overflow the stack, crashing the daemon.

Cap the strndupa length at MAX_NAME (1024) in both find_device and
do_set_default.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:18:06 +02:00
Wim Taymans
b7aae374bf pulse-server: keep allocate buffer size around
For playback and capture streams we allocate MAXLENGTH (4M) buffers but
for upload streams we must allow space for the total upload stream, which
can be up to the max allowed sample size (16M).

Keep the allocated size for the stream around in a variable so that we
can use it when writing/reading to/from the ringbuffer.

This could later also be extended to use the attr.maxlength variable to
size the buffer (but it's usually 4M anyway). This is more complicated
because we need to grow the buffer size when new attributes are set,
which is probably more complicated than useful.
2026-04-30 15:25:31 +02:00
Wim Taymans
96c3ada6f2 JSON: use the json builder instead of memstream and fprintf
Use the JSON builder to prepare arguments for modules and metadata
instead of custom memopen and fprintf. This makes it easier to ensure
the strings are all properly escaped.

This removes the use of spa_json_encode_string(), which could return a
truncated, non-zero terminated result, which we needed to check
everywhere.
2026-04-30 13:23:23 +02:00
Wim Taymans
4ddedc72cd security: add missing NULL checks after reply_new in stream creation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 10:23:07 +02:00
Wim Taymans
f29a4e6e14 pulse-server: fix loading of defaults 2026-04-30 10:11:38 +02:00
Wim Taymans
d4a1278018 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-04-29 18:26:01 +02:00
Wim Taymans
8e7ca70352 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-04-29 18:20:04 +02:00
Wim Taymans
890c06117a security: fix integer overflow in port latency offset conversion
Client-supplied int64_t offset was multiplied by 1000 without overflow
check. Use spa_overflow_mul to detect and reject values that would
overflow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:19:03 +02:00
Wim Taymans
f32295429f security: fix module leak on OOM in PulseAudio do_load_module
If module_create succeeded but the subsequent calloc for
pending_module failed, the module was leaked in the modules map.
Move the calloc before module_create so failure cleanup is trivial.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:13:56 +02:00
Wim Taymans
2d8dc8b457 security: fix JSON injection in PulseAudio do_set_default
The device name was interpolated into a JSON metadata string without
escaping. A node with crafted name containing quote characters could
inject arbitrary JSON keys into the default sink/source metadata.
Use spa_json_encode_string to properly escape the value.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:09:50 +02:00
Wim Taymans
d3e1be8b6e 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-04-29 17:08:17 +02:00
Wim Taymans
cd7bb1e37d 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-04-29 16:51:46 +02:00
Wim Taymans
52afec565b security: add total sample cache size limit in PulseAudio protocol
There was no limit on the total size of the sample cache. A client
could upload many samples to exhaust server memory. Add a configurable
pulse.max-sample-cache property (default 64MB) to cap the total size
of all cached samples.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 16:39:57 +02:00
Wim Taymans
37990b5e90 security: add per-client stream limit in PulseAudio protocol
There was no limit on the number of streams a single client could
create. Each stream allocates a 4MB ring buffer, allowing a malicious
client to exhaust server memory. Add a configurable pulse.max-streams
property (default 64) to limit streams per client.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 16:28:05 +02:00
Wim Taymans
6efaf12d00 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-04-27 11:24:30 +02:00
Wim Taymans
ed2c0ad4ee spa: add spa_alloca that does overflow and limit checks
Make a function like alloca but with overflow checks and a max
allocation size.

Use this function where we can and also make sure that all alloca calls
are in some way limited.
2026-04-27 10:53:44 +02:00
Wim Taymans
a9f1ad414e security: fix integer truncation in peer_name alloca size
Memory Safety: Medium

The strlen() return value (size_t) is stored in an int before being
passed to alloca(). If a malicious client sets an extremely long
PW_KEY_NODE_NAME property, the addition could overflow the int,
resulting in a small or negative alloca size and a subsequent buffer
overflow in snprintf().

Change the type to size_t and add a bounds check to prevent
excessively large stack allocations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 16:09:08 +02:00
Wim Taymans
a6155387da security: fix unchecked alloca in pulse-server property list handling
Memory Safety: Medium

Two alloca() calls in the PulseAudio protocol server were missed by the
previous alloca bounds-checking fix (commit 0d2877c0d):

1. fill_node_info_proplist() adds n_items counts from node properties
   and client properties without checking the total before alloca().
   A client with a very large number of properties can exhaust the stack.

2. fill_card_info() uses pi->n_props from port info for an alloca()
   without bounds checking. A card object with many port properties can
   similarly exhaust the stack.

Add MAX_ALLOCA_SIZE checks consistent with the existing pattern to
prevent stack overflow from large property counts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
00413a3263 security: fix stack exhaustion via unbounded alloca in pulse-server
Memory Safety: Medium

Several functions in the PulseAudio protocol implementation use alloca()
to allocate arrays of port_info, profile_info, or dict_item structs
based on counts derived from card parameters or client property lists.
These counts have no upper bounds, so a card object with a very large
number of parameters or a client sending many properties can cause
alloca() to exhaust the stack, resulting in a stack overflow crash.

Add a MAX_ALLOCA_SIZE (64KB) limit and check element counts before each
alloca() call. If the requested allocation exceeds the limit, the
function returns -ENOMEM instead of crashing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-24 15:55:35 +02:00
Wim Taymans
e490c503fd pulse-server: update initial stream is_paused state
When the stream starts corked, we set the INACTIVE flag and we also need
to set the stream state as PAUSED or else uncork will not unpause
anything.
2026-04-15 18:25:28 +02:00
Wim Taymans
823dcd8843 scheduler: make nodes move to IDLE when inactive
When a node is inactive but linked to a driver, the only reason it is
not being scheduled is because it is inactive.

We already set up the links and negotiate the format and buffers to
prepare going to RUNNING. This patch now also make the node go to IDLE,
which makes the adapter negotiate a forma and buffers with the internal
node.

This makes things more symetrical, when linking a node, it becomes IDLE,
when activating it becomes RUNNABLE, when inactive it goes back to IDLE.
The switch to RUNNING will also be faster when things are already set up
in the IDLE state.

The main advantage is that it allows us to implement the startup of
corked streams in pulseaudio better. Before this patch we had to set the
stream to active to make it go through the Format and buffer negotiation
and then quickly set it back to inactive, hopefully without skipping a
cycle. After this patch, the corked stream goes all the way to IDLE,
where it then waits to become active.

See #4991
2026-04-14 14:28:29 +02:00
Wim Taymans
0e0c325194 fix some uninitialized variables warnings 2026-04-08 11:29:36 +02:00
Wim Taymans
be0e037809 pulse-server: avoid doing allocations and string copies
We can just concatenate the stream and client dict on the stack, reusing
all the strings without having to do allocations or copies.

Also filter out the object.id and object.serial from the client, we want
to keep the ones from the streams.
2026-02-19 13:03:50 +01:00
Wim Taymans
6eb4483069 pulse-server: add client props to sink_input/source_output
Instead of adding the client props to the stream props when we create
it, add them when we enumerate the streams.

This makes it possible to also have the client props in the stream props
for streams that are not created with the pulse API.

Fixes #5090
2026-02-19 12:08:23 +01:00
Arun Raghavan
ed59342d28 pipewire-pulse: Expose bluetooth headset autoswitch config as a message
Makes it easier for libpulse-based clients to modify this setting if
they want.
2026-01-26 14:44:30 -08:00
Arun Raghavan
703380d62d pulse-server: Fix querying after setting of mono mixdown 2026-01-26 14:37:08 -08:00
Arun Raghavan
385161b12a pulse-server: Add a message to enable/disable mono mixdown
WirePlumber recently added a mechanism to force mono mixdown on audio
outputs, which is a useful feature for accessibility. Let's also expose
that setting via libpulse for existing audio settings UIs to be able to
use.
2025-12-18 16:35:35 -08:00
Wim Taymans
2c6aa8e0d0 pulse-server: only use passive for devices
The dont-inhibit-auto-suspend flag does not do anything when using
direct-on-input-idx (capturing from a stream) in pulseaudio, so also
make it do nothing on pulse-server.

See #4991
2025-11-25 10:17:14 +01:00
Arun Raghavan
3337af64ca pulse-server: Support clearing default sink/source
The PulseAudio way of doing this is to accept @NONE@ to clear the
default setting, so let's accept that.
2025-11-06 17:23:16 -08:00
Wim Taymans
7bd65cfe93 pulse-server: increase min quantum values
The default values of 128/48000 seem to be too low as a good default.
Bump them to 256/48000.

Fixes #4875
2025-11-06 12:52:48 +01:00
Wim Taymans
06efc8ffb6 pulse-server: clear timer when stream is created
Make a function when the stream is created so that we can clear the
create_tag and the timer.
2025-09-18 14:22:00 +02:00
Wim Taymans
ca713c08ee pulse-server: use the new timer-queue for timeouts
Use the timer queue for scheduling stream and object data timeouts.

This avoids allocating timerfds for these timeouts and the timer queue
can handle many timeouts more efficiently.
2025-09-18 13:55:43 +02:00
Wim Taymans
370d190572 pulse: improve stream suspended state handling
Only send out SUSPENDED event when there is a change in the suspended
state. This avoids sending out unsuspend events when we simply uncork.

Implement the fail_on_suspend flag for capture and playback streams.
Instead of suspending those streams, we need to kill them.
2025-09-01 12:55:51 +02:00
Wim Taymans
bd7ce5c7fa pulse-server: only react to state changes when not corked
When we are starting or corked we don't emit suspend/resume caused
by state changes.
2025-06-25 10:31:32 +02:00
Arun Raghavan
220b037683 pulse-server: Implement stream suspended callback 2025-06-23 09:19:10 +00:00
Wim Taymans
83c644fe09 pulse-server: mark empty buffers
This makes it use some more optimal paths in the mixer.
2025-06-13 18:07:55 +02:00
Wim Taymans
13105a8e64 pulse-server: Implement record PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
Also implement the flag for record streams, where it is more usually
used, like in pavucontrol to disable starting a network source.
2025-06-02 11:48:01 +02:00
Arun Raghavan
60669920f0 pulse-server: Implement PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND
We do this by setting the node as passive.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4255
Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4726
2025-06-02 14:38:22 +05:30
Wim Taymans
c45d667934 loop: spa_loop_invoke -> spa_loop_locked where possible
When we simply need to change some state for the code executed in the
loop, we can use locked() instead of invoke(). This is more efficient
and avoids some context switches in the normal case.
2025-05-30 11:59:35 +02:00
Wim Taymans
3905e3b3d3 stream: set errno to the current error
Make the state_changed event and _get_state() function set errno with
the current error value if the state is in error, so that application
can use this to give more detailed error reporting.

Use this in alsa, v4l2 and pulse to give some other error codes than
EIO.

Fixes #4574
2025-03-04 13:22:51 +01:00
Wim Taymans
cf7e917024 pulse-server: make a function to silence a buffer 2025-01-16 16:16:39 +01:00
Pauli Virtanen
e393e57a26 pulse-server: ensure positive stream delay in GET_PLAYBACK/RECORD_LATENCY
Pulseaudio protocol requires stream latency is uint64. Clamp the
Pipewire signed latency to the range, better than wrapping around.
2024-11-19 22:07:09 +02:00
Wim Taymans
0dfd6d997f protocol-pulse: implement readiness notification
Write a newline to the fd in the PIPEWIRE_PULSE_NOTIFICATION_FD env
variable when set.

This is to implement readiness notification as suggested in
https://skarnet.org/software/s6/notifywhenup.html

Fixes #4347
2024-10-22 09:50:27 +02:00
Wim Taymans
9e932ec671 pulse-server: set pulse.corked on streams
Set the corked state on streams so that we can use this in sink-input
and source-output info without guessing.

The problem is that when a stream starts un-corked, the state is less
than RUNNING and so before this patch, pulse-server reports a corked
stream, which is not what pulseaudio reports.
2024-09-30 15:02:08 +02:00
Wim Taymans
ca488a5dcc pulse-server: add quirk to block record and playback streams
Add aquirk to block any record or playback stream.
2024-09-23 10:56:40 +02:00
Barnabás Pőcze
27b76ae686 pulse-server: calculate event mask from facility and type
Make `client_queue_subscribe_event()` take the facility and type
separately, and calculate the mask itself, so that the caller
does not need to be concerned with that.
2024-09-18 19:35:08 +02:00
Wim Taymans
b5cccdb382 json: add and use spa_json_str_object_find()
Parse a string as a json object and copy the value with key as a string.
2024-09-16 13:12:05 +02:00
Wim Taymans
ce390d5b22 spa: add spa_json_object_next
This gets the next key and value from an object. This function is better
because it will skip key/value pairs that don't fit in the array to hold
the key.

The previous code patter would stop parsing the object as soon as a key
larger than the available space was found.
2024-09-16 09:50:36 +02:00
Wim Taymans
cd81b5f39a spa: add spa_json_begin_array/object and relaxed versions
Add spa_json_begin_array/object to replace
spa_json_init+spa_json_begin_array/object

This function is better because it does not waste a useless spa_json
structure as an iterator. The relaxed versions also error out when the
container is mismatched because parsing a mismatched container is not
going to give any results anyway.
2024-09-16 09:50:33 +02:00