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>
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>
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>
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>
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>
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
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.
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
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>
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)
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)
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)
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
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.
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.
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
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 /.
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
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
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.
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.
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.
Check that the number of fds for the message does not exceed the number
of received fds with SCM_RIGHTS.
The check was simply doing an array bounds check. This could still lead
to out-of-sync fds or usage of uninitialized/invalid fds when the
message header claims more fds than there were passed with SCM_RIGHTS.
Found by Claude Code.
They are emited from the streaming thread and therefore can be emitted
concurrently with the events on the main thread. This can cause crashes
when the hook list is iterated.
Instead, make those events into callbacks that are more efficient,
and threadsafe.
Add a control.ump port property. When true, the port wants UMP and the
mixer will convert to it. When false, the port supports both UMP and
Midi1 and no conversions will happen. When unset, the mixer will always
convert UMP to midi1.
Remove the CONTROL_types property from the filter. This causes problems
because this is the format negotiated with peers, which might not
support the types but can still be linked because the mixer will
convert.
The control.ump port property is supposed to be a temporary fix until we
can negotiate the mixer ports properly with the CONTROL_types.
Remove UMP handling from bluetooth midi, just use the raw Midi1 events
now that the mixer will give those and we are supposed to output our
unconverted format.
Fix midi events in-place in netjack because we can.
Update docs and pw-mididump to note that we are back to midi1 as the
default format.
With this, most of the midi<->UMP conversion should be gone again and we
should be able to avoid conversion problems in ALSA and PipeWire.
Fixes#5183
Avoid doing conversions in the nodes between Midi formats, just assume
the imput is what we expect and output what we naturally produce.
For ALSA this means we produce and consume Midi1 or Midi2 depending on the
configurtation.
All of the other modules (ffado, RTP, netjack and VBAN) really only
produce and consume MIDI1.
Set the default MIDI format to MIDI1 in ALSA.
Whith this change, almost everything now produces and consumes MIDI1
again (previously the buffer format was forced to MIDI2).
The problem is that MIDI2 to and from MIDI1 conversion has problems in
some cases in PipeWire and ALSA and breaks compatibility with some
hardware.
The idea is to let elements produce their prefered format and that the
control mixer also negotiates and converts to the node prefered format.
There is then a mix of MIDI2 and MIDI1 on ports but with the control
port adapting, this should not be a problem.
There is one remaining problem to make this work, the port format is
taken from the node port and not the mixer port, which would then expose
the prefered format on the port and force negotiation to it with the
peer instead of in the mixer.
See #5183