Commit graph

1072 commits

Author SHA1 Message Date
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
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
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
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
Jonas Holmberg
5cd734e8c0 module-protocol-native: Fix socket activation
Fix path comparison in is_socket_unix() and don't unset LISTEN_FDS since
the function that uses it is called more than once and it was not unset
when sd_listen_fds() was used.

Fixes #5140
2026-03-03 09:44:14 +01:00
Wim Taymans
ab70dae0a8 modules: add PRIORITY_SESSION
For driver nodes, priority.session is needed to be able to change the
default device.

Fixes #5125
2026-02-16 10:38:05 +01:00
Hugo Osvaldo Barrera
57efceeb02 Implement socket activation without libsystemd
Socket activation uses sd_listen_fds from libsystemd, and can only be
compiled on systems with systemd.

This is an issue for Alpine / postmarketOS, where upstream has no
systemd package, but downstream depends on upstream's pipewire package
and wants to rely on socket activation. This also prevents using
socket-activation on other non-systemd distributions, including
non-Linux.

Implement equivalent functionality without a dependency on libsystemd.
2026-02-03 13:17:59 +01:00
Pauli Virtanen
f60e03b4ef pulse-server: use timeout also for creating sample-play streams
Add 35 sec timeout for PLAY_SAMPLE streams to start streaming, similar
to what we do with normal streams, and fail playback if they don't
start.

This avoids pending sample playback using up resources indefinitely if
streams fail to start for some reason, e.g. session manager is not
linking them.
2026-02-02 11:25:01 +00:00
Pauli Virtanen
a50e9a995e pulse-server: disconnect from server on EPROTO
If we get EPROTO, we likely have missed on some messages from the
server, and our state is now out of sync.

It's likely we can't recover (e.g. if error is due to fd limit hit), so
just drop the server connection in this case, similarly as if we got
EPIPE.
2026-02-02 11:16:15 +00:00
Wim Taymans
2aecb49f50 pulse-server: use null to clear the value
The message makes it seem that you can pass 'clear' to clear the setting
but in fact you should pass 'null'.
2026-01-27 10:17:34 +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
Timon
aec99d2b6f format: Add support for sample rate of 1.536 Mhz 2026-01-09 01:16:30 +01: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
fuleyi
23f0acfd1d pulse-server: Fix missing subscription events on device port changes
When a device profile changes (e.g., Bluetooth headset switching from
a2dp-sink to headset-head-unit), the active port information changes
but PulseAudio compatibility layer clients don't receive the expected
PA_SUBSCRIPTION_EVENT_SOURCE or PA_SUBSCRIPTION_EVENT_SINK change events.

Root cause:
The collect_device_info() function updates the active_port index from
SPA_PARAM_Route parameters, but doesn't update the corresponding
active_port_name field. When update_device_info() uses memcmp() to
detect changes in the device_info structure, it compares the entire
structure including active_port_name. If the pointer value doesn't
change (even though the actual port changed), no change is detected,
and the change_mask flag (PW_MANAGER_OBJECT_FLAG_SOURCE/SINK) is not
set, preventing subscription events from being sent.

Solution:
After setting active_port in collect_device_info(), look up the
corresponding port name from SPA_PARAM_EnumRoute parameters by
matching both the port index and direction. Initialize active_port_name
to NULL at the start to ensure it's always recalculated.

This fix applies to all device types (Bluetooth, USB, PCI sound cards)
and all profile switching scenarios, ensuring applications using the
PulseAudio compatibility layer receive proper device change notifications.

Tested with:
- Bluetooth headset profile switching (a2dp-sink ↔ headset-head-unit)
- Applications subscribing to PA_SUBSCRIPTION_MASK_SOURCE/SINK events
- Verified no regression in audio initialization
2025-11-03 15:31:15 +00:00
Wim Taymans
c63c100c4b pulse: use more specific type when parsing params
We expect a Struct for the classes and a Object for the props so we can
use the right POD type when persing.
2025-10-31 12:04:00 +01:00
Wim Taymans
78219471ff spa: remove some obsolete functions
The spa_audio_info array now always holds enough positions for all
channels and we don't need to wrap around.
2025-10-24 09:35:59 +02:00
Wim Taymans
11f1298f53 spa: make a function to make a channel short name
Make a function that can generate and parse a short name for
the positions that are not in the type list, like the AUX channels.
2025-10-22 13:04:53 +02:00
Wim Taymans
dbc5c81e4a spa: avoid using SPA_AUDIO_MAX_CHANNELS
Use SPA_N_ELEMENTS instead of the array we try to handle.
2025-10-21 16:05:33 +02:00
Wim Taymans
818d1435ce treewide: access the position information using helpers
Make sure we don't access out of bounds and that we use the helpers
wherever we can to access the position information.
2025-10-21 13:06:25 +02:00
Wim Taymans
8bbca3b8f3 spa: add spa_audio_parse_position_n
Add a function that accepts the size of the position array when reading
the audio positions. This makes it possible to decouple the position
array size from SPA_AUDIO_MAX_CHANNELS.

Also use SPA_N_ELEMENTS to pass the number of array elements to
functions instead of a fixed constant. This makes it easier to change
the array size later to a different constant without having to patch up
all the places where the size is used.
2025-10-21 09:59:13 +02:00
Wim Taymans
13b8c23767 Don't use SPA_AUDIO_MAX_CHANNELS directly
Make a MAX_CHANNELS define and use that one in code. This makes it
easier to change the constant later.
2025-10-21 09:43:06 +02:00
Wim Taymans
a75cea96fb modules: port modules to timer-queue
Instead of using timerfd, use the context timer-queue to schedule
timeouts. This saves fds and removes some redundant code.

Make the rtp-source timeout and standby code a bit better by using
atomic operations.
2025-10-15 16:57:24 +02:00
Wim Taymans
468a9ac954 pulse-server: add the peer ip to client properties
When clients connect with IP, add the peer IP address to properties. We
might use this later to make a better stream node.name than a copy of the
client application name.
2025-09-29 09:39:57 +02:00
Wim Taymans
fdc74df383 modules: use timer-queue in avahi-poll
Pass the pw_context to get to the shared queue and loop.
Patch up the users of avahi-poll.

Fixes #4913
2025-09-26 13:39:49 +02:00
Wim Taymans
9be06c46b7 pulse-server: fix case statement 2025-09-26 11:43:52 +02:00
Wim Taymans
17cad8e7ef pulse-server: add a help message
Shows all available messages on /core because I keep forgetting.
2025-09-26 10:57:04 +02:00
Wim Taymans
5a894270e6 pulse-server: add a pipewire-pulse:list-modules message
It list all available module names, which you can then describe further.
Make a little module_info iterator function for this.
2025-09-26 10:55:10 +02:00
Wim Taymans
06214b6087 pulse-server: map some more errno to errors
Mostly EADDRINUSE to ERR_BUSY, which happens when loading TCP when
it's already loaded on the address.
2025-09-26 10:50:52 +02: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
361a0de85a pulse-server: make timer function static and fix formatting 2025-09-17 19:18:27 +02:00
Arun Raghavan
cfde4c1b17 pulse: Handle timed out streams
If we don't get a link on a stream, we might never send a create stream
reply. The client handles this fine by timing out after 30s and dropping
the stream, but the server holds on to the pw_stream forever (or until
the client quits).

Let's add a timer to clean up such streams on the server.

Fixes: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4901
2025-09-17 11:48:27 -04: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
1957d3fb00 pulse: avoid a compiler warning 2025-07-25 17:37:56 +02:00
Demi Marie Obenour
9e789c65c2 src: check that POD arrays have the correct size for their type
The parser does not check that POD arrays have the correct size for
their type, so the calling code must do that.

This also enumerates some of the code that cannot handle the size of the
values of an array not being the exact expected size for its type.
There is a lot of it.
2025-07-24 16:27:42 -04:00
Demi Marie Obenour
fb315b9050 *: Missing bounds checks in POD handling
There were missing bounds checks for ill-formed POD all over the place.
2025-07-15 10:13:17 +02:00
Demi Marie Obenour
9a66938283 pulse: don't ignore return value
If a function can fail don't pretend it succeeded.
2025-07-10 14:06:05 +00:00
Demi Marie Obenour
b3bf5be1f6 *: Avoid macros that use casts where possible
Use direct field access when the type is known, instead of a macro that
includes a cast.

These were missed in e4fcbef89a.
2025-07-10 14:02:55 +00: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
b51755bc8b pulse-server: add stream_properties for RTP streams 2025-06-18 12:29:39 +02:00