Fix CVE-2026-18649: limit RTP H.264/H.265 fragmentation unit size

Backport upstream MR 12234 to fix CVE-2026-18649 in
gstreamer1-plugins-good-1.22.12. Adds a max-fragmentation-unit-size
property (default 32MB) to both the H264 and H265 RTP depayloaders,
dropping fragmentation units that exceed this limit to prevent
excessive memory usage. Also properly resets internal state fields
when discarding data during fragmentation unit handling.

CVE: CVE-2026-18649
Upstream patches:
 - https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12234.patch
Resolves: RHEL-224165

This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.

Assisted-by: Ymir
This commit is contained in:
RHEL Packaging Agent 2026-08-11 14:49:39 +00:00
parent a8a9c25b9f
commit 67028be52b
2 changed files with 320 additions and 1 deletions

View File

@ -0,0 +1,310 @@
From f92e4319eed01faea1a93360cd29008e211973cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Wed, 29 Jul 2026 17:39:56 +0300
Subject: [PATCH 1/2] rtph264depay: rtph265depay: Limit the maximum
fragmentation unit size
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/work_items/5224
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12234>
---
.../gst/rtp/gstrtph264depay.c | 43 ++++++++++-
.../gst/rtp/gstrtph264depay.h | 1 +
.../gst/rtp/gstrtph265depay.c | 71 +++++++++++++++++++
.../gst/rtp/gstrtph265depay.h | 2 +
4 files changed, 116 insertions(+), 1 deletion(-)
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
index 9cef347c21..9ccd8ab24e 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
@@ -41,12 +41,14 @@ GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
#define DEFAULT_ACCESS_UNIT FALSE
#define DEFAULT_WAIT_FOR_KEYFRAME FALSE
#define DEFAULT_REQUEST_KEYFRAME FALSE
+#define DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE (32 * 1024 * 1024)
enum
{
PROP_0,
PROP_WAIT_FOR_KEYFRAME,
PROP_REQUEST_KEYFRAME,
+ PROP_MAX_FRAGMENTATION_UNIT_SIZE,
};
@@ -126,6 +128,9 @@ gst_rtp_h264_depay_set_property (GObject * object, guint prop_id,
case PROP_REQUEST_KEYFRAME:
self->request_keyframe = g_value_get_boolean (value);
break;
+ case PROP_MAX_FRAGMENTATION_UNIT_SIZE:
+ self->max_fragmentation_unit_size = g_value_get_uint (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -145,6 +150,9 @@ gst_rtp_h264_depay_get_property (GObject * object, guint prop_id,
case PROP_REQUEST_KEYFRAME:
g_value_set_boolean (value, self->request_keyframe);
break;
+ case PROP_MAX_FRAGMENTATION_UNIT_SIZE:
+ g_value_set_uint (value, self->max_fragmentation_unit_size);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -194,6 +202,24 @@ gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
DEFAULT_REQUEST_KEYFRAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRtpH264Depay:max-fragmentation-unit-size:
+ *
+ * Maximum size in bytes for a fragmentation unit. Larger units
+ * will be dropped to prevent excessive memory usage.
+ *
+ * Use 0 for automatic.
+ *
+ * Since: 1.28.6
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MAX_FRAGMENTATION_UNIT_SIZE,
+ g_param_spec_uint ("max-fragmentation-unit-size",
+ "Max Fragmentation Unit Size",
+ "Maximum size in bytes for a fragmentation unit (0 = auto)", 0,
+ G_MAXUINT, DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
gst_element_class_add_static_pad_template (gstelement_class,
&gst_rtp_h264_depay_src_template);
gst_element_class_add_static_pad_template (gstelement_class,
@@ -223,6 +249,8 @@ gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
(GDestroyNotify) gst_buffer_unref);
rtph264depay->wait_for_keyframe = DEFAULT_WAIT_FOR_KEYFRAME;
rtph264depay->request_keyframe = DEFAULT_REQUEST_KEYFRAME;
+ rtph264depay->max_fragmentation_unit_size =
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
}
static void
@@ -1396,8 +1424,21 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
rtph264depay->fu_marker = marker;
/* if NAL unit ends, flush the adapter */
- if (E)
+ if (E) {
gst_rtp_h264_finish_fragmentation_unit (rtph264depay);
+ GST_DEBUG_OBJECT (rtph264depay, "End of Fragmentation Unit");
+ } else {
+ guint limit = rtph264depay->max_fragmentation_unit_size ?
+ rtph264depay->max_fragmentation_unit_size :
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
+ if (gst_adapter_available (rtph264depay->adapter) > limit) {
+ GST_WARNING_OBJECT (rtph264depay,
+ "Too big (> %u bytes) fragmentation unit, dropping.", limit);
+ gst_rtp_base_depayload_flush (depayload, FALSE);
+ gst_adapter_clear (rtph264depay->adapter);
+ return NULL;
+ }
+ }
break;
}
default:
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h
index 8ca7381beb..ae3ee4a6e2 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h
@@ -75,6 +75,7 @@ struct _GstRtpH264Depay
gboolean wait_for_keyframe;
gboolean request_keyframe;
gboolean waiting_for_keyframe;
+ guint max_fragmentation_unit_size;
};
struct _GstRtpH264DepayClass
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
index 41d2762ffe..b8d2943228 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
@@ -39,6 +39,13 @@ GST_DEBUG_CATEGORY_STATIC (rtph265depay_debug);
* expressed a restriction or preference via caps */
#define DEFAULT_STREAM_FORMAT GST_H265_STREAM_FORMAT_BYTESTREAM
#define DEFAULT_ACCESS_UNIT FALSE
+#define DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE (32 * 1024 * 1024)
+
+enum
+{
+ PROP_0,
+ PROP_MAX_FRAGMENTATION_UNIT_SIZE,
+};
/* 3 zero bytes syncword */
static const guint8 sync_bytes[] = { 0, 0, 0, 1 };
@@ -119,6 +126,37 @@ static void gst_rtp_h265_depay_push (GstRtpH265Depay * rtph265depay,
GstBuffer * outbuf, gboolean keyframe, GstClockTime timestamp,
gboolean marker);
+static void
+gst_rtp_h265_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpH265Depay *self = GST_RTP_H265_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_MAX_FRAGMENTATION_UNIT_SIZE:
+ self->max_fragmentation_unit_size = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_rtp_h265_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpH265Depay *self = GST_RTP_H265_DEPAY (object);
+
+ switch (prop_id) {
+ case PROP_MAX_FRAGMENTATION_UNIT_SIZE:
+ g_value_set_uint (value, self->max_fragmentation_unit_size);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
static void
gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass)
@@ -132,6 +170,26 @@ gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass)
gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
gobject_class->finalize = gst_rtp_h265_depay_finalize;
+ gobject_class->set_property = gst_rtp_h265_depay_set_property;
+ gobject_class->get_property = gst_rtp_h265_depay_get_property;
+
+ /**
+ * GstRtpH265Depay:max-fragmentation-unit-size:
+ *
+ * Maximum size in bytes for a fragmentation unit. Larger units
+ * will be dropped to prevent excessive memory usage.
+ *
+ * Use 0 for automatic.
+ *
+ * Since: 1.28.6
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_MAX_FRAGMENTATION_UNIT_SIZE,
+ g_param_spec_uint ("max-fragmentation-unit-size",
+ "Max Fragmentation Unit Size",
+ "Maximum size in bytes for a fragmentation unit (0 = auto)", 0,
+ G_MAXUINT, DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_static_pad_template (gstelement_class,
&gst_rtp_h265_depay_src_template);
@@ -165,6 +223,8 @@ gst_rtp_h265_depay_init (GstRtpH265Depay * rtph265depay)
(GDestroyNotify) gst_buffer_unref);
rtph265depay->pps = g_ptr_array_new_with_free_func (
(GDestroyNotify) gst_buffer_unref);
+ rtph265depay->max_fragmentation_unit_size =
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
}
static void
@@ -1516,6 +1576,17 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
if (E) {
gst_rtp_h265_finish_fragmentation_unit (rtph265depay);
GST_DEBUG_OBJECT (rtph265depay, "End of Fragmentation Unit");
+ } else {
+ guint limit = rtph265depay->max_fragmentation_unit_size ?
+ rtph265depay->max_fragmentation_unit_size :
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
+ if (gst_adapter_available (rtph265depay->adapter) > limit) {
+ GST_WARNING_OBJECT (rtph265depay,
+ "Too big (> %u bytes) fragmentation unit, dropping.", limit);
+ gst_rtp_base_depayload_flush (depayload, FALSE);
+ gst_adapter_clear (rtph265depay->adapter);
+ return NULL;
+ }
}
break;
}
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h
index 505bdb5cd1..6e525cc086 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h
@@ -86,6 +86,8 @@ struct _GstRtpH265Depay
/* downstream allocator */
GstAllocator *allocator;
GstAllocationParams params;
+
+ guint max_fragmentation_unit_size;
};
struct _GstRtpH265DepayClass
From 8c6d8dceb16dbde77e451d5b122b864b8420aa75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Tue, 4 Aug 2026 20:05:57 +0300
Subject: [PATCH 2/2] rtph264depay: rtph265depay: Reset missing fields when
resetting during fragmentation unit handling
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12234>
---
subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c | 7 ++++++-
subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c | 7 ++++++-
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
index 9ccd8ab24e..5467a51848 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
@@ -1399,6 +1399,9 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
"%u to %u within Fragmentation Unit. Data was lost, dropping "
"stored.", rtph264depay->last_fu_seqnum,
gst_rtp_buffer_get_seq (rtp));
+ rtph264depay->wait_start = TRUE;
+ rtph264depay->current_fu_type = 0;
+ rtph264depay->last_fu_seqnum = 0;
gst_adapter_clear (rtph264depay->adapter);
return NULL;
}
@@ -1434,7 +1437,9 @@ gst_rtp_h264_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
if (gst_adapter_available (rtph264depay->adapter) > limit) {
GST_WARNING_OBJECT (rtph264depay,
"Too big (> %u bytes) fragmentation unit, dropping.", limit);
- gst_rtp_base_depayload_flush (depayload, FALSE);
+ rtph264depay->wait_start = TRUE;
+ rtph264depay->current_fu_type = 0;
+ rtph264depay->last_fu_seqnum = 0;
gst_adapter_clear (rtph264depay->adapter);
return NULL;
}
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
index b8d2943228..c555835436 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
@@ -1545,6 +1545,9 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
"%u to %u within Fragmentation Unit. Data was lost, dropping "
"stored.", rtph265depay->last_fu_seqnum,
gst_rtp_buffer_get_seq (rtp));
+ rtph265depay->wait_start = TRUE;
+ rtph265depay->current_fu_type = 0;
+ rtph265depay->last_fu_seqnum = 0;
gst_adapter_clear (rtph265depay->adapter);
return NULL;
}
@@ -1583,7 +1586,9 @@ gst_rtp_h265_depay_process (GstRTPBaseDepayload * depayload, GstRTPBuffer * rtp)
if (gst_adapter_available (rtph265depay->adapter) > limit) {
GST_WARNING_OBJECT (rtph265depay,
"Too big (> %u bytes) fragmentation unit, dropping.", limit);
- gst_rtp_base_depayload_flush (depayload, FALSE);
+ rtph265depay->wait_start = TRUE;
+ rtph265depay->current_fu_type = 0;
+ rtph265depay->last_fu_seqnum = 0;
gst_adapter_clear (rtph265depay->adapter);
return NULL;
}

View File

@ -28,7 +28,7 @@
Name: gstreamer1-plugins-good
Version: 1.22.12
Release: 8%{?dist}
Release: 9%{?dist}
Summary: GStreamer plugins with good code and licensing
License: CC0-1.0 AND GPL-2.0-only AND LGPL-2.0-only AND LGPL-2.0-or-later AND LGPL-2.1-only AND LGPL-2.1-or-later AND xlock AND MIT AND BSD-3-Clause AND CC-BY-3.0
@ -80,6 +80,9 @@ Patch0029: 0001-rtpqdm2depay-error-out-if-anyone-tries-to-use-this-e.patch
# https://issues.redhat.com/browse/RHEL-184478
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11797
Patch0030: gstreamer1-plugins-good-1.22.12-CVE-2026-53705.patch
# https://issues.redhat.com/browse/RHEL-224165
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12234
Patch0031: gstreamer1-plugins-good-1.22.12-CVE-2026-18649.patch
BuildRequires: meson >= 0.48.0
BuildRequires: gcc
@ -269,6 +272,7 @@ to be installed.
%patch -P 0028 -p3
%patch -P 0029 -p3
%patch -P 0030 -p3
%patch -P 0031 -p3
%build
%meson \
@ -419,6 +423,11 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -fv {} ';'
%changelog
* Tue Aug 11 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.22.12-9
- Limit maximum fragmentation unit size in RTP H264/H265
depayloaders to prevent excessive memory usage
(CVE-2026-18649)
* Wed Jul 29 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.22.12-8
- Fix integer overflows in wavpackdec (CVE-2026-53705)