Commit graph

1145 commits

Author SHA1 Message Date
Wim Taymans
7303a55b50 treewide: replace EBADFD with posix EBADF
EBADF was used in some places already, some other places used EBADFD
(with and without an #ifdef). EBADFD is linux specific.
2026-05-27 13:36:39 +02:00
Wim Taymans
784a9dd00f pulse: do all delay calculations when we need it
Just store the values for calculating the delay in the hot path. Then
compute the delay only when we need it.
2026-05-26 14:50:47 +02:00
Wim Taymans
3a9dbc6d99 pulse: add some SPA_LIKELY 2026-05-26 14:50:15 +02:00
Wim Taymans
753ed37ec5 pulse: inline the message check
Inline the resize check and then call the resize function when
necessary.
2026-05-26 14:48:47 +02:00
Wim Taymans
22536600b8 pulse-server: use the new in-follow passive mode
A passive port is not automatically activated anymore by an active peer
node, it now needs the "follow" mode to follow the state of the peer without
activating it.
2026-05-25 18:19:12 +02:00
Wim Taymans
63eb53c1cb pulse-server: always set stream.capture.sink for monitor
Also set the stream.capture.sink when we find the sink by index, not
just by name when it ends with .monitor.
2026-05-25 18:17:51 +02:00
Wim Taymans
e0d7b37826 pulse-server: keep track of dont_inhibit_auto_suspend
Keep the flag dont_inhibit_auto_suspend around and use it do decide when
to send suspend messages to the client.

We don't always want to send suspend messages when the stream state changes
because that could happen because the stream was, for example, relinked.

The intention of the suspend message is mostly for monitor streams that
use the dont-inhibit flag and want to follow the suspend state of the
sink.

See #5273
2026-05-25 18:16:19 +02:00
Wim Taymans
79b4aba6cc pulse: also handle potential overflow in ROUND_UP 2026-05-14 16:27:20 +02:00
Wim Taymans
98fdedf348 filter-graph: relax LADSPA plugin loading
Make a new library.filter-path for the filter-graph that will filter and
restrict the dlopen filenames (used for the LADSPA plugin only).

By default this is false and so filter-chain can load from absolute
paths without extra checks.

Enable the extra checks for the pulse LADSPA modules and the
audioconvert filter graphs because these allow loading LADSPA plugins
into other processes.

Fixes #5222
2026-05-14 13:23:19 +02:00
Wim Taymans
4f975d0071 treewide: add error checking to spa_json_builder_close
There could have been a write error or allocation error while building
the json file that we can detect in spa_json_builder_close().

Error out instead of silently using a truncated JSON.

Use spa_autofree for the memory to make cleanup easier.
2026-05-13 18:14:44 +02:00
Wim Taymans
6d1c242433 pulse-server: implement more valid_args on modules
If the valid_args is NULL, reject all arguments.
2026-05-13 16:53:40 +02:00
Wim Taymans
e5ff44910e pulse-server: improve module argument checking
Make the module valid_args a structure that includes the argument key,
description and some flags. Use this to enforce mandatory properties
in a more central place.

We should be able to generate the module usage from this as wel later to
have things a bit more structured.
2026-05-13 10:23:47 +02:00
Wim Taymans
8860dc809d pulse-server: use pw_net_get_ip instead of inet_ntop 2026-05-12 12:14:52 +02:00
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
51b635cc98 modules: convert snprintf to strbuf
Use spa_strbuf instead of snprintf to handle errors better.
2026-05-06 13:35:09 +02:00
Wim Taymans
01b2af13c7 pulse-server: handle strdup error 2026-05-05 14:54:43 +02:00
Wim Taymans
c551408ec2 security: reject path traversal in echo-cancel aec_method parameter
The aec_method parameter is interpolated into a SPA library path
as "aec/libspa-aec-%s". A client could use "../" sequences to
load arbitrary SPA plugins. Reject values containing ".." or "/".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:44:28 +02:00
Wim Taymans
5d0e806bdb security: limit blocklist regex length in switch-on-connect module
A PulseAudio client can load this module with an arbitrarily complex
blocklist regex, causing catastrophic backtracking in regexec on
every new device. Cap the regex string at 1024 characters.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:40:25 +02:00
Wim Taymans
dac6b4f2c5 security: clamp negative max-clients config to zero in pulse server
A negative max-clients value in the config is parsed as int then
assigned to uint32_t, wrapping to UINT32_MAX and effectively
disabling the client limit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:28:02 +02:00
Wim Taymans
c38a32e2e1 security: fix NULL pointer dereference in LADSPA sink/source modules
When sink_name/source_name is not provided, pw_properties_get for
PW_KEY_NODE_NAME returns NULL, which is then passed to
pw_properties_setf as a %s argument.

Add NULL check before calling pw_properties_setf.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:24:52 +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
6ea673b68a security: fix issues in pulse module core files
- volume.c: add spa_pod_is_object check before casting param to
  spa_pod_object, preventing out-of-bounds reads on malformed pods
- manager.c: add NULL check for p->param in has_param before
  dereferencing via SPA_POD_SIZE
- snap-policy.c: check strings1[1] and strings2[1] for NULL before
  passing to g_str_equal, fixing wrong operand order
- format.c: use map->channels consistently in format_build_param

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 17:08:04 +02:00
Wim Taymans
ef2541a1ef security: fix multiple issues in pulse module implementations
- module-zeroconf-publish: guard spa_hook_remove of impl_listener with
  a flag to prevent operating on uninitialized hook when unload is called
  after a partial load failure; bail out of create_service when
  pw_properties_new fails to prevent NULL dereference in publish_service
- module-device-restore: add missing NULL check after message_alloc in
  emit_event; make manager_events static const
- module-jackdbus-detect: fix memory leak on error paths in prepare by
  using goto out instead of early return; free props/sink_props/source_props
  in unload
- module-roc-sink-input: add missing valid_args whitelist
- module-rtp-recv: add missing valid_args whitelist
- module-rtp-send: add missing valid_args whitelist
- module-gsettings: add missing NULL check after strdup in load_group

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 16:50:30 +02:00
Wim Taymans
dfc5fd86a7 pulse: only fixate when necessary
Check if the format is already fixated before doing a copy and fixate.
The copy can fail so we need to check this.
2026-04-30 16:27:15 +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
32648b7cc7 pulse: handle wraparound near the end correctly
If offsetis near MAXLENGTH, we can still read past the end of the
buffer. Use the ringbuffer to wraparound.
2026-04-30 14:14:59 +02:00
Wim Taymans
b9b93f3cdb pulse: use json builder for message handler output
Makes sure we escape the string correctly.
2026-04-30 13:53:20 +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
57c621e654 server: use the right client_fd
After accept, we transfered ownership of the client_fd to the source so
use the fd on the new owner.
2026-04-30 10:00:53 +02:00
Wim Taymans
4a34da368e security: fix potential buffer over-read in combine-sink name encoding
spa_json_encode_string was called with sizeof(name)-1, which would
not write a null terminator on truncation. Use sizeof(name) and skip
sink names that don't fit in the buffer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 09:27:37 +02:00
Wim Taymans
912f7f5c64 security: add missing NULL check after pw_properties_new in zeroconf
pw_properties_new can return NULL under OOM. The result was used
directly without a check, leading to a NULL pointer dereference.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 09:25:19 +02:00
Wim Taymans
e1f4c441f4 security: fix OOB read in IEC958 format enum parsing
In the SPA_CHOICE_Enum case, values[index+1] was used to skip the
default value at index 0, but the bounds check only validated index,
not index+1. Move bounds checks into each case with the correct limit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 09:19:41 +02:00
Wim Taymans
390874e7c3 security: fix JSON injection in simple-protocol-tcp address
The listen address was inserted into a JSON array without escaping.
Build the address string first, then encode it with
spa_json_encode_string.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 09:15:36 +02:00
Wim Taymans
0ae17566f2 security: reject unknown tags in message_get to prevent va_arg desync
The switch in message_get had no default case. An unrecognized tag byte
from a malicious client would skip the switch body without consuming
the va_arg parameter, desynchronizing all subsequent argument reads
and causing undefined behavior.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-30 09:14:08 +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
6d2600c09d security: fix one-byte OOB read in module_args_add_props
A trailing backslash in a module argument string would cause the
escape handling to advance past the null terminator, reading one
byte out of bounds on the next loop iteration.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:24:13 +02:00
Wim Taymans
c6faaff410 security: add missing NULL check after strndup in cmd.c
strndup can return NULL under OOM. The result was passed directly to
spa_json_begin_array which would dereference the NULL pointer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:21:16 +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
6a8c2469c5 security: fix create_tag check to allow upload stream memblocks
The create_tag guard added in a2de6c886 also rejected memblocks for
upload streams, which never clear create_tag. Upload streams allocate
their buffer immediately, so the NULL deref risk does not apply to
them. Exempt STREAM_TYPE_UPLOAD from the check.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:16:52 +02:00
Wim Taymans
3a3579ed68 security: fix operation counter leak in operation_complete
operation_complete removed the operation from the list and freed it
but never decremented client->n_operations. After 64 completed
operations the client would be permanently locked out.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 18:15:22 +02:00
Wim Taymans
344c9265a6 security: fix JSON injection in pulse module arguments
Use spa_json_encode_string to escape user-supplied strings before
inserting them into JSON configs in module-always-sink,
module-x11-bell, and module-switch-on-connect.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:56:12 +02:00
Wim Taymans
7c2d8f7251 security: add missing NULL checks after message_alloc in reply
Both reply_new and reply_error passed the message_alloc result directly
to message_put without checking for NULL, which would cause a NULL
pointer dereference on allocation failure.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:54:21 +02:00
Wim Taymans
1b8962d7c2 security: fix JSON injection in native-protocol-tcp address
The listen address was inserted into JSON without escaping. Build the
address string first, then encode it with spa_json_encode_string to
prevent injection of arbitrary JSON keys.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:52:19 +02:00
Wim Taymans
c5c2d197dc security: fix JSON injection in LADSPA plugin/label strings
The plugin and label parameters in module-ladspa-sink and
module-ladspa-source were inserted into the filter-chain JSON config
without escaping. Use spa_json_encode_string to prevent injection.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:50:49 +02:00
Wim Taymans
bc4e1a989c 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-04-29 17:23:43 +02:00
Wim Taymans
807b93fb05 security: add per-client pending sample limit in PulseAudio protocol
There was no limit on concurrent PLAY_SAMPLE operations per client.
Each creates a PipeWire stream, allowing a client to exhaust server
resources. Add a MAX_PENDING_SAMPLES (64) limit per client.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:19:08 +02:00
Wim Taymans
138e30df38 security: add per-client operation count limit in PulseAudio protocol
There was no limit on pending operations per client. Commands like
SET_SINK_VOLUME each allocate an operation that persists until a
manager sync completes. A client flooding these commands can exhaust
server memory. Add a MAX_OPERATIONS (64) limit per client.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 17:17:38 +02:00