Fix CVE-2026-18296: heap buffer overflow in qtmoovrecover

Backport upstream commit 93fa4cd30ba4 to fix CVE-2026-18296.
The patch adds validation of box sizes and box versions in
atomsrecovery.c (qtmoovrecover), preventing potential security
issues. The upstream monorepo path prefix was stripped to fit
the standalone gst-plugins-good source tree used in RHEL 8.
Added as Patch14 following the existing CVE patch naming
convention.

CVE: CVE-2026-18296
Upstream patches:
 - 93fa4cd30b.patch
Resolves: RHEL-246549

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-22 12:38:59 +00:00
parent 10effc6042
commit be69763989
2 changed files with 269 additions and 1 deletions

View File

@ -0,0 +1,259 @@
From d487603fa1f0eb7202a7e3f662eb7617da4969ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Wed, 17 Jun 2026 16:18:50 +0300
Subject: [PATCH] qtmoovrecover: Validate box sizes
Also validate box versions where it matters.
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/work_items/5118
Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/work_items/5120
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/12041>
---
gst/isomp4/atomsrecovery.c | 88 ++++++++++++++++++++++++++++++++++++--
1 file changed, 84 insertions(+), 4 deletions(-)
diff --git a/gst/isomp4/atomsrecovery.c b/gst/isomp4/atomsrecovery.c
index edc4434..1761854 100644
--- a/gst/isomp4/atomsrecovery.c
+++ b/gst/isomp4/atomsrecovery.c
@@ -283,6 +283,8 @@ moov_recov_file_parse_prefix (MoovRecovFile * moovrf)
if (!read_atom_header (moovrf->file, &fourcc, &size)) {
return FALSE;
}
+ if (size < 8)
+ return FALSE;
if (fourcc != FOURCC_ftyp) {
/* we might have a prefix here */
@@ -294,6 +296,8 @@ moov_recov_file_parse_prefix (MoovRecovFile * moovrf)
/* now read the ftyp */
if (!read_atom_header (moovrf->file, &fourcc, &size))
return FALSE;
+ if (size < 8)
+ return FALSE;
}
/* this has to be the ftyp */
@@ -315,12 +319,25 @@ moov_recov_file_parse_mvhd (MoovRecovFile * moovrf)
/* check for sanity */
if (fourcc != FOURCC_mvhd)
return FALSE;
+ if (size < 8)
+ return FALSE;
moovrf->mvhd_size = size;
moovrf->mvhd_pos = ftell (moovrf->file) - 8;
+ guint8 version;
+ if (fread (&version, 1, 1, moovrf->file) != 1)
+ return FALSE;
+ if (version != 0) {
+ GST_WARNING ("Version %d mvhd not supported", version);
+ return FALSE;
+ }
+
+ if (size != 108)
+ return FALSE;
+
/* skip the remaining of the mvhd in the file */
- return fseek (moovrf->file, size - 8, SEEK_CUR) == 0;
+ return fseek (moovrf->file, size - 8 - 1, SEEK_CUR) == 0;
}
static gboolean
@@ -357,6 +374,8 @@ mdat_recov_file_find_mdat (FILE * file, GError ** err)
case FOURCC_ftyp:
case FOURCC_free:
case FOURCC_udta:
+ if (size < 8)
+ return FALSE;
if (fseek (file, size - 8, SEEK_CUR) != 0) {
goto file_seek_error;
}
@@ -486,6 +505,8 @@ skip_atom (MoovRecovFile * moovrf, guint32 expected_fourcc)
return FALSE;
if (fourcc != expected_fourcc)
return FALSE;
+ if (size < 8)
+ return FALSE;
return (fseek (moovrf->file, size - 8, SEEK_CUR) == 0);
}
@@ -502,11 +523,24 @@ moov_recov_parse_tkhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
if (fourcc != FOURCC_tkhd)
return FALSE;
+ if (size < 8)
+ return FALSE;
trakrd->tkhd_file_offset = ftell (moovrf->file) - 8;
- /* move 8 bytes forward to the trak_id pos */
- if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
+ guint8 version;
+ if (fread (&version, 1, 1, moovrf->file) != 1)
+ return FALSE;
+ if (version != 0) {
+ GST_WARNING ("Version %d tkhd not supported", version);
+ return FALSE;
+ }
+
+ if (size != 92)
+ return FALSE;
+
+ /* move 12-1 bytes forward to the trak_id pos */
+ if (fseek (moovrf->file, 12 - 1, SEEK_CUR) != 0)
return FALSE;
if (fread (data, 1, 4, moovrf->file) != 4)
return FALSE;
@@ -530,6 +564,8 @@ moov_recov_parse_stbl (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
if (fourcc != FOURCC_stbl)
return FALSE;
+ if (size < 8)
+ return FALSE;
trakrd->stbl_file_offset = ftell (moovrf->file) - 8;
trakrd->stbl_size = size;
@@ -539,12 +575,17 @@ moov_recov_parse_stbl (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
if (fourcc != FOURCC_stsd)
return FALSE;
+ if (auxsize < 8)
+ return FALSE;
if (fseek (moovrf->file, auxsize - 8, SEEK_CUR) != 0)
return FALSE;
trakrd->stsd_size = auxsize;
trakrd->post_stsd_offset = ftell (moovrf->file);
+ if (trakrd->stbl_size < trakrd->post_stsd_offset - trakrd->stbl_file_offset)
+ return FALSE;
+
/* as this is the last atom we parse, we don't skip forward */
return TRUE;
@@ -556,11 +597,14 @@ moov_recov_parse_minf (MoovRecovFile * moovrf, TrakRecovData * trakrd)
guint32 size;
guint32 fourcc;
guint32 auxsize;
+ guint64 offset;
if (!read_atom_header (moovrf->file, &fourcc, &size))
return FALSE;
if (fourcc != FOURCC_minf)
return FALSE;
+ if (size < 8)
+ return FALSE;
trakrd->minf_file_offset = ftell (moovrf->file) - 8;
trakrd->minf_size = size;
@@ -571,17 +615,23 @@ moov_recov_parse_minf (MoovRecovFile * moovrf, TrakRecovData * trakrd)
if (fourcc != FOURCC_vmhd && fourcc != FOURCC_smhd && fourcc != FOURCC_hmhd &&
fourcc != FOURCC_gmhd)
return FALSE;
+ if (auxsize < 8)
+ return FALSE;
if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
return FALSE;
/* skip a possible hdlr and the following dinf */
if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
return FALSE;
+ if (auxsize < 8)
+ return FALSE;
if (fourcc == FOURCC_hdlr) {
if (fseek (moovrf->file, auxsize - 8, SEEK_CUR))
return FALSE;
if (!read_atom_header (moovrf->file, &fourcc, &auxsize))
return FALSE;
+ if (auxsize < 8)
+ return FALSE;
}
if (fourcc != FOURCC_dinf)
return FALSE;
@@ -592,6 +642,10 @@ moov_recov_parse_minf (MoovRecovFile * moovrf, TrakRecovData * trakrd)
if (!moov_recov_parse_stbl (moovrf, trakrd))
return FALSE;
+ offset = ftell (moovrf->file);
+ if (trakrd->minf_size < offset - trakrd->minf_file_offset)
+ return FALSE;
+
return TRUE;
}
@@ -607,11 +661,24 @@ moov_recov_parse_mdhd (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
if (fourcc != FOURCC_mdhd)
return FALSE;
+ if (size < 8)
+ return FALSE;
trakrd->mdhd_file_offset = ftell (moovrf->file) - 8;
+ guint8 version;
+ if (fread (&version, 1, 1, moovrf->file) != 1)
+ return FALSE;
+ if (version != 0) {
+ GST_WARNING ("Version %d mdhd not supported", version);
+ return FALSE;
+ }
+
+ if (size != 32)
+ return FALSE;
+
/* get the timescale */
- if (fseek (moovrf->file, 12, SEEK_CUR) != 0)
+ if (fseek (moovrf->file, 12 - 1, SEEK_CUR) != 0)
return FALSE;
if (fread (data, 1, 4, moovrf->file) != 4)
return FALSE;
@@ -626,12 +693,15 @@ moov_recov_parse_mdia (MoovRecovFile * moovrf, TrakRecovData * trakrd)
{
guint32 size;
guint32 fourcc;
+ guint64 offset;
/* make sure we are on a tkhd atom */
if (!read_atom_header (moovrf->file, &fourcc, &size))
return FALSE;
if (fourcc != FOURCC_mdia)
return FALSE;
+ if (size < 8)
+ return FALSE;
trakrd->mdia_file_offset = ftell (moovrf->file) - 8;
trakrd->mdia_size = size;
@@ -643,6 +713,11 @@ moov_recov_parse_mdia (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
if (!moov_recov_parse_minf (moovrf, trakrd))
return FALSE;
+
+ offset = ftell (moovrf->file);
+ if (trakrd->mdia_size < offset - trakrd->mdia_file_offset)
+ return FALSE;
+
return TRUE;
}
@@ -665,6 +740,8 @@ moov_recov_parse_trak (MoovRecovFile * moovrf, TrakRecovData * trakrd)
if (fourcc != FOURCC_trak) {
return FALSE;
}
+ if (size < 8)
+ return FALSE;
trakrd->trak_size = size;
/* now we should have a trak header 'tkhd' */
@@ -683,6 +760,9 @@ moov_recov_parse_trak (MoovRecovFile * moovrf, TrakRecovData * trakrd)
return FALSE;
trakrd->extra_atoms_offset = ftell (moovrf->file);
+ if (trakrd->trak_size < trakrd->extra_atoms_offset - offset)
+ return FALSE;
+
trakrd->extra_atoms_size = size - (trakrd->extra_atoms_offset - offset);
trakrd->file_offset = offset;

View File

@ -15,7 +15,7 @@
Name: gstreamer1-plugins-good
Version: 1.16.1
Release: 7%{?gitcommit:.git%{shortcommit}}%{?dist}.3
Release: 7%{?gitcommit:.git%{shortcommit}}%{?dist}.4
Summary: GStreamer plugins with good code and licensing
License: LGPLv2+
@ -51,6 +51,9 @@ Patch12: gstreamer1-plugins-good-1.16.1-CVE-2026-18649.patch
# https://issues.redhat.com/browse/RHEL-239048
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/0bcc6564c7deedc7d6d7373a2ab6479c9bf3889f
Patch13: gstreamer1-plugins-good-1.16.1-CVE-2026-73434.patch
# https://issues.redhat.com/browse/RHEL-246549
# https://gitlab.freedesktop.org/gstreamer/gstreamer/-/commit/93fa4cd30ba43b38b02a9de76a7a80dc198c87a0
Patch14: gstreamer1-plugins-good-1.16.1-CVE-2026-18296.patch
BuildRequires: gcc
BuildRequires: gcc-c++
@ -198,6 +201,7 @@ to be installed.
%patch11 -p1
%patch12 -p1
%patch13 -p1
%patch14 -p1
%build
%configure --disable-silent-rules --disable-fatal-warnings \
@ -382,6 +386,11 @@ find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
%changelog
* Sat Aug 22 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.16.1-7.4
- Fix CVE-2026-18296: validate box sizes and versions in
qtmoovrecover (atomsrecovery)
Resolves: RHEL-246549
* Thu Aug 13 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 1.16.1-7.3
- Fix CVE-2026-73434: out-of-bounds read in AVI demuxer vprp handling
Resolves: RHEL-239048