Commit graph

14758 commits

Author SHA1 Message Date
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
Wim Taymans
3e67b89a1a 1.6.4 2026-04-22 10:30:36 +02:00
Charles
51c6e70ae5 gst: fix crop height typo in pipewiresink do_send_buffer
The crop region height was incorrectly set to meta->width instead of
meta->height when copying GstVideoCropMeta into the SPA buffer.
2026-04-22 10:18:20 +02:00
zuozhiwei
e01ff7e67e audioconvert: fix tmp_datas[1] when scratch ports grow 2026-04-21 17:17:31 +02:00
Masum Reza
cf8a0b012f alsa: acp: don’t override user-selected port on availability changes
ACP was re-selecting the “best” port on every port availability event,
even when a port was already explicitly selected by the user. This
differs from PulseAudio’s behavior, where port switching decisions are
left to higher-level policy.

This caused issues on devices where Line Out (speakers) and Headphones
share the same analog interface: when headphones are plugged in, ACP
would immediately switch away from the user-selected Line Out, or end up
in a state where no sound is produced despite selecting speakers explicitly from
clients like pwvucontrol.

Fix this by only re-evaluating and switching ports when:
  - no active port is currently selected, or
  - the active port has become unavailable

This preserves manual user choices and prevents ACP from fighting client
port selections during route activation.

Additionally, adjust ALSA mixer paths to better separate Line Out and
Headphones behavior:
  - Disable Line Out controls in the headphones path
  - Add explicit Line Out and Auto-Mute Mode handling in the lineout path

Together, these changes align PipeWire’s behavior more closely with
PulseAudio and fix cases where selecting speakers while headphones are
plugged results in no audio output.

Signed-off-by: John Titor <masumrezarock100@gmail.com>
2026-04-21 17:15:05 +02:00
Pauli Virtanen
04af44d5c3 bluez5: more MT7925 quirks
The MT7925 chipset has several alternative USB ids recognized by kernel,
list them all.

(cherry picked from commit cee1bdfb5a)
2026-04-19 19:15:23 +03:00
Pauli Virtanen
bb6199214d bluez5: add quirk for LC3-24kHz for HFP
MT7925 fails to setup a SCO connection that results to working LC3-24kHz
audio. Other controllers (Intel etc) appear to work OK.

Add quirk for disabling this codec, and disable it for this Mediatek
controller.

(cherry picked from commit 84e6845aa6)
2026-04-19 19:15:23 +03:00
Pauli Virtanen
b2028a03f0 bluez5: fix disabling HFP codecs via bluez5.codecs
backend-native should not advertise disabled HFP codecs as available.

(cherry picked from commit 6e8e234e61)
2026-04-19 19:15:23 +03:00
Martin Geier
c148028f5a bluez5: iso-io: don't use streams without tx_latency enabled for fill level calculation
When there is a stream without tx_latency enabled, the fill_count ends
with MIN_FILL value. This causes one buffer of silence to be written to
every stream before the actual data in each iteration.
Consequently, more data is written than consumed in each iteration.
After several iterations, spa_bt_send fails, triggering a
group_latency_check failure in few next iterations and leading to
dropped data.

Skip streams without tx_latency enabled in fill level calculations
to prevent these audio glitches.

(cherry picked from commit 42415eadd9)
2026-04-19 19:15:23 +03:00
Alexander Sarmanow
78888a78c3 bluez5: bap: add support for manual BIS config
(cherry picked from commit 54a4515b09)
2026-04-19 19:15:23 +03:00
ValdikSS
5918e6f05d bluez5: aac: Use VBR encoding with Mode 5 by default
(cherry picked from commit ee1b429441)
2026-04-19 19:15:23 +03:00
ValdikSS
cb1d19e433 bluez5: aac: use higher band limit for CBR mode
FDK-AAC encoder uses band pass filter, which is automatically
applied at all bitrates.
For CBR encoding mode, its values are as follows (for stereo):

* 0-12 kb/s:   5   kHz
* 12-20 kb/s:  6.4 kHz
* 20-28 kb/s:  9.6 kHz
* 40-56 kb/s:  13  kHz
* 56-72 kb/s:  16  kHz
* 72-576 kb/s: 17  kHz

VBR uses the following table (stereo):

* Mode 1: 13   kHz
* Mode 2: 13   kHz
* Mode 3: 15.7 kHz
* Mode 4: 16.5 kHz
* Mode 5: 19.3 kHz

17 kHz for CBR is a limiting value for high bitrate.

Assume >110 kbit/s as a "high bitrate" CBR and increase the
band pass cutout up to 19.3 kHz (as in mode 5 VBR).

Link: d8e6b1a3aa/libAACenc/src/bandwidth.cpp (L114-L160)
(cherry picked from commit a35b6b0c4b)
2026-04-19 19:15:23 +03:00
ValdikSS
cc71d011e0 bluez5: aac: use maximum possible peak bitrate according to MTU
Android 11 and newer, in both CBR and VBR modes,
* Sets bitrate (AACENC_BITRATE) to the max_bitrate value of A2DP
* Sets peak bitrate (AACENC_PEAK_BITRATE) according to the maximum data
   which could fit into single audio packet based on MTU

AACENC_BITRATE is used only in CBR mode. For VBR mode, the only limiting
factor is AACENC_PEAK_BITRATE.

Do the same in Pipewire.

Link: https://gitlab.freedesktop.org/pipewire/pipewire/-/work_items/1482#note_2949680
Link: https://cs.android.com/android/platform/superproject/+/android16-qpr2-release:packages/modules/Bluetooth/system/stack/a2dp/a2dp_aac_encoder.cc;drc=37d7b4549f7b8740df1a290f04c20c591a2d3391;l=269
(cherry picked from commit 49d5f4f236)
2026-04-19 19:15:23 +03:00
Chiluka Rohith
d444eebea4 pw-cat: Fix waveX format endian assign
SF_FORMAT_WAVEX is not supported to SF_ENDIAN_CPU. Due to that, unable
to record in .wav file (for > 2 channels).  Add case for SF_FORMAT_WAVEX
to get assign SF_ENDIAN_FILE.

Fixes #5233
2026-04-16 13:57:37 +02:00
Wim Taymans
686095ea97 pipewire-jack: also ignore ports with other DSP type
The DSP port type needs to be something else than "other" for it
to become visible. This way we can also remove the IS_VISIBLE check
because we never add invisible ports to the object list.
2026-04-16 13:57:34 +02:00
Wim Taymans
c3c3cb7ef2 jack: don't emit "other" ports
When we see a non-dsp port, simply ignore it. This will make sure also
the links are ignored.

See #3512
2026-04-16 13:57:31 +02:00
Wim Taymans
e0697f52c3 alsa-seq: add : between client and port name
The separator is important for applications to find the client name and
group ports.

Fixes #5229
2026-04-16 10:19:05 +02:00
zuozhiwei
b0f719edd4 alsa: fix inverted port validity check in port_reuse_buffer
The CHECK_PORT condition in impl_node_port_reuse_buffer was inverted with a negation operator, causing the function to reject valid output ports and accept invalid ones.

Fixes the logic so that valid ports proceed to buffer recycling and invalid ports are properly rejected.
2026-04-16 10:18:58 +02:00
Wim Taymans
db0fa4b419 filter-graph: allow negative Gain in mixer
To allow for polarity changes.

Fixes #5228
2026-04-16 10:18:47 +02:00
Wim Taymans
d9b6153123 alsa-seq: remove port from mix_list on destroy
When the port is destroyed we need to remove it from the mix_list or
else the process function will keep trying to use the invalid memory.

This is because the port logic does not want to call any functions on
the port (like clearing the IO or Format) after it emitted the destroy
signal and we need to clean up ourselves.

Fixes #5221
2026-04-16 10:18:30 +02:00
Wim Taymans
8be0d7534b dlopen: support search path ending in /
When the search path is /usr/lib/, /usr/lib/foo.so fails to load because
there is no / after the search path. Fix this by requiring that either
the search path end with / or the following char is a /.
2026-04-16 10:18:03 +02:00
Wim Taymans
00b12dc67a pipewire: check init count before loading plugins
When pw_init() was not called and the init_count is 0, the plugin path
was not set and loading plugins will fail/segfault.

Avoid this and return en error early instead with a message that
pw_init() should be called first.

See !2784
2026-04-16 10:17:52 +02:00
Wim Taymans
cc3d0d1191 1.6.3 2026-04-08 18:00:08 +02:00
Wim Taymans
cf88df2185 filter-chain: don't corrupt the enumerated properties
When we add a Format property after we dereffed all the other params in
the builder, we might relocate the builder memory and invalidate all
previously dereffed params, causing corruption.

Instead, first add all the params to the builder and then deref the
params.

There is a special case when we have both a capture and playback
stream. The capture stream will receive all filter params and the
playback stream will just receive its Format param.

Fixes #5202
2026-04-08 17:55:36 +02:00
Wim Taymans
d6adf944df filter-graph: return current control value correctly
The control values are only set in the port control_data after the
filter has been activated and the instances are created.

Property enumerations might happen before that and then we can either
return the current_value (when set in a control section or later with a
param property) or the default value.
2026-04-08 17:55:33 +02:00
Wim Taymans
821b62dac5 dlopen: improve prefix check some more
If we pass a path /usr/libevil/mycode.so, it might have a prefix of
/usr/lib but we should still reject it. Do thi by checking that after
the prefix match, we start a new directory.
2026-04-08 16:22:04 +02:00
Wim Taymans
1ac706c3bc mem: handle overflow in pw_map_range_init()
Integer overflows can result in map_range_init() to return wrong offset
or size that can result in access to invalid or unmapped memory.

Check for the overflows and return an EOVERFLOW error.

Found by Claude Code.
2026-04-08 16:21:38 +02:00