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>
File and Resource Handling: Medium
The lock_socket() function opens the lock file without O_NOFOLLOW. If an
attacker places a symlink at the lock file path, open() follows it and
creates or truncates a file at the symlink target with the caller's
privileges. While the lock path is typically in a user-owned runtime
directory, adding O_NOFOLLOW is a low-cost defense-in-depth measure that
prevents symlink attacks in case the directory permissions are
misconfigured or the path is influenced by untrusted input.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
File and Resource Handling: Medium
The socket initialization code uses stat() followed by unlink() to clean
up stale socket files. This creates two issues:
1. stat() follows symlinks, so an attacker who places a symlink at the
socket path can trick the daemon into unlinking an arbitrary file.
2. The gap between stat() and unlink() creates a TOCTOU race window
where the file could be replaced between the check and the removal.
Fix by using lstat() to detect symlinks without following them, refusing
to proceed if the path is a symlink, and only unlinking files that are
actually sockets (S_ISSOCK). This narrows the race window and prevents
symlink-based file deletion attacks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: High
In get_midi_size(), the overflow check for SysEx and meta-event message
sizes has the comparison operator inverted. The check
(unsigned int)(INT_MAX - size - 1) > value
rejects small (safe) payload sizes and accepts large sizes that cause
signed integer overflow in the subsequent size += (int)value + 1.
This means all SysEx messages (0xF0, 0xF7) and system reset/meta events
(0xFF) with valid payloads are incorrectly rejected, while crafted
packets with very large variable-length values bypass the check. Although
the caller has a secondary bounds check that mitigates most exploitation,
the inverted check is both a functional bug (breaks SysEx over RTP) and
a defense-in-depth failure.
Fix by swapping the operands so that the check correctly rejects values
that would overflow: value > (unsigned int)(INT_MAX - size - 1).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: High
The nj2_dump_session_params() function logs char array fields (type,
name, driver_name, follower_name) from network-received
nj2_session_params structs using %s format. These fields are fixed-size
char arrays filled by recvfrom() and are not guaranteed to contain a null
terminator. A malicious peer can send a packet with no null bytes in
these fields, causing pw_log_info to read past the struct boundary,
potentially crashing the process or leaking adjacent heap memory.
Use %.*s format specifier with explicit maximum lengths in the dump
function to bound the string reads. Also force null-terminate the
string fields in nj2_session_params_ntoh() so that all downstream
consumers after byte-order conversion are safe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: Critical
In handle_iec61883_packet(), the data_len field from an incoming network
packet is converted via ntohs() and then unconditionally has 8 subtracted
from it. If an attacker sends a malformed AVB packet with data_len < 8,
the subtraction wraps the uint32_t n_bytes to a very large value
(~4 billion). This corrupted size is then passed to
spa_ringbuffer_write_data(), which can overwrite the ring buffer and
adjacent heap memory with attacker-controlled network data.
Add a bounds check to verify data_len >= 8 before the subtraction,
returning early on malformed packets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: High
Several Bluetooth audio codec implementations calculate codesize by
multiplying samples * channels * sizeof(sample_type) without overflow
checks. The parameters come from Bluetooth codec negotiation, which is
influenced by the remote peer. If the multiplication overflows, codesize
wraps to a small value, causing subsequent buffer size checks to pass
while the actual data processing operates on the full (larger) sample
count, leading to heap buffer overflows.
Affected codecs: LC3 (BAP), LC3plus (A2DP), Opus (A2DP), Opus-G (A2DP).
Add overflow checks before each codesize multiplication to ensure the
result fits in the target integer type, returning -EINVAL on overflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Memory Safety: High
In descriptor_load(), the initial calloc for the descriptor struct, the
strdup for the label, and four calloc calls for port arrays (input,
output, control, notify) all lacked NULL checks. If any allocation fails
under memory pressure, the code proceeds to dereference NULL pointers
when populating the port arrays, causing a crash.
Add NULL checks after all allocation calls, using the existing
descriptor_unref cleanup path which already handles freeing partially
initialized descriptors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
File and Resource Handling: High
The pipe-tunnel module creates FIFOs and then adjusts their
permissions using chmod() on the path. Between mkfifo() and
chmod(), an attacker with write access to the directory (e.g.,
/tmp with the default hardcoded paths) can delete the FIFO and
replace it with a symlink to a target file. The chmod(0666) then
changes permissions on the symlink target, allowing the attacker
to make arbitrary files world-readable/writable.
Fix by:
1. Adding O_NOFOLLOW to the open() call so symlinks are rejected
at open time rather than followed.
2. Moving the permission change from chmod() (path-based, follows
symlinks) to fchmod() (fd-based, operates on the already-opened
and validated file descriptor), and doing it after the fstat
S_ISFIFO check confirms we opened an actual FIFO.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: Medium
In both module-netjack2-driver.c and module-netjack2-manager.c, the
socket buffer size is computed as:
NETWORK_MAX_LATENCY * (mtu + period_size * sizeof(float) * n_ports)
This arithmetic is performed in int (signed 32-bit) but the
intermediate values can exceed INT_MAX with large but valid network
parameters. Signed integer overflow is undefined behavior in C,
and the resulting negative value passed to setsockopt would set an
incorrect socket buffer size.
Fix by widening the intermediate computation to size_t and clamping
the result to INT_MAX before storing in the int variable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: Medium
In update_delay(), the delay compensation size is computed as
delay * sizeof(float) where delay is int64_t but size is uint32_t.
When the delay value is very large, the multiplication result
truncates to a small uint32_t value. This causes an undersized
buffer allocation in resize_delay(), while compensate_samples
retains the original large value. Subsequent use of
compensate_samples could then write past the end of the buffer.
A negative delay (possible if delay_samples overflows) would also
produce a large unsigned size due to implicit conversion.
Fix by clamping the delay to be non-negative and within the maximum
delay buffer size before the multiplication, ensuring the size
cannot truncate or wrap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: Medium
In recalculate_buffer(), the buffer size computation
(delay + (1u<<15)) * 4 can overflow uint32_t when delay is large.
Additionally, the subsequent multiplication buffer_size * channels
for the realloc size can also overflow uint32_t, wrapping to a
small value and causing an undersized allocation. Later writes to
the buffer using the logical buffer_size would then overflow the
heap.
The delay value derives from rate * target_delay where both values
come from stream negotiation properties.
Fix by adding an overflow check on the delay computation and
widening the allocation size to size_t to prevent the second
overflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: High
In netjack2_init(), several buffer sizes are computed by multiplying
network-provided session parameters (period_size, channel counts,
kbps) without overflow checks. A malicious network peer can send
crafted session parameters that cause these multiplications to
overflow, resulting in undersized buffer allocations. Subsequent
writes to these buffers then overflow the heap.
Specific issues fixed:
1. midi_size = period_size * sizeof(float) * max_midi_channels can
overflow, causing calloc to allocate a small buffer.
2. encoded_size = max_encoded_size * max_audio_channels can overflow
for both INT and OPUS encoders.
3. OPUS kbps * period_size * 1024 numerator can overflow uint32_t;
widen to uint64_t for the intermediate calculation.
4. Division by zero if sample_rate is 0 in OPUS encoder path.
5. Missing NULL checks on calloc for empty and midi_data buffers.
6. Channel counts not capped to MAX_CHANNELS before use.
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 vban_midi_receive(), the received buffer is cast to struct
vban_header and its n_frames field is accessed before validating
that the packet is large enough to contain the header. A truncated
packet shorter than VBAN_HEADER_SIZE would cause an out-of-bounds
read.
Fix by checking that len >= VBAN_HEADER_SIZE before accessing the
header, matching the fix applied to vban_audio_receive().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Memory Safety: High
In vban_audio_receive(), the received buffer is cast to struct
vban_header and its fields are accessed before validating that the
packet is large enough to contain the header. If a truncated packet
shorter than VBAN_HEADER_SIZE is received, this reads past the end
of the buffer.
Additionally, when len < hlen, the plen calculation (len - hlen)
produces a negative ssize_t value which, when used in the unsigned
division plen / stride, gets implicitly converted to a very large
value, potentially causing further out-of-bounds reads.
Fix by checking that len >= VBAN_HEADER_SIZE before accessing the
header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a consumer (e.g. Firefox via xdg-desktop-portal) connects to a
pipewiresink mode=provide node and format negotiation fails, the error
reaches the stream as a transient proxy error. The comments in
proxy_error suggest the application should decide whether the error is
permanent.
Before this on_state_changed unconditionally made every proxy error
permanent by calling pw_stream_set_error, which posted
GST_ELEMENT_ERROR and killed the entire provider pipeline. A virtual
camera provider should survive consumer negotiation failures.
In mode=provide, log the error as a warning and continue. Other modes
retain the existing behavior.
To reproduce (with the previous pool fix applied):
Producers:
gst-launch-1.0 -v -e pipewiresrc path=<id> ! \
video/x-raw,width=1280,height=720,framerate=24/1 ! \
jpegenc ! rtpjpegpay ! rtpstreampay ! \
udpsink host=127.0.0.1 port=5000
gst-launch-1.0 -e \
udpsrc address=127.0.0.1 port=5000 ! queue ! \
application/x-rtp-stream,encoding-name=JPEG ! rtpstreamdepay ! \
application/x-rtp,encoding-name=JPEG ! rtpjpegdepay ! \
decodebin ! videorate ! videoconvert ! \
pipewiresink mode=provide \
stream-properties="properties,media.class=Video/Source,media.role=Camera" \
client-name=VirtualCam
Then open Firefox and select VirtualCam as camera source, without this
fix the provider pipeline exits with an error, bringing down any other
clients streaming from it.
META_VideoCrop is present on every buffer negotiated through the
adapter, even when the producer never sets a meaningful crop
region. Before commit c634ef961, gst_buffer_get_video_crop_meta
returned NULL on new GstBuffers so the zero values were never
applied. After that commit, gst_buffer_add_video_crop_meta always
succeeds, and an invalid crop produces black frames.
Without this, the following produces black frames,
Producer:
gst-launch-1.0 videotestsrc is-live=true ! \
video/x-raw,format=I420,width=1280,height=720,framerate=24/1 ! \
pipewiresink mode=provide \
stream-properties="properties,media.class=Video/Source,media.role=Camera" \
client-name=VirtualCam
Consumer:
gst-launch-1.0 pipewiresrc path=<id> ! videoconvert ! autovideosink
When streams are skipped via continue in updateDescriptors(),
the loop index i and descriptorSetLen diverge. The image info
is written at descriptorSetLen but pImageInfo was referencing
index i, pointing to uninitialized memory and causing incorrect
Vulkan descriptor updates.
Fix by using descriptorSetLen consistently.
Signed-off-by: Wang Yu <wangyu@uniontech.com>
We don't need 2 convolvers anymore, we can use the same convolver with
2 outputs with the left and right ir.
Add latency option to the sofa plugin. I believe the latency of the
SOFA filters is by default 0, so use that.
Add support for multiple convolver outputs. This makes things more
efficient because we only need to do the input FFT once to produce the N
outputs.
Add convolver2 that can have multiple outputs.
port_use_buffers and related port methods increment port_id when the
implicit output direction differs from the adapter's primary direction.
port_reuse_buffer only receives a port id but applies to output ports,
so apply the same offset before forwarding to this->target.
Also update videoadapter for the same mapping.
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.
We need to deactivate the graph when the format was cleared on both the
input and output. This means we got suspended and we need to clear. We
can safely do this now because we take the right locks.