https://bugs.gentoo.org/974283 https://gstreamer.freedesktop.org/security/sa-2026-0014.html https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/11245 From 6dfb6e2e8c26477fa3cba0ef439ae0011318319c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 26 Mar 2026 18:45:57 +0200 Subject: [PATCH 2/8] typefind: Avoid signed 32 bit integer overflow when parsing AV1 LEB128 values Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/work_items/4994 Part-of: --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -6881,7 +6881,7 @@ av1_leb128 (const guint8 * data, guint32 * retval, gint * read_bytes) for (i = 0; i < 8; i++) { leb128_byte = data[i]; - value |= (((gint) leb128_byte & 0x7f) << (i * 7)); + value |= (((guint64) leb128_byte & 0x7f) << (i * 7)); if (!(leb128_byte & 0x80)) break; -- GitLab From f7835ad222a176a51c84d81cdee3456dd3dfec52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 26 Mar 2026 18:59:11 +0200 Subject: [PATCH 4/8] typefind: Use a byte reader for parsing AV1 bitstreams And make sure to use appropriate bounds checks. Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/work_items/4993 Part-of: --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -6870,17 +6870,17 @@ av1_is_valid_obu_type (guint obu_type) } static gboolean -av1_leb128 (const guint8 * data, guint32 * retval, gint * read_bytes) +av1_leb128 (GstByteReader * br, guint32 * retval) { guint8 leb128_byte = 0; guint64 value = 0; gint i; *retval = 0; - *read_bytes = 0; for (i = 0; i < 8; i++) { - leb128_byte = data[i]; + if (!gst_byte_reader_get_uint8 (br, &leb128_byte)) + return FALSE; value |= (((guint64) leb128_byte & 0x7f) << (i * 7)); if (!(leb128_byte & 0x80)) break; @@ -6895,7 +6895,6 @@ av1_leb128 (const guint8 * data, guint32 * retval, gint * read_bytes) /* check for bitstream conformance see chapter 4.10.5 */ if (value < G_MAXUINT32) { *retval = (guint32) value; - *read_bytes = i + 1; return TRUE; } @@ -6903,44 +6902,44 @@ av1_leb128 (const guint8 * data, guint32 * retval, gint * read_bytes) } static gboolean -av1_is_valid_obu (const guint8 * data, guint * obu_type, gint * read_bytes) +av1_is_valid_obu (GstByteReader * br, guint * obu_type) { gboolean obu_forbidden_bit; gboolean obu_extension_flag; gboolean obu_has_size_field; gboolean obu_reserved_1bit; - int offset = 1; + guint8 b; *obu_type = 0; - *read_bytes = 0; + + if (!gst_byte_reader_get_uint8 (br, &b)) + return FALSE; /* Detect OBU header */ - obu_forbidden_bit = !!(data[0] & 0x80); + obu_forbidden_bit = !!(b & 0x80); if (obu_forbidden_bit) return FALSE; - *obu_type = (data[0] & 0x78) >> 3; - obu_extension_flag = !!(data[0] & 0x4); - obu_has_size_field = !!(data[0] & 0x2); - obu_reserved_1bit = !!(data[0] & 0x1); + *obu_type = (b & 0x78) >> 3; + obu_extension_flag = !!(b & 0x4); + obu_has_size_field = !!(b & 0x2); + obu_reserved_1bit = !!(b & 0x1); /* if obu_extension_flag is set temporal_id (3 bits) * spatial_id (2 bits) and extension_header_reserved_3bits (3 bits) * field are coded in the header so OBU size field is * 1 byte after */ - if (obu_extension_flag) - offset++; - - *read_bytes += offset; + if (obu_extension_flag) { + if (!gst_byte_reader_skip (br, 1)) + return FALSE; + } if (av1_is_valid_obu_type (*obu_type) && !obu_reserved_1bit) { if (obu_has_size_field) { guint32 obu_size; - gint bytes; - if (!av1_leb128 (data + offset, &obu_size, &bytes)) + if (!av1_leb128 (br, &obu_size)) return FALSE; - *read_bytes += bytes; } return TRUE; @@ -6956,42 +6955,39 @@ av1_type_find (GstTypeFind * tf, gpointer unused) guint32 frame_unit_size; guint32 obu_length; const guint8 *data; + GstByteReader br; guint obu_type; - gint read_bytes; - gint offset = 0; data = gst_type_find_peek (tf, 0, 25); if (!data) return; - if (av1_is_valid_obu (data, &obu_type, &read_bytes)) { + gst_byte_reader_init (&br, data, 25); + + if (av1_is_valid_obu (&br, &obu_type)) { gst_type_find_suggest_simple (tf, GST_TYPE_FIND_MINIMUM, "video/x-av1", "stream-format", G_TYPE_STRING, "obu-stream", "alignment", G_TYPE_STRING, "none", NULL); return; } - if (!av1_leb128 (data, &temporal_unit_size, &read_bytes)) + if (!av1_leb128 (&br, &temporal_unit_size)) return; - offset += read_bytes; - if (!av1_leb128 (data + offset, &frame_unit_size, &read_bytes)) + if (!av1_leb128 (&br, &frame_unit_size)) return; - offset += read_bytes; if (frame_unit_size > temporal_unit_size) return; - if (!av1_leb128 (data + offset, &obu_length, &read_bytes)) + if (!av1_leb128 (&br, &obu_length)) return; - offset += read_bytes; if (obu_length > frame_unit_size) return; - if (!av1_is_valid_obu (data + offset, &obu_type, &read_bytes)) + if (!av1_is_valid_obu (&br, &obu_type)) return; - offset += read_bytes; /* The first OBU must be a temporal delimiter */ if (obu_type == 2) -- GitLab From 30a18fc8dba3892f168008fe211f7c951465f26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 26 Mar 2026 19:19:19 +0200 Subject: [PATCH 6/8] typefind: Allow G_MAXUINT32 as LEB128 encoded value when parsing AV1 bitstreams The spec states that any value less than or equal to (1<<32) - 1 should be accepted but we were rejecting (1<<32) - 1. Part-of: --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -6893,7 +6893,7 @@ av1_leb128 (GstByteReader * br, guint32 * retval) return FALSE; /* check for bitstream conformance see chapter 4.10.5 */ - if (value < G_MAXUINT32) { + if (value <= G_MAXUINT32) { *retval = (guint32) value; return TRUE; } -- GitLab From 554e3ee6f2a353c0192b2af10f7b141e8cd32d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 26 Mar 2026 19:27:22 +0200 Subject: [PATCH 8/8] typefind: Remove dead code in AV1 LEB128 parser Part-of: --- a/gst/typefind/gsttypefindfunctions.c +++ b/gst/typefind/gsttypefindfunctions.c @@ -6889,9 +6889,6 @@ av1_leb128 (GstByteReader * br, guint32 * retval) return FALSE; } - if (i == 8) - return FALSE; - /* check for bitstream conformance see chapter 4.10.5 */ if (value <= G_MAXUINT32) { *retval = (guint32) value; -- GitLab