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

Backport upstream MR 12234 to fix CVE-2026-18649 in
rtph264depay and rtph265depay elements. The patch limits the
maximum fragmentation unit size (defaulting to 32MB) to prevent
excessive memory usage, and properly resets internal state fields
when errors occur during fragmentation unit handling.

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

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:40:54 +00:00
parent 9b48c1cc9b
commit bf45d4c419
2 changed files with 295 additions and 1 deletions

View File

@ -0,0 +1,288 @@
From 434aec750431e62eac02ee762e79299b3958f97f 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 | 39 +++++++++++++++++
.../gst/rtp/gstrtph265depay.h | 1 +
4 files changed, 83 insertions(+), 1 deletion(-)
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
index bf9b1050f9..55b8b02b4c 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;
@@ -195,6 +203,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,
@@ -227,6 +253,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
@@ -1465,8 +1493,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 ac1f0106f4..27486bf441 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.h
@@ -76,6 +76,7 @@ struct _GstRtpH264Depay
gboolean request_keyframe;
gboolean waiting_for_keyframe;
gboolean requesting_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 177a1103e8..50e24a32e7 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
@@ -41,12 +41,14 @@ GST_DEBUG_CATEGORY_STATIC (rtph265depay_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,
};
@@ -142,6 +144,9 @@ gst_rtp_h265_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;
@@ -161,6 +166,9 @@ gst_rtp_h265_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;
@@ -212,6 +220,24 @@ gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass)
DEFAULT_REQUEST_KEYFRAME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * 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);
gst_element_class_add_static_pad_template (gstelement_class,
@@ -249,6 +275,8 @@ gst_rtp_h265_depay_init (GstRtpH265Depay * rtph265depay)
(GDestroyNotify) gst_buffer_unref);
rtph265depay->wait_for_keyframe = DEFAULT_WAIT_FOR_KEYFRAME;
rtph265depay->request_keyframe = DEFAULT_REQUEST_KEYFRAME;
+ rtph265depay->max_fragmentation_unit_size =
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
}
static void
@@ -1703,6 +1731,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 fc6248e85c..45d9466f7a 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.h
@@ -91,6 +91,7 @@ struct _GstRtpH265Depay
gboolean request_keyframe;
gboolean waiting_for_keyframe;
gboolean requesting_keyframe;
+ guint max_fragmentation_unit_size;
};
struct _GstRtpH265DepayClass
From ab66eaae2f4ef0a4e017f980fa62d2c2f01f46a9 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 | 6 ++++++
subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c | 6 ++++++
2 files changed, 12 insertions(+)
diff --git a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
index 55b8b02b4c..44ddc5b0fa 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph264depay.c
@@ -1467,6 +1467,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_rtp_base_depayload_flush (depayload, FALSE);
gst_adapter_clear (rtph264depay->adapter);
return NULL;
@@ -1503,6 +1506,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);
+ rtph264depay->wait_start = TRUE;
+ rtph264depay->current_fu_type = 0;
+ rtph264depay->last_fu_seqnum = 0;
gst_rtp_base_depayload_flush (depayload, FALSE);
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 50e24a32e7..5748f51f69 100644
--- a/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
+++ b/subprojects/gst-plugins-good/gst/rtp/gstrtph265depay.c
@@ -1699,6 +1699,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_rtp_base_depayload_flush (depayload, FALSE);
gst_adapter_clear (rtph265depay->adapter);
return NULL;
@@ -1738,6 +1741,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);
+ rtph265depay->wait_start = TRUE;
+ rtph265depay->current_fu_type = 0;
+ rtph265depay->last_fu_seqnum = 0;
gst_rtp_base_depayload_flush (depayload, FALSE);
gst_adapter_clear (rtph265depay->adapter);
return NULL;

View File

@ -35,7 +35,7 @@
Name: gstreamer1-plugins-good
Version: 1.26.7
Release: 3%{?dist}
Release: 4%{?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
@ -58,6 +58,8 @@ Source1: gstreamer-good.appdata.xml
Patch: 0001-rtpqdm2depay-error-out-if-anyone-tries-to-use-this-e.patch
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11797
Patch: gstreamer1-plugins-good-1.26.7-CVE-2026-53705.patch
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12234
Patch: gstreamer1-plugins-good-1.26.7-CVE-2026-18649.patch
BuildRequires: meson >= 0.48.0
BuildRequires: gcc
@ -378,6 +380,10 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -fv {} ';'
%changelog
* Tue Aug 11 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.26.7-4
- Fix RTP H264/H265 depayloader fragmentation unit handling (CVE-2026-18649)
Resolves: RHEL-224159
* Wed Jul 29 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.26.7-3
- Fix integer overflow in wavpack decoder (CVE-2026-53705)
Resolves: RHEL-184481