Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:pipewire
User: [email protected]
Usertags: pu

Hello release team,

[ Reason ]

Fix CVE-2026-14330 (no-dsa):
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1141309
https://security-tracker.debian.org/tracker/CVE-2026-14330

[ Impact ]

Vulnerable systems if not installed.

[ Tests ]

Test plan:

0. Install pulseaudio-utils and candidate pipewire-pulse:

   $ sudo apt install pulseaudio-utils \
       ../pipewire-pulse_1.4.2-1+deb13u1_amd64.deb \
       ../pipewire_1.4.2-1+deb13u1_amd64.deb \
       ../libpipewire-0.3-modules_1.4.2-1+deb13u1_amd64.deb  \
       ../pipewire-bin_1.4.2-1+deb13u1_amd64.deb  \
       ../libpipewire-0.3-0t64_1.4.2-1+deb13u1_amd64.deb  \
       ../libspa-0.2-modules_1.4.2-1+deb13u1_amd64.deb  \
       ../gstreamer1.0-pipewire_1.4.2-1+deb13u1_amd64.deb \
       ../pipewire-alsa_1.4.2-1+deb13u1_amd64.deb \
       ../libspa-0.2-modules_1.4.2-1+deb13u1_amd64.deb  \
       ../libspa-0.2-bluetooth_1.4.2-1+deb13u1_amd64.deb

1. Reboot to make sure new version is used:
   $ reboot
   ...
   $ dpkg -s pipewire-pulse | grep Version
   Version: 1.4.2-1+deb13u1

2. Upload sample to pactl:
   pactl upload-sample /usr/share/sounds/alsa/Front_Left.wav my-sample

3. Play sample from pactl:
   pactl play-sample my-sample

4. Confirm sound can be heard from pipewire-pulse

Observations:

Test plan successful, sound can be heard before and after upgrading
pipewire-pulse to 1.4.2-1+deb13u1 which contains the CVE fix.

[ Risks ]

Possible regression in pipewire-pulse frontend if too many channels or
memory are allocated as they now have hard limits to fix the CVE.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]

See d/changelog.

Cherry-picked two extra upstream commits needed for the CVE fix to
apply, they were not needed for the unstable fix but are needed here
since they introduce some additional checks that are not part of the CVE
but are necessary for the CVE patch to apply correctly.

[ Other info ]

N/A
diff -Nru pipewire-1.4.2/debian/changelog pipewire-1.4.2/debian/changelog
--- pipewire-1.4.2/debian/changelog     2025-04-14 16:04:20.000000000 +0200
+++ pipewire-1.4.2/debian/changelog     2026-10-01 11:26:04.000000000 +0200
@@ -1,3 +1,11 @@
+pipewire (1.4.2-1+deb13u1) trixie; urgency=medium
+
+  * d/gbp.conf: update for trixie branch
+  * d/salsa-ci.yml: set RELEASE to trixie
+  * Import+rebase upstream patches for CVE-2026-14330 (Closes: #1141309)
+
+ -- Agathe Porte <[email protected]>  Thu, 01 Oct 2026 11:26:04 +0200
+
 pipewire (1.4.2-1) unstable; urgency=medium
 
   * New upstream release
diff -Nru pipewire-1.4.2/debian/gbp.conf pipewire-1.4.2/debian/gbp.conf
--- pipewire-1.4.2/debian/gbp.conf      2025-04-14 16:04:20.000000000 +0200
+++ pipewire-1.4.2/debian/gbp.conf      2026-09-29 17:48:04.000000000 +0200
@@ -1,6 +1,6 @@
 [DEFAULT]
 pristine-tar = True
-debian-branch = debian/master
+debian-branch = debian/trixie
 upstream-branch = upstream/1.4.x
 upstream-vcs-tag = %(version)s
 
diff -Nru pipewire-1.4.2/debian/patches/CVE-2026-14330_part1.patch 
pipewire-1.4.2/debian/patches/CVE-2026-14330_part1.patch
--- pipewire-1.4.2/debian/patches/CVE-2026-14330_part1.patch    1970-01-01 
01:00:00.000000000 +0100
+++ pipewire-1.4.2/debian/patches/CVE-2026-14330_part1.patch    2026-09-29 
18:02:48.000000000 +0200
@@ -0,0 +1,93 @@
+From: Wim Taymans <[email protected]>
+Date: Thu, 23 Apr 2026 18:48:13 +0200
+Subject: security: fix stack exhaustion via unbounded alloca in pulse-server
+
+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 <[email protected]>
+
+Origin: 
https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/42c0df1a47e0bacfa0d71b5221b5ce3b85301d21.patch
+Bug-Debian: https://bugs.debian.org/1141309
+
+Signed-off-by: Agathe Porte <[email protected]>
+---
+ src/modules/module-protocol-pulse/pulse-server.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/src/modules/module-protocol-pulse/pulse-server.c 
b/src/modules/module-protocol-pulse/pulse-server.c
+index cb66f75..687821f 100644
+--- a/src/modules/module-protocol-pulse/pulse-server.c
++++ b/src/modules/module-protocol-pulse/pulse-server.c
+@@ -71,6 +71,7 @@
+ /* The max amount of data we send in one block when capturing. In PulseAudio 
this
+  * size is derived from the mempool PA_MEMPOOL_SLOT_SIZE */
+ #define MAX_BLOCK     (64*1024)
++#define MAX_ALLOCA_SIZE       (64*1024)
+ 
+ #define TEMPORARY_MOVE_TIMEOUT        (SPA_NSEC_PER_SEC)
+ 
+@@ -3099,6 +3100,8 @@ static int do_set_port_latency_offset(struct client 
*client, uint32_t command, u
+               return -ENOENT;
+ 
+       collect_card_info(card, &card_info);
++      if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
++              return -ENOMEM;
+       port_info = alloca(card_info.n_ports * sizeof(*port_info));
+       card_info.active_profile = SPA_ID_INVALID;
+       n_ports = collect_port_info(card, &card_info, NULL, port_info);
+@@ -3238,6 +3241,8 @@ static int do_remove_proplist(struct client *client, 
uint32_t command, uint32_t
+       }
+ 
+       dict.n_items = props->dict.n_items;
++      if (dict.n_items > MAX_ALLOCA_SIZE / sizeof(struct spa_dict_item))
++              return -ENOMEM;
+       dict.items = items = alloca(sizeof(struct spa_dict_item) * 
dict.n_items);
+       for (i = 0; i < dict.n_items; i++) {
+               items[i].key = props->dict.items[i].key;
+@@ -3521,6 +3526,8 @@ static int fill_card_info(struct client *client, struct 
message *m,
+               TAG_U32, card_info.n_profiles,                  /* n_profiles */
+               TAG_INVALID);
+ 
++      if (card_info.n_profiles > MAX_ALLOCA_SIZE / sizeof(*profile_info))
++              return -ENOMEM;
+       profile_info = alloca(card_info.n_profiles * sizeof(*profile_info));
+       n_profiles = collect_profile_info(o, &card_info, profile_info);
+ 
+@@ -3550,6 +3557,8 @@ static int fill_card_info(struct client *client, struct 
message *m,
+               uint32_t n_ports;
+               struct port_info *port_info, *pi;
+ 
++              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
++                      return -ENOMEM;
+               port_info = alloca(card_info.n_ports * sizeof(*port_info));
+               card_info.active_profile = SPA_ID_INVALID;
+               n_ports = collect_port_info(o, &card_info, NULL, port_info);
+@@ -3754,6 +3763,8 @@ static int fill_sink_info(struct client *client, struct 
message *m,
+               uint32_t n_ports, n;
+               struct port_info *port_info, *pi;
+ 
++              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
++                      return -ENOMEM;
+               port_info = alloca(card_info.n_ports * sizeof(*port_info));
+               n_ports = collect_port_info(card, &card_info, &dev_info, 
port_info);
+ 
+@@ -3950,6 +3961,8 @@ static int fill_source_info(struct client *client, 
struct message *m,
+               uint32_t n_ports, n;
+               struct port_info *port_info, *pi;
+ 
++              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
++                      return -ENOMEM;
+               port_info = alloca(card_info.n_ports * sizeof(*port_info));
+               n_ports = collect_port_info(card, &card_info, &dev_info, 
port_info);
+ 
diff -Nru pipewire-1.4.2/debian/patches/CVE-2026-14330_part2.patch 
pipewire-1.4.2/debian/patches/CVE-2026-14330_part2.patch
--- pipewire-1.4.2/debian/patches/CVE-2026-14330_part2.patch    1970-01-01 
01:00:00.000000000 +0100
+++ pipewire-1.4.2/debian/patches/CVE-2026-14330_part2.patch    2026-09-29 
18:02:48.000000000 +0200
@@ -0,0 +1,38 @@
+From: Wim Taymans <[email protected]>
+Date: Fri, 24 Apr 2026 14:12:50 +0200
+Subject: security: fix unchecked alloca in pulse-server property list
+ handling
+
+Memory Safety: Medium
+
+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 <[email protected]>
+
+Origin: 
https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/1302cbd08d739e8319e0e8f9cf562a6deab2e08e.patch
+Bug-Debian: https://bugs.debian.org/1141309
+
+Signed-off-by: Agathe Porte <[email protected]>
+---
+ src/modules/module-protocol-pulse/pulse-server.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/modules/module-protocol-pulse/pulse-server.c 
b/src/modules/module-protocol-pulse/pulse-server.c
+index 687821f..4f643d5 100644
+--- a/src/modules/module-protocol-pulse/pulse-server.c
++++ b/src/modules/module-protocol-pulse/pulse-server.c
+@@ -3574,7 +3574,8 @@ static int fill_card_info(struct client *client, struct 
message *m,
+ 
+                       pi = &port_info[n];
+ 
+-                      if (pi->info && pi->n_props > 0) {
++                      if (pi->info && pi->n_props > 0 &&
++                          pi->n_props <= MAX_ALLOCA_SIZE / sizeof(*items)) {
+                               items = alloca(pi->n_props * sizeof(*items));
+                               dict.items = items;
+                               pdict = collect_props(pi->info, &dict);
diff -Nru pipewire-1.4.2/debian/patches/CVE-2026-14330_part3.patch 
pipewire-1.4.2/debian/patches/CVE-2026-14330_part3.patch
--- pipewire-1.4.2/debian/patches/CVE-2026-14330_part3.patch    1970-01-01 
01:00:00.000000000 +0100
+++ pipewire-1.4.2/debian/patches/CVE-2026-14330_part3.patch    2026-09-29 
18:02:48.000000000 +0200
@@ -0,0 +1,327 @@
+From: Wim Taymans <[email protected]>
+Date: Mon, 27 Apr 2026 10:53:44 +0200
+Subject: spa: add spa_alloca that does overflow and limit checks
+
+Make a function like alloca but with overflow checks and a max
+allocation size.
+
+Use this function where we can and also make sure that all alloca calls
+are in some way limited.
+
+Origin: 
https://gitlab.freedesktop.org/pipewire/pipewire/-/commit/ed2c0ad4eee1695381e06f7accb902cbcf547420.patch
+Bug-Debian: https://bugs.debian.org/1141309
+
+[ap: rebase for 1.4.2 and fix conflicts]
+Signed-off-by: Agathe Porte <[email protected]>
+---
+ spa/include/spa/utils/defs.h                     | 10 +++++
+ spa/plugins/audioconvert/audioadapter.c          | 12 ++++--
+ src/modules/module-protocol-pulse/defs.h         |  3 ++
+ src/modules/module-protocol-pulse/message.c      |  6 ++-
+ src/modules/module-protocol-pulse/pulse-server.c | 49 +++++++++++-------------
+ src/pipewire/buffers.c                           |  3 ++
+ src/pipewire/conf.c                              |  4 +-
+ src/pipewire/impl-node.c                         | 21 ++++++----
+ 8 files changed, 68 insertions(+), 40 deletions(-)
+
+diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h
+index 1c1a73a..15bf05a 100644
+--- a/spa/include/spa/utils/defs.h
++++ b/spa/include/spa/utils/defs.h
+@@ -455,6 +455,16 @@ struct spa_error_location {
+       _strp;                                                          \
+ })
+ 
++#define spa_alloca(n, size, max_size)                         \
++({                                                            \
++      void *_res = NULL;                                      \
++      if ((size_t)n > (size_t)max_size / (size_t)size)        \
++              errno = ENOMEM;                                 \
++      else                                                    \
++              _res = alloca((size_t)n * (size_t)size);        \
++      _res;                                                   \
++})
++
+ /**
+  * \}
+  */
+diff --git a/spa/plugins/audioconvert/audioadapter.c 
b/spa/plugins/audioconvert/audioadapter.c
+index 5c0eb4d..55ae1f2 100644
+--- a/spa/plugins/audioconvert/audioadapter.c
++++ b/spa/plugins/audioconvert/audioadapter.c
+@@ -35,6 +35,7 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.audioadapter");
+ 
+ #define MAX_PORTS     (SPA_AUDIO_MAX_CHANNELS+1)
+ #define MAX_RETRY     64
++#define MAX_BLOCKS    4096
+ 
+ /** \cond */
+ 
+@@ -351,6 +352,7 @@ static void emit_node_info(struct impl *this, bool full)
+ 
+               if (this->info.props)
+                       n_items = this->info.props->n_items;
++              n_items = SPA_MIN(n_items, 1024u);
+               items = alloca((n_items + 2) * sizeof(struct spa_dict_item));
+               for (i = 0; i < n_items; i++)
+                       items[i] = this->info.props->items[i];
+@@ -502,6 +504,9 @@ static int negotiate_buffers(struct impl *this)
+ 
+       align = SPA_MAX(align, this->max_align);
+ 
++      if (blocks > MAX_BLOCKS)
++              return -ENOMEM;
++
+       datas = alloca(sizeof(struct spa_data) * blocks);
+       memset(datas, 0, sizeof(struct spa_data) * blocks);
+       aligns = alloca(sizeof(uint32_t) * blocks);
+@@ -1875,11 +1880,12 @@ static int load_converter(struct impl *this, const 
struct spa_dict *info,
+       struct spa_dict_item *items;
+       struct spa_dict cinfo;
+       char direction[16];
+-      uint32_t i;
++      uint32_t i, n_items;
+ 
+-      items = alloca((info->n_items + 1) * sizeof(struct spa_dict_item));
++      n_items = SPA_MIN(info->n_items, 1024u);
++      items = alloca((n_items + 1) * sizeof(struct spa_dict_item));
+       cinfo = SPA_DICT(items, 0);
+-      for (i = 0; i < info->n_items; i++)
++      for (i = 0; i < n_items; i++)
+               items[cinfo.n_items++] = info->items[i];
+ 
+       snprintf(direction, sizeof(direction), "%s",
+diff --git a/src/modules/module-protocol-pulse/defs.h 
b/src/modules/module-protocol-pulse/defs.h
+index fa47c3d..571af8d 100644
+--- a/src/modules/module-protocol-pulse/defs.h
++++ b/src/modules/module-protocol-pulse/defs.h
+@@ -34,6 +34,9 @@
+ 
+ #define MAXLENGTH             (4u*1024*1024) /* 4MB */
+ 
++/* pulseaudio has a 128 char limit for this but we can allow more */
++#define MAX_NAME              1024u
++
+ #define SCACHE_ENTRY_SIZE_MAX (1024*1024*16)
+ 
+ #define MODULE_INDEX_MASK     0xfffffffu
+diff --git a/src/modules/module-protocol-pulse/message.c 
b/src/modules/module-protocol-pulse/message.c
+index dbebc43..c55b7a5 100644
+--- a/src/modules/module-protocol-pulse/message.c
++++ b/src/modules/module-protocol-pulse/message.c
+@@ -529,10 +529,12 @@ static void add_stream_group(struct message *m, struct 
spa_dict *dict, const cha
+       else
+               return;
+ 
+-      write_string(m, key);
+       l = strlen(prefix) + strlen(id) + strlen(str) + 6; /* "-by-" , ":" and 
\0 */
++      if (l < 0 || l > 4096)
++              return;
++      write_string(m, key);
+       b = alloca(l);
+-      snprintf(b, l, "%s-by-%s:%s", prefix, id, str);
++      spa_scnprintf(b, l, "%s-by-%s:%s", prefix, id, str);
+       write_u32(m, l);
+       write_arbitrary(m, b, l);
+ }
+diff --git a/src/modules/module-protocol-pulse/pulse-server.c 
b/src/modules/module-protocol-pulse/pulse-server.c
+index 4f643d5..6afe37c 100644
+--- a/src/modules/module-protocol-pulse/pulse-server.c
++++ b/src/modules/module-protocol-pulse/pulse-server.c
+@@ -745,8 +745,11 @@ static int reply_create_record_stream(struct stream 
*stream, struct pw_manager_o
+               peer_index = peer->index;
+               if (!pw_manager_object_is_source(peer)) {
+                       size_t len = (name ? strlen(name) : 5) + 10;
+-                      peer_name = tmp = alloca(len);
+-                      snprintf(tmp, len, "%s.monitor", name ? name : "sink");
++                      if (len <= MAX_NAME) {
++                              peer_name = tmp = alloca(len);
++                              spa_scnprintf(tmp, len, "%s.monitor", name ? 
name : "sink");
++                      } else
++                              peer_name = NULL;
+               } else {
+                       peer_name = name;
+               }
+@@ -857,7 +860,7 @@ static void manager_added(void *data, struct 
pw_manager_object *o)
+                                   pw_manager_object_is_monitor(peer)) {
+                                       int len = strlen(peer_name) + 10;
+                                       char *tmp = alloca(len);
+-                                      snprintf(tmp, len, "%s.monitor", 
peer_name);
++                                      spa_scnprintf(tmp, len, "%s.monitor", 
peer_name);
+                                       peer_name = tmp;
+                               }
+                               if (peer_name != NULL)
+@@ -3100,9 +3103,8 @@ static int do_set_port_latency_offset(struct client 
*client, uint32_t command, u
+               return -ENOENT;
+ 
+       collect_card_info(card, &card_info);
+-      if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
+-              return -ENOMEM;
+-      port_info = alloca(card_info.n_ports * sizeof(*port_info));
++      if ((port_info = spa_alloca(card_info.n_ports, sizeof(*port_info), 
MAX_ALLOCA_SIZE)) == NULL)
++              return -errno;
+       card_info.active_profile = SPA_ID_INVALID;
+       n_ports = collect_port_info(card, &card_info, NULL, port_info);
+ 
+@@ -3241,9 +3243,9 @@ static int do_remove_proplist(struct client *client, 
uint32_t command, uint32_t
+       }
+ 
+       dict.n_items = props->dict.n_items;
+-      if (dict.n_items > MAX_ALLOCA_SIZE / sizeof(struct spa_dict_item))
+-              return -ENOMEM;
+-      dict.items = items = alloca(sizeof(struct spa_dict_item) * 
dict.n_items);
++      if ((dict.items = items = spa_alloca(dict.n_items,
++                      sizeof(struct spa_dict_item), MAX_ALLOCA_SIZE)) == NULL)
++              return -errno;
+       for (i = 0; i < dict.n_items; i++) {
+               items[i].key = props->dict.items[i].key;
+               items[i].value = NULL;
+@@ -3526,9 +3528,8 @@ static int fill_card_info(struct client *client, struct 
message *m,
+               TAG_U32, card_info.n_profiles,                  /* n_profiles */
+               TAG_INVALID);
+ 
+-      if (card_info.n_profiles > MAX_ALLOCA_SIZE / sizeof(*profile_info))
+-              return -ENOMEM;
+-      profile_info = alloca(card_info.n_profiles * sizeof(*profile_info));
++      if ((profile_info = spa_alloca(card_info.n_profiles, 
sizeof(*profile_info), MAX_ALLOCA_SIZE)) == NULL)
++              return -errno;
+       n_profiles = collect_profile_info(o, &card_info, profile_info);
+ 
+       for (n = 0; n < n_profiles; n++) {
+@@ -3557,9 +3558,8 @@ static int fill_card_info(struct client *client, struct 
message *m,
+               uint32_t n_ports;
+               struct port_info *port_info, *pi;
+ 
+-              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
+-                      return -ENOMEM;
+-              port_info = alloca(card_info.n_ports * sizeof(*port_info));
++              if ((port_info = spa_alloca(card_info.n_ports, 
sizeof(*port_info), MAX_ALLOCA_SIZE)) == NULL)
++                      return -errno;
+               card_info.active_profile = SPA_ID_INVALID;
+               n_ports = collect_port_info(o, &card_info, NULL, port_info);
+ 
+@@ -3575,8 +3575,7 @@ static int fill_card_info(struct client *client, struct 
message *m,
+                       pi = &port_info[n];
+ 
+                       if (pi->info && pi->n_props > 0 &&
+-                          pi->n_props <= MAX_ALLOCA_SIZE / sizeof(*items)) {
+-                              items = alloca(pi->n_props * sizeof(*items));
++                          (items = spa_alloca(pi->n_props, sizeof(*items), 
MAX_ALLOCA_SIZE)) != NULL) {
+                               dict.items = items;
+                               pdict = collect_props(pi->info, &dict);
+                       }
+@@ -3683,7 +3682,7 @@ static int fill_sink_info(struct client *client, struct 
message *m,
+       if (name == NULL)
+               name = "unknown";
+ 
+-      size = strlen(name) + 10;
++      size = SPA_MIN(strlen(name) + 10, MAX_NAME);
+       monitor_name = alloca(size);
+       if (pw_manager_object_is_source(o))
+               snprintf(monitor_name, size, "%s", name);
+@@ -3764,9 +3763,8 @@ static int fill_sink_info(struct client *client, struct 
message *m,
+               uint32_t n_ports, n;
+               struct port_info *port_info, *pi;
+ 
+-              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
+-                      return -ENOMEM;
+-              port_info = alloca(card_info.n_ports * sizeof(*port_info));
++              if ((port_info = spa_alloca(card_info.n_ports, 
sizeof(*port_info), MAX_ALLOCA_SIZE)) == NULL)
++                      return -errno;
+               n_ports = collect_port_info(card, &card_info, &dev_info, 
port_info);
+ 
+               message_put(m,
+@@ -3882,11 +3880,11 @@ static int fill_source_info(struct client *client, 
struct message *m,
+       if (name == NULL)
+               name = "unknown";
+ 
+-      size = strlen(name) + 10;
++      size = SPA_MIN(strlen(name) + 10, MAX_NAME);
+       monitor_name = alloca(size);
+       snprintf(monitor_name, size, "%s.monitor", name);
+ 
+-      size = strlen(desc) + 20;
++      size = SPA_MIN(strlen(desc) + 20, MAX_NAME);
+       monitor_desc = alloca(size);
+       snprintf(monitor_desc, size, "Monitor of %s", desc);
+ 
+@@ -3962,9 +3960,8 @@ static int fill_source_info(struct client *client, 
struct message *m,
+               uint32_t n_ports, n;
+               struct port_info *port_info, *pi;
+ 
+-              if (card_info.n_ports > MAX_ALLOCA_SIZE / sizeof(*port_info))
+-                      return -ENOMEM;
+-              port_info = alloca(card_info.n_ports * sizeof(*port_info));
++              if ((port_info = spa_alloca(card_info.n_ports, 
sizeof(*port_info), MAX_ALLOCA_SIZE)) == NULL)
++                      return -errno;
+               n_ports = collect_port_info(card, &card_info, &dev_info, 
port_info);
+ 
+               message_put(m,
+diff --git a/src/pipewire/buffers.c b/src/pipewire/buffers.c
+index e73adaa..db59b98 100644
+--- a/src/pipewire/buffers.c
++++ b/src/pipewire/buffers.c
+@@ -221,6 +221,9 @@ int pw_buffers_negotiate(struct pw_context *context, 
uint32_t flags,
+       if ((res = param_filter(result, &input, &output, SPA_PARAM_Meta, &b)) > 
0)
+               n_params += res;
+ 
++      if (n_params > 4096)
++              return -EINVAL;
++
+       metas = alloca(sizeof(struct spa_meta) * n_params);
+ 
+       n_metas = 0;
+diff --git a/src/pipewire/conf.c b/src/pipewire/conf.c
+index 387a3ab..d74835f 100644
+--- a/src/pipewire/conf.c
++++ b/src/pipewire/conf.c
+@@ -358,7 +358,9 @@ int pw_conf_save_state(const char *prefix, const char 
*name, const struct pw_pro
+       if ((sfd = open_write_dir(path, sizeof(path), prefix)) < 0)
+               return sfd;
+ 
+-      tmp_name = alloca(strlen(name)+5);
++      size_t tmp_name_size = strlen(name) + 5;
++      if (tmp_name_size > PATH_MAX)
++              return -EINVAL;
+       sprintf(tmp_name, "%s.tmp", name);
+       if ((fd = openat(sfd, tmp_name,  O_CLOEXEC | O_CREAT | O_WRONLY | 
O_TRUNC, 0600)) < 0) {
+               res = -errno;
+diff --git a/src/pipewire/impl-node.c b/src/pipewire/impl-node.c
+index 351f98b..1231b5c 100644
+--- a/src/pipewire/impl-node.c
++++ b/src/pipewire/impl-node.c
+@@ -31,6 +31,8 @@ PW_LOG_TOPIC_EXTERN(log_node);
+ 
+ #define DEFAULT_SYNC_TIMEOUT  ((uint64_t)(5 * SPA_NSEC_PER_SEC))
+ 
++#define MAX_COMMAND   (64*1024u)
++
+ /** \cond */
+ struct impl {
+       struct pw_impl_node this;
+@@ -1939,14 +1941,17 @@ static void node_event(void *data, const struct 
spa_event *event)
+                       size_t size = SPA_POD_SIZE(&event->pod);
+ 
+                       /* turn the event and all the arguments into a command 
*/
+-                      command = alloca(size);
+-                      memcpy(command, event, size);
+-                      command->body.body.type = SPA_TYPE_COMMAND_Node;
+-                      command->body.body.id = SPA_NODE_COMMAND_RequestProcess;
+-
+-                      /* send the request process to the driver but only on 
the
+-                       * server size */
+-                      handle_request_process_command(node->driver_node, 
command);
++                      if ((command = spa_alloca(1, size, MAX_COMMAND)) != 
NULL) {
++                              memcpy(command, event, size);
++                              command->body.body.type = SPA_TYPE_COMMAND_Node;
++                              command->body.body.id = 
SPA_NODE_COMMAND_RequestProcess;
++
++                              /* send the request process to the driver but 
only on the
++                               * server size */
++                              
handle_request_process_command(node->driver_node, command);
++                      } else {
++                              pw_log_warn("%p: ignore large command", node);
++                      }
+               }
+               break;
+       default:
diff -Nru pipewire-1.4.2/debian/patches/series 
pipewire-1.4.2/debian/patches/series
--- pipewire-1.4.2/debian/patches/series        2025-04-14 16:04:20.000000000 
+0200
+++ pipewire-1.4.2/debian/patches/series        2026-09-29 18:02:48.000000000 
+0200
@@ -1 +1,4 @@
 Fix_services.patch
+CVE-2026-14330_part1.patch
+CVE-2026-14330_part2.patch
+CVE-2026-14330_part3.patch
diff -Nru pipewire-1.4.2/debian/salsa-ci.yml pipewire-1.4.2/debian/salsa-ci.yml
--- pipewire-1.4.2/debian/salsa-ci.yml  2025-04-14 16:04:20.000000000 +0200
+++ pipewire-1.4.2/debian/salsa-ci.yml  2026-09-29 18:02:48.000000000 +0200
@@ -5,3 +5,6 @@
 
 reprotest:
   allow_failure: true
+
+variables:
+  RELEASE: 'trixie'

Reply via email to