Version in base suite: 1.26.2-3 Base version: gst-plugins-bad1.0_1.26.2-3 Target version: gst-plugins-bad1.0_1.26.2-3+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/g/gst-plugins-bad1.0/gst-plugins-bad1.0_1.26.2-3.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/g/gst-plugins-bad1.0/gst-plugins-bad1.0_1.26.2-3+deb13u1.dsc changelog | 10 patches/CVE-2026-2923.patch | 550 ++++++++++++++++++++++++++++++++++++++++++++ patches/CVE-2026-3081.patch | 43 +++ patches/CVE-2026-3082.patch | 19 + patches/CVE-2026-3084.patch | 41 +++ patches/CVE-2026-3086.patch | 16 + patches/series | 5 7 files changed, 684 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpktj5oauz/gst-plugins-bad1.0_1.26.2-3.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpktj5oauz/gst-plugins-bad1.0_1.26.2-3+deb13u1.dsc: no acceptable signature found diff -Nru gst-plugins-bad1.0-1.26.2/debian/changelog gst-plugins-bad1.0-1.26.2/debian/changelog --- gst-plugins-bad1.0-1.26.2/debian/changelog 2025-07-10 08:07:14.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/changelog 2026-03-30 21:57:55.000000000 +0000 @@ -1,3 +1,13 @@ +gst-plugins-bad1.0 (1.26.2-3+deb13u1) trixie-security; urgency=medium + + * CVE-2026-2923 + * CVE-2026-3081 + * CVE-2026-3082 + * CVE-2026-3084 + * CVE-2026-3086 + + -- Moritz Mühlenhoff Mon, 30 Mar 2026 23:57:55 +0200 + gst-plugins-bad1.0 (1.26.2-3) unstable; urgency=medium * d/patches: 0001-h266parser-Fix-overflow-when-parsing-subpic_level_in.patch diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-2923.patch gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-2923.patch --- gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-2923.patch 1970-01-01 00:00:00.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-2923.patch 2026-03-30 21:57:50.000000000 +0000 @@ -0,0 +1,550 @@ +From 729d2715568831ff25aeb4fee5312edb49bde9f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= +Date: Wed, 25 Feb 2026 17:22:52 +0200 +Subject: [PATCH] dvbsuboverlay: Mark parsed byte array as const + +From 7be5f191f01f3a8e114f4c6e8fb783716f51e98a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= +Date: Wed, 11 Feb 2026 20:45:12 +0200 +Subject: [PATCH] dvbsuboverlay: Add missing bounds checks to the parser + everywhere + +From 504f965a086ab8cf2d223a1a99d03a71b67458bc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= +Date: Thu, 12 Feb 2026 09:50:23 +0200 +Subject: [PATCH] dvbsuboverlay: Avoid integer overflows and unreasonably large + displays/regions + +--- gst-plugins-bad1.0-1.26.2.orig/gst/dvbsuboverlay/dvb-sub.c ++++ gst-plugins-bad1.0-1.26.2/gst/dvbsuboverlay/dvb-sub.c +@@ -373,8 +373,8 @@ dvb_sub_init (void) + } + + static void +-_dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, +- gint buf_size) ++_dvb_sub_parse_page_segment (DvbSub * dvb_sub, guint16 page_id, ++ const guint8 * buf, gint buf_size) + { /* FIXME: Use guint for buf_size here and in many other places? */ + DVBSubRegionDisplay *display; + DVBSubRegionDisplay *tmp_display_list, **tmp_ptr; +@@ -451,8 +451,8 @@ _dvb_sub_parse_page_segment (DvbSub * dv + } + + static void +-_dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, +- gint buf_size) ++_dvb_sub_parse_region_segment (DvbSub * dvb_sub, guint16 page_id, ++ const guint8 * buf, gint buf_size) + { + const guint8 *buf_end = buf + buf_size; + guint8 region_id; +@@ -483,6 +483,17 @@ _dvb_sub_parse_region_segment (DvbSub * + region->height = GST_READ_UINT16_BE (buf); + buf += 2; + ++ /* Avoid integer overflows and also clamp to a reasonable size of 8kx8k for ++ * the region size. We allow 16kx16k display sizes. */ ++ if (region->width > 8192 || region->height > 8192) { ++ GST_WARNING ("too large region of %ux%x", region->width, region->height); ++ g_free (region->pbuf); ++ region->pbuf = NULL; ++ region->buf_size = 0; ++ region->width = region->height = 0; ++ return; ++ } ++ + if (region->width * region->height != region->buf_size) { /* FIXME: Read closer from spec what happens when dimensions change */ + g_free (region->pbuf); + +@@ -574,8 +585,8 @@ _dvb_sub_parse_region_segment (DvbSub * + } + + static void +-_dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, +- gint buf_size) ++_dvb_sub_parse_clut_segment (DvbSub * dvb_sub, guint16 page_id, ++ const guint8 * buf, gint buf_size) + { + const guint8 *buf_end = buf + buf_size; + guint8 clut_id; +@@ -585,6 +596,9 @@ _dvb_sub_parse_clut_segment (DvbSub * dv + + GST_MEMDUMP ("DVB clut packet", buf, buf_size); + ++ if (buf_size < 1) ++ return; ++ + clut_id = *buf++; + buf += 1; + +@@ -601,7 +615,7 @@ _dvb_sub_parse_clut_segment (DvbSub * dv + dvb_sub->clut_list = clut; + } + +- while (buf + 4 < buf_end) { ++ while (buf + 2 < buf_end) { + entry_id = *buf++; + + depth = (*buf) & 0xe0; +@@ -614,11 +628,15 @@ _dvb_sub_parse_clut_segment (DvbSub * dv + full_range = (*buf++) & 1; + + if (full_range) { ++ if (buf + 4 > buf_end) ++ break; + y = *buf++; + cr = *buf++; + cb = *buf++; + alpha = *buf++; + } else { ++ if (buf + 2 > buf_end) ++ break; + y = buf[0] & 0xfc; + cr = (((buf[0] & 3) << 2) | ((buf[1] >> 6) & 3)) << 4; + cb = (buf[1] << 2) & 0xf0; +@@ -633,11 +651,11 @@ _dvb_sub_parse_clut_segment (DvbSub * dv + GST_DEBUG ("CLUT DEFINITION: clut %d := (%d,%d,%d,%d)", entry_id, y, cb, cr, + alpha); + +- if (depth & 0x80) ++ if ((depth & 0x80) && entry_id < 4) + clut->clut4[entry_id] = AYUV (y, cb, cr, 255 - alpha); +- if (depth & 0x40) ++ if ((depth & 0x40) && entry_id < 16) + clut->clut16[entry_id] = AYUV (y, cb, cr, 255 - alpha); +- if (depth & 0x20) ++ if ((depth & 0x20) && entry_id < 256) + clut->clut256[entry_id] = AYUV (y, cb, cr, 255 - alpha); + } + } +@@ -649,8 +667,6 @@ _dvb_sub_read_2bit_string (guint8 * dest + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) + { + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); +- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ +- + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; +@@ -661,23 +677,29 @@ _dvb_sub_read_2bit_string (guint8 * dest + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 1)) { + guint run_length = 0, clut_index = 0; + +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2)) ++ goto not_enough_data; + + if (bits) { /* 2-bit_pixel-code */ + run_length = 1; + clut_index = bits; + } else { /* 2-bit_zero */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1)) ++ goto not_enough_data; + if (bits == 1) { /* switch_1 == '1' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3)) ++ goto not_enough_data; + run_length += 3; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2)) ++ goto not_enough_data; + } else { /* switch_1 == '0' */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1)) ++ goto not_enough_data; + if (bits == 1) { /* switch_2 == '1' */ + run_length = 1; /* 1x pseudo-colour '00' */ + } else { /* switch_2 == '0' */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2)) ++ goto not_enough_data; + switch (bits) { /* switch_3 */ + case 0x0: /* end of 2-bit/pixel_code_string */ + stop_parsing = TRUE; +@@ -686,14 +708,18 @@ _dvb_sub_read_2bit_string (guint8 * dest + run_length = 2; + break; + case 0x2: /* the following 6 bits contain run length coded pixel data */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4)) ++ goto not_enough_data; + run_length += 12; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2)) ++ goto not_enough_data; + break; + case 0x3: /* the following 10 bits contain run length coded pixel data */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8)) ++ goto not_enough_data; + run_length += 29; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 2)) ++ goto not_enough_data; + break; + } + } +@@ -727,13 +753,18 @@ _dvb_sub_read_2bit_string (guint8 * dest + pixels_read += run_length; + } + +- // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good +- //gst_bit_reader_skip_to_byte (&gb); +- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3; ++ gst_bit_reader_skip_to_byte (&gb); ++ *srcbuf = gb.data + gb.byte; + + GST_TRACE ("PIXEL: returning, read %u pixels", pixels_read); + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; ++ ++not_enough_data: ++ GST_WARNING ("Not enough data"); ++ // Go to the end of the buffer so the caller stops parsing ++ *srcbuf += buf_size; ++ return 0; + } + + // FFMPEG-FIXME: The same code in ffmpeg is much more complex, it could use the same +@@ -743,7 +774,6 @@ _dvb_sub_read_4bit_string (guint8 * dest + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) + { + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); +- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; +@@ -755,28 +785,35 @@ _dvb_sub_read_4bit_string (guint8 * dest + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 3)) { + guint run_length = 0, clut_index = 0; + +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 4)) ++ goto not_enough_data; + + if (bits) { + run_length = 1; + clut_index = bits; + } else { +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1)) ++ goto not_enough_data; + if (bits == 0) { /* switch_1 == '0' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 3); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 3)) ++ goto not_enough_data; + if (!run_length) { + stop_parsing = TRUE; + } else { + run_length += 2; + } + } else { /* switch_1 == '1' */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1)) ++ goto not_enough_data; + if (bits == 0) { /* switch_2 == '0' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 2)) ++ goto not_enough_data; + run_length += 4; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4)) ++ goto not_enough_data; + } else { /* switch_2 == '1' */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 2); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 2)) ++ goto not_enough_data; + switch (bits) { + case 0x0: /* switch_3 == '00' */ + run_length = 1; /* 1 pixel of pseudo-color 0 */ +@@ -785,14 +822,18 @@ _dvb_sub_read_4bit_string (guint8 * dest + run_length = 2; /* 2 pixels of pseudo-color 0 */ + break; + case 0x2: /* switch_3 == '10' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 4)) ++ goto not_enough_data; + run_length += 9; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4)) ++ goto not_enough_data; + break; + case 0x3: /* switch_3 == '11' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 8)) ++ goto not_enough_data; + run_length += 25; +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 4); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 4)) ++ goto not_enough_data; + break; + } + } +@@ -826,14 +867,19 @@ _dvb_sub_read_4bit_string (guint8 * dest + pixels_read += run_length; + } + +- // FIXME: Test skip_to_byte instead of adding 7 bits, once everything else is working good +- //gst_bit_reader_skip_to_byte (&gb); +- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3; ++ gst_bit_reader_skip_to_byte (&gb); ++ *srcbuf = gb.data + gb.byte; + + GST_LOG ("Returning with %u pixels read", pixels_read); + + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; ++ ++not_enough_data: ++ GST_WARNING ("Not enough data"); ++ // Go to the end of the buffer so the caller stops parsing ++ *srcbuf += buf_size; ++ return 0; + } + + static int +@@ -841,8 +887,6 @@ _dvb_sub_read_8bit_string (guint8 * dest + const guint8 ** srcbuf, gint buf_size, guint8 non_mod, guint8 * map_table) + { + GstBitReader gb = GST_BIT_READER_INIT (*srcbuf, buf_size); +- /* FIXME: Handle FALSE returns from gst_bit_reader_get_* calls? */ +- + gboolean stop_parsing = FALSE; + guint32 bits = 0; + guint32 pixels_read = 0; +@@ -858,23 +902,29 @@ _dvb_sub_read_8bit_string (guint8 * dest + /* Rephrased - it's better to work with bytes with default value '0' instead of reading from memory we don't own. */ + while (!stop_parsing && (gst_bit_reader_get_remaining (&gb) > 7)) { + guint run_length = 0, clut_index = 0; +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8); ++ ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 8)) ++ goto not_enough_data; + + if (bits) { /* 8-bit_pixel-code */ + run_length = 1; + clut_index = bits; + } else { /* 8-bit_zero */ +- bits = gst_bit_reader_get_bits_uint32_unchecked (&gb, 1); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &bits, 1)) ++ goto not_enough_data; + if (bits == 0) { /* switch_1 == '0' */ + /* run_length_1-127 for pseudo-colour _entry) '0x00' */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7)) ++ goto not_enough_data; + if (run_length == 0) { /* end_of_string_signal */ + stop_parsing = TRUE; + } + } else { /* switch_1 == '1' */ + /* run_length_3-127 */ +- run_length = gst_bit_reader_get_bits_uint32_unchecked (&gb, 7); +- clut_index = gst_bit_reader_get_bits_uint32_unchecked (&gb, 8); ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &run_length, 7)) ++ goto not_enough_data; ++ if (!gst_bit_reader_get_bits_uint32 (&gb, &clut_index, 8)) ++ goto not_enough_data; + + if (run_length < 3) { + GST_WARNING ("runlength value was %u, but the spec requires it " +@@ -912,10 +962,17 @@ _dvb_sub_read_8bit_string (guint8 * dest + + GST_LOG ("Returning with %u pixels read", pixels_read); + +- *srcbuf += (gst_bit_reader_get_pos (&gb) + 7) >> 3; ++ gst_bit_reader_skip_to_byte (&gb); ++ *srcbuf = gb.data + gb.byte; + + // FIXME: Shouldn't need this variable if tracking things in the loop better + return pixels_read; ++ ++not_enough_data: ++ GST_WARNING ("Not enough data"); ++ // Go to the end of the buffer so the caller stops parsing ++ *srcbuf += buf_size; ++ return 0; + } + + static void +@@ -928,7 +985,6 @@ _dvb_sub_parse_pixel_data_block (DvbSub + guint8 *pbuf; + int x_pos, y_pos; + int i; +- gboolean dest_buf_filled = FALSE; + + guint8 map2to4[] = { 0x0, 0x7, 0x8, 0xf }; + guint8 map2to8[] = { 0x00, 0x77, 0x88, 0xff }; +@@ -963,24 +1019,13 @@ _dvb_sub_parse_pixel_data_block (DvbSub + + // FFMPEG-FIXME: ffmpeg doesn't check for equality and so can overflow destination buffer later on with bad input data + // FFMPEG-FIXME: However that makes it warn on end_of_object_line and map tables as well, so we add the dest_buf_filled tracking +- // FIXME: Removed x_pos checking here, because we don't want to turn dest_buf_filled to TRUE permanently in that case +- // FIXME: We assume that region->width - x_pos as dbuf_len to read_nbit_string will take care of that case nicely; +- // FIXME: That is, that read_nbit_string never scribbles anything if dbuf_len passed to it is zero due to this. +- if (y_pos >= region->height) { +- dest_buf_filled = TRUE; ++ if (x_pos >= region->width || y_pos >= region->height) { ++ GST_WARNING ("Invalid object location for data_type 0x%x!", *buf); ++ return; + } + + switch (*buf++) { + case 0x10: +- if (dest_buf_filled) { +- /* FIXME: Be more verbose */ +- GST_WARNING ("Invalid object location for data_type 0x%x!", +- *(buf - 1)); +- GST_MEMDUMP ("Remaining data after invalid object location:", buf, +- (guint) (buf_end - buf)); +- return; +- } +- + if (region->depth == 8) + map_table = map2to8; + else if (region->depth == 4) +@@ -995,15 +1040,6 @@ _dvb_sub_parse_pixel_data_block (DvbSub + region->width - x_pos, &buf, buf_end - buf, non_mod, map_table); + break; + case 0x11: +- if (dest_buf_filled) { +- /* FIXME: Be more verbose */ +- GST_WARNING ("Invalid object location for data_type 0x%x!", +- *(buf - 1)); +- GST_MEMDUMP ("Remaining data after invalid object location:", buf, +- buf_end - buf); +- return; // FIXME: Perhaps tell read_nbit_string that dbuf_len is zero and let it walk the bytes regardless? (Same FIXME for 2bit and 8bit) +- } +- + if (region->depth < 4) { + GST_WARNING ("4-bit pixel string in %d-bit region!", region->depth); + return; +@@ -1024,15 +1060,6 @@ _dvb_sub_parse_pixel_data_block (DvbSub + GST_DEBUG ("READ_4BIT_STRING finished: buf pointer now %p", buf); + break; + case 0x12: +- if (dest_buf_filled) { +- /* FIXME: Be more verbose */ +- GST_WARNING ("Invalid object location for data_type 0x%x!", +- *(buf - 1)); +- GST_MEMDUMP ("Remaining data after invalid object location:", +- buf, (guint) (buf_end - buf)); +- return; +- } +- + if (region->depth < 8) { + GST_WARNING ("8-bit pixel string in %d-bit region!", region->depth); + return; +@@ -1046,19 +1073,29 @@ _dvb_sub_parse_pixel_data_block (DvbSub + + case 0x20: + GST_DEBUG ("handling map2to4 table data"); +- /* FIXME: I don't see any guards about buffer size here - buf++ happens with the switch, but +- * FIXME: buffer is walked without length checks? Same deal in other map table cases */ ++ if (buf + 2 > buf_end) { ++ GST_WARNING ("map2to4 table too short"); ++ return; ++ } + map2to4[0] = (*buf) >> 4; + map2to4[1] = (*buf++) & 0xf; + map2to4[2] = (*buf) >> 4; + map2to4[3] = (*buf++) & 0xf; + break; + case 0x21: ++ if (buf + 4 > buf_end) { ++ GST_WARNING ("map2to8 table too short"); ++ return; ++ } + GST_DEBUG ("handling map2to8 table data"); + for (i = 0; i < 4; i++) + map2to8[i] = *buf++; + break; + case 0x22: ++ if (buf + 16 > buf_end) { ++ GST_WARNING ("map4to8 table too short"); ++ return; ++ } + GST_DEBUG ("handling map4to8 table data"); + for (i = 0; i < 16; i++) + map4to8[i] = *buf++; +@@ -1076,8 +1113,8 @@ _dvb_sub_parse_pixel_data_block (DvbSub + } + + static void +-_dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, guint8 * buf, +- gint buf_size) ++_dvb_sub_parse_object_segment (DvbSub * dvb_sub, guint16 page_id, ++ const guint8 * buf, gint buf_size) + { + const guint8 *buf_end = buf + buf_size; + guint object_id; +@@ -1085,6 +1122,9 @@ _dvb_sub_parse_object_segment (DvbSub * + + guint8 coding_method, non_modifying_color; + ++ if (buf_size < 3) ++ return; ++ + object_id = GST_READ_UINT16_BE (buf); + buf += 2; + +@@ -1107,6 +1147,9 @@ _dvb_sub_parse_object_segment (DvbSub * + DVBSubObjectDisplay *display; + guint16 top_field_len, bottom_field_len; + ++ if (buf + 4 > buf_end) ++ return; ++ + top_field_len = GST_READ_UINT16_BE (buf); + buf += 2; + bottom_field_len = GST_READ_UINT16_BE (buf); +@@ -1147,7 +1190,7 @@ _dvb_sub_parse_object_segment (DvbSub * + } + + static gint +-_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, guint8 * buf, ++_dvb_sub_parse_display_definition_segment (DvbSub * dvb_sub, const guint8 * buf, + gint buf_size) + { + int dds_version, info_byte; +@@ -1164,6 +1207,18 @@ _dvb_sub_parse_display_definition_segmen + display_height = GST_READ_UINT16_BE (buf) + 1; + buf += 2; + ++ /* Avoid integer overflows and also clamp to a reasonable size of 16kx16k */ ++ if (display_width > 16384 || display_height > 16384) { ++ GST_WARNING ("too large display size of %ux%x", display_width, ++ display_height); ++ /* Reset to the initial values */ ++ dvb_sub->display_def.version = -1; ++ dvb_sub->display_def.window_flag = 0; ++ dvb_sub->display_def.display_width = 720; ++ dvb_sub->display_def.display_height = 576; ++ return -1; ++ } ++ + if ((display_width != dvb_sub->display_def.display_width) + || (display_height != dvb_sub->display_def.display_height)) { + dvb_sub->display_def.display_width = display_width; +@@ -1386,7 +1441,8 @@ dvb_sub_free (DvbSub * sub) + * 0 or positive if data was handled. If positive, then amount of data consumed on success. FIXME: List the positive return values. + */ + gint +-dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, guint8 * data, gint len) ++dvb_sub_feed_with_pts (DvbSub * dvb_sub, guint64 pts, const guint8 * data, ++ gint len) + { + unsigned int pos = 0; + guint8 segment_type; +--- gst-plugins-bad1.0-1.26.2.orig/gst/dvbsuboverlay/dvb-sub.h ++++ gst-plugins-bad1.0-1.26.2/gst/dvbsuboverlay/dvb-sub.h +@@ -129,7 +129,7 @@ typedef struct { + DvbSub *dvb_sub_new (void); + void dvb_sub_free (DvbSub * sub); + +-gint dvb_sub_feed_with_pts (DvbSub *dvb_sub, guint64 pts, guint8 *data, gint len); ++gint dvb_sub_feed_with_pts (DvbSub *dvb_sub, guint64 pts, const guint8 *data, gint len); + void dvb_sub_set_callbacks (DvbSub *dvb_sub, DvbSubCallbacks *callbacks, gpointer user_data); + void dvb_subtitles_free (DVBSubtitles *sub); + diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3081.patch gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3081.patch --- gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3081.patch 1970-01-01 00:00:00.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3081.patch 2026-03-30 21:52:25.000000000 +0000 @@ -0,0 +1,43 @@ +From c35d1df1c6514db8249dfbf22b952d2691fe347a Mon Sep 17 00:00:00 2001 +From: Carlos Bentzen +Date: Fri, 20 Feb 2026 13:34:50 +0100 +Subject: [PATCH] h266parser: Fix out of bounds write when parsing pic_timing + SEI + +--- gst-plugins-bad1.0-1.26.2.orig/gst-libs/gst/codecparsers/gsth266parser.c ++++ gst-plugins-bad1.0-1.26.2/gst-libs/gst/codecparsers/gsth266parser.c +@@ -1460,7 +1460,8 @@ gst_h266_parser_parse_pic_timing (GstH26 + + if (bp->du_hrd_params_present_flag && + bp->du_cpb_params_in_pic_timing_sei_flag) { +- READ_UE (nr, pt->num_decoding_units_minus1); ++ READ_UE_MAX (nr, pt->num_decoding_units_minus1, ++ GST_H266_MAX_DECODING_UNITS_IN_PIC_TIMING - 1); + if (pt->num_decoding_units_minus1 > 0) { + READ_UINT8 (nr, pt->du_common_cpb_removal_delay_flag, 1); + if (pt->du_common_cpb_removal_delay_flag) { +--- gst-plugins-bad1.0-1.26.2.orig/gst-libs/gst/codecparsers/gsth266parser.h ++++ gst-plugins-bad1.0-1.26.2/gst-libs/gst/codecparsers/gsth266parser.h +@@ -105,6 +105,11 @@ G_BEGIN_DECLS + The min coding block size is 8, so min width or height is 8. + The min CTU size is 32. */ + #define GST_H266_MAX_CTUS_IN_PICTURE (80216064 / 8 / 32) ++/* Practical limit for number of decoding units per picture. ++ The spec allows up to PicSizeInCtbsY which could be very large, ++ but 600 is a reasonable practical limit matching the array sizes ++ in GstH266PicTiming. */ ++#define GST_H266_MAX_DECODING_UNITS_IN_PIC_TIMING 600 + + /** + * GST_H266_IS_NAL_TYPE_IDR: +@@ -3066,8 +3071,8 @@ struct _GstH266PicTiming { + guint8 du_common_cpb_removal_delay_flag; + guint8 du_common_cpb_removal_delay_increment_minus1[8]; + /* TODO: PicSizeInCtbsY could be very large */ +- guint32 num_nalus_in_du_minus1[600]; +- guint8 du_cpb_removal_delay_increment_minus1[600][8]; ++ guint32 num_nalus_in_du_minus1[GST_H266_MAX_DECODING_UNITS_IN_PIC_TIMING]; ++ guint8 du_cpb_removal_delay_increment_minus1[GST_H266_MAX_DECODING_UNITS_IN_PIC_TIMING][8]; + guint8 delay_for_concatenation_ensured_flag; + guint8 display_elemental_periods_minus1; + }; diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3082.patch gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3082.patch --- gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3082.patch 1970-01-01 00:00:00.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3082.patch 2026-03-30 21:55:14.000000000 +0000 @@ -0,0 +1,19 @@ +From 108e5a1713c2c06744cf40139900f8f7c2076485 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?V=C3=ADctor=20Manuel=20J=C3=A1quez=20Leal?= + +Date: Wed, 11 Feb 2026 22:07:49 +0100 +Subject: [PATCH] libs: jpegparser: boundary checks before copying it + +--- gst-plugins-bad1.0-1.26.2.orig/gst-libs/gst/codecparsers/gstjpegparser.c ++++ gst-plugins-bad1.0-1.26.2/gst-libs/gst/codecparsers/gstjpegparser.c +@@ -77,6 +77,10 @@ ensure_debug_category (void) + + #define READ_BYTES(reader, buf, length) G_STMT_START { \ + const guint8 *vals; \ ++ if (length > sizeof (buf)) { \ ++ GST_WARNING ("data size is bigger than its storage"); \ ++ goto failed; \ ++ } \ + if (!gst_byte_reader_get_data (reader, length, &vals)) { \ + GST_WARNING ("failed to read bytes, size:%d", length); \ + goto failed; \ diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3084.patch gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3084.patch --- gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3084.patch 1970-01-01 00:00:00.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3084.patch 2026-03-30 21:50:40.000000000 +0000 @@ -0,0 +1,41 @@ +From 30fd03d95459af230c5bd5c76c31a82255db4135 Mon Sep 17 00:00:00 2001 +From: Carlos Bentzen +Date: Fri, 20 Feb 2026 17:10:04 +0100 +Subject: [PATCH] h266parser: Validate tile index bounds in picture partition + parsing + +--- gst-plugins-bad1.0-1.26.2.orig/gst-libs/gst/codecparsers/gsth266parser.c ++++ gst-plugins-bad1.0-1.26.2/gst-libs/gst/codecparsers/gsth266parser.c +@@ -3618,15 +3618,28 @@ gst_h266_parser_parse_picture_partition + goto error; + } + +- tile_idx += pps->tile_idx_delta_val[i]; ++ gint new_tile_idx = (gint) tile_idx + pps->tile_idx_delta_val[i]; ++ if (new_tile_idx < 0 || ++ new_tile_idx >= (gint) pps->num_tiles_in_pic) { ++ GST_WARNING ("tile_idx %d out of bounds.", new_tile_idx); ++ goto error; ++ } ++ tile_idx = new_tile_idx; + } else { + pps->tile_idx_delta_val[i] = 0; + +- tile_idx += pps->slice_width_in_tiles_minus1[i] + 1; +- if (tile_idx % pps->num_tile_columns == 0) { +- tile_idx += pps->slice_height_in_tiles_minus1[i] * ++ gint new_tile_idx = (gint) tile_idx + ++ pps->slice_width_in_tiles_minus1[i] + 1; ++ if (new_tile_idx % pps->num_tile_columns == 0) { ++ new_tile_idx += pps->slice_height_in_tiles_minus1[i] * + pps->num_tile_columns; + } ++ if (new_tile_idx < 0 || ++ new_tile_idx >= (gint) pps->num_tiles_in_pic) { ++ GST_WARNING ("tile_idx %d out of bounds.", new_tile_idx); ++ goto error; ++ } ++ tile_idx = new_tile_idx; + } + } + } diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3086.patch gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3086.patch --- gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3086.patch 1970-01-01 00:00:00.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/CVE-2026-3086.patch 2026-03-30 21:53:31.000000000 +0000 @@ -0,0 +1,16 @@ +From a2edc745bfea8835186a264c5e666be93f65a38e Mon Sep 17 00:00:00 2001 +From: Carlos Bentzen +Date: Fri, 20 Feb 2026 17:40:24 +0100 +Subject: [PATCH] h266parser: Fix APS ID bounds check in APS parsing + +--- gst-plugins-bad1.0-1.26.2.orig/gst-libs/gst/codecparsers/gsth266parser.c ++++ gst-plugins-bad1.0-1.26.2/gst-libs/gst/codecparsers/gsth266parser.c +@@ -4389,7 +4389,7 @@ gst_h266_parse_aps (GstH266Parser * pars + READ_UINT8 (&nr, params_type, 3); + aps->params_type = params_type; + READ_UINT8 (&nr, aps->aps_id, 5); +- CHECK_ALLOWED_MAX (aps->aps_id, GST_H266_MAX_APS_COUNT); ++ CHECK_ALLOWED_MAX (aps->aps_id, GST_H266_MAX_APS_COUNT - 1); + READ_UINT8 (&nr, aps->chroma_present_flag, 1); + + switch (aps->params_type) { diff -Nru gst-plugins-bad1.0-1.26.2/debian/patches/series gst-plugins-bad1.0-1.26.2/debian/patches/series --- gst-plugins-bad1.0-1.26.2/debian/patches/series 2025-07-10 07:59:37.000000000 +0000 +++ gst-plugins-bad1.0-1.26.2/debian/patches/series 2026-03-30 21:57:26.000000000 +0000 @@ -1,3 +1,8 @@ 02_opencv-data-path.patch Skip-failing-tests.patch 0001-h266parser-Fix-overflow-when-parsing-subpic_level_in.patch +CVE-2026-3084.patch +CVE-2026-3081.patch +CVE-2026-3086.patch +CVE-2026-3082.patch +CVE-2026-2923.patch