Fix CVE-2026-18649 in H.264/H.265 RTP depayloaders

Backport CVE-2026-18649 fix from upstream GStreamer MR 12244
to gstreamer1-plugins-good 1.16.1. The patch adds a
max-fragmentation-unit-size property (default 32 MB) to both
H.264 and H.265 RTP depayloaders. If a fragmentation unit
exceeds this limit while being assembled, it is dropped and
the depayloader state is reset, preventing excessive memory
usage from crafted RTP streams.

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

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-13 14:36:59 +00:00
parent 1a5072bc97
commit 14df9f8d70
2 changed files with 305 additions and 1 deletions

View File

@ -0,0 +1,296 @@
From 07cbde0479905b968c54f6ca22999aa9b62bd653 Mon Sep 17 00:00:00 2001
From: RHEL Packaging Agent <redhat-ymir-agent@redhat.com>
Date: Fri, 7 Aug 2026 14:34:04 +0000
Subject: [PATCH] rtph264depay: rtph265depay: Limit the maximum fragmentation
unit size
Adds a max-fragmentation-unit-size property (default 32 MB) to both
H.264 and H.265 RTP depayloaders. If a fragmentation unit exceeds
this limit while being assembled, it is dropped and the depayloader
state is reset to prevent excessive memory usage.
Adapted from upstream commits:
- 5cd490c125e04676659593b0f5b19130fc2face7
- 820bd15585b13af8be9b0131699655194ae68a5b
Fixes: CVE-2026-18649
---
gst/rtp/gstrtph264depay.c | 79 ++++++++++++++++++++++++++++++++++++++-
gst/rtp/gstrtph264depay.h | 2 +
gst/rtp/gstrtph265depay.c | 75 +++++++++++++++++++++++++++++++++++++
gst/rtp/gstrtph265depay.h | 2 +
4 files changed, 157 insertions(+), 1 deletion(-)
diff --git a/gst/rtp/gstrtph264depay.c b/gst/rtp/gstrtph264depay.c
index 275a9a0..625244f 100644
--- a/gst/rtp/gstrtph264depay.c
+++ b/gst/rtp/gstrtph264depay.c
@@ -38,6 +38,13 @@ GST_DEBUG_CATEGORY_STATIC (rtph264depay_debug);
* expressed a restriction or preference via caps */
#define DEFAULT_BYTE_STREAM TRUE
#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 };
@@ -83,6 +90,10 @@ G_DEFINE_TYPE (GstRtpH264Depay, gst_rtp_h264_depay,
GST_TYPE_RTP_BASE_DEPAYLOAD);
static void gst_rtp_h264_depay_finalize (GObject * object);
+static void gst_rtp_h264_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h264_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
static GstStateChangeReturn gst_rtp_h264_depay_change_state (GstElement *
element, GstStateChange transition);
@@ -111,6 +122,24 @@ gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
gobject_class->finalize = gst_rtp_h264_depay_finalize;
+ gobject_class->set_property = gst_rtp_h264_depay_set_property;
+ gobject_class->get_property = gst_rtp_h264_depay_get_property;
+
+ /**
+ * 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.
+ */
+ 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);
@@ -128,6 +157,38 @@ gst_rtp_h264_depay_class_init (GstRtpH264DepayClass * klass)
gstrtpbasedepayload_class->handle_event = gst_rtp_h264_depay_handle_event;
}
+static void
+gst_rtp_h264_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstRtpH264Depay *self = GST_RTP_H264_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_h264_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstRtpH264Depay *self = GST_RTP_H264_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_h264_depay_init (GstRtpH264Depay * rtph264depay)
{
@@ -139,6 +200,8 @@ gst_rtp_h264_depay_init (GstRtpH264Depay * rtph264depay)
(GDestroyNotify) gst_buffer_unref);
rtph264depay->pps = g_ptr_array_new_with_free_func (
(GDestroyNotify) gst_buffer_unref);
+ rtph264depay->max_fragmentation_unit_size =
+ DEFAULT_MAX_FRAGMENTATION_UNIT_SIZE;
}
static void
@@ -1241,8 +1304,22 @@ 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);
+ rtph264depay->wait_start = TRUE;
+ rtph264depay->current_fu_type = 0;
+ gst_adapter_clear (rtph264depay->adapter);
+ return NULL;
+ }
+ }
break;
}
default:
diff --git a/gst/rtp/gstrtph264depay.h b/gst/rtp/gstrtph264depay.h
index ba41312..a02a65d 100644
--- a/gst/rtp/gstrtph264depay.h
+++ b/gst/rtp/gstrtph264depay.h
@@ -62,6 +62,8 @@ struct _GstRtpH264Depay
GstClockTime fu_timestamp;
gboolean fu_marker;
+ guint max_fragmentation_unit_size;
+
/* misc */
GPtrArray *sps;
GPtrArray *pps;
diff --git a/gst/rtp/gstrtph265depay.c b/gst/rtp/gstrtph265depay.c
index 551e08a..b046030 100644
--- a/gst/rtp/gstrtph265depay.c
+++ b/gst/rtp/gstrtph265depay.c
@@ -38,6 +38,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 };
@@ -99,6 +106,10 @@ G_DEFINE_TYPE (GstRtpH265Depay, gst_rtp_h265_depay,
GST_TYPE_RTP_BASE_DEPAYLOAD);
static void gst_rtp_h265_depay_finalize (GObject * object);
+static void gst_rtp_h265_depay_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_rtp_h265_depay_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
static GstStateChangeReturn gst_rtp_h265_depay_change_state (GstElement *
element, GstStateChange transition);
@@ -128,6 +139,24 @@ 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.
+ */
+ 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);
@@ -145,6 +174,38 @@ gst_rtp_h265_depay_class_init (GstRtpH265DepayClass * klass)
gstrtpbasedepayload_class->handle_event = gst_rtp_h265_depay_handle_event;
}
+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_init (GstRtpH265Depay * rtph265depay)
{
@@ -161,6 +222,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
@@ -1520,6 +1583,18 @@ 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);
+ rtph265depay->wait_start = TRUE;
+ rtph265depay->current_fu_type = 0;
+ gst_adapter_clear (rtph265depay->adapter);
+ return NULL;
+ }
}
break;
}
diff --git a/gst/rtp/gstrtph265depay.h b/gst/rtp/gstrtph265depay.h
index cf17694..e851d3b 100644
--- a/gst/rtp/gstrtph265depay.h
+++ b/gst/rtp/gstrtph265depay.h
@@ -76,6 +76,8 @@ struct _GstRtpH265Depay
GstClockTime fu_timestamp;
gboolean fu_marker;
+ guint max_fragmentation_unit_size;
+
/* misc */
GPtrArray *vps;
GPtrArray *sps;

View File

@ -15,7 +15,7 @@
Name: gstreamer1-plugins-good
Version: 1.16.1
Release: 7%{?gitcommit:.git%{shortcommit}}%{?dist}.1
Release: 7%{?gitcommit:.git%{shortcommit}}%{?dist}.2
Summary: GStreamer plugins with good code and licensing
License: LGPLv2+
@ -45,6 +45,9 @@ Patch10: gstreamer1-plugins-good-1.16.1-CVE-2026-53705.patch
# https://issues.redhat.com/browse/RHEL-239068
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12231
Patch11: gstreamer1-plugins-good-1.16.1-CVE-2026-73433.patch
# https://issues.redhat.com/browse/RHEL-224145
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12244
Patch12: gstreamer1-plugins-good-1.16.1-CVE-2026-18649.patch
BuildRequires: gcc
BuildRequires: gcc-c++
@ -190,6 +193,7 @@ to be installed.
%patch9 -p1
%patch10 -p1
%patch11 -p1
%patch12 -p1
%build
%configure --disable-silent-rules --disable-fatal-warnings \
@ -374,6 +378,10 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%changelog
* Thu Aug 13 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.16.1-7.2
- Fix CVE-2026-18649 in H.264/H.265 RTP depayloaders
Resolves: RHEL-224145
* Thu Aug 13 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.16.1-7.1
- Fix multiple security issues in AVI demuxer (CVE-2026-73433)
Resolves: RHEL-239068