Bug 2563952 (CVE-2026-119610) - CVE-2026-119610 gstreamer1-plugins-good: gstreamer1-plugins-good: out-of-bounds heap read in MTAP16/MTAP24 H.264 RTP depayloader via signed/unsigned underflow
Summary: CVE-2026-119610 gstreamer1-plugins-good: gstreamer1-plugins-good: out-of-boun...
Keywords:
Status: NEW
Alias: CVE-2026-119610
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On: 2569059 2569060 2569061 2569063 2569081 2569082
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-10-30 12:07 UTC by OSIDB Bzimport
Modified: 2026-11-09 11:08 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-10-30 12:07:24 UTC
GStreamer gst-plugins-good ships the rtph264depay element (gst/rtp/gstrtph264depay.c). MTAP16 (NAL type 26) and MTAP24 (NAL type 27) support was added in gst-plugins-good 1.28.0 (upstream commit 367cda03c9, 2025-10-08).

In gst_rtp_h264_depay_process() the variable payload_len is declared as gint (signed 32-bit). For the MTAP16/MTAP24 branch (lines 1380-1471), the code strips the 1-byte NAL type header (line 1387) and then unconditionally strips the 2-byte decoding-order-number base (DON base, line 1396) without first checking that at least 2 bytes remain. When the RTP payload is truncated (e.g., only 1 byte — just the NAL type), payload_len goes negative (e.g., 1-1-2 = -2).

Bug 1 — Wrong loop guard (line 1398): aggregation_unit_size is gsize (unsigned). The comparison 'while (payload_len > aggregation_unit_size)' performs an unsigned promotion of the signed payload_len. A negative payload_len (e.g., -2) becomes a very large unsigned value (0xFFFFFFFE on 32-bit), so the loop condition is TRUE and the loop body executes even though the packet is exhausted.

Bug 2 — Broken clamping (line 1427): Inside the loop, nalu_size is read via GST_READ_UINT16_BE() from the payload pointer that is already past the end of the packet buffer (OOB heap read #1). The subsequent clamping guard 'if (nalu_size > payload_len)' is also a signed/unsigned comparison: nalu_size is guint, payload_len is gint (still negative). Negative payload_len is promoted to a huge unsigned value, so the condition evaluates FALSE and nalu_size is NOT clamped. nalu_size may be up to 65535.

Bug 3 — memcpy from OOB (line 1441): memcpy(map.data + sizeof(sync_bytes), payload, nalu_size) reads nalu_size (up to 65535) bytes from payload, which points past the end of the actual packet. This is the primary heap-buffer-over-read confirmed by ASan: READ of 48830 bytes at gstrtph264depay.c:1432.

The allocated output buffer (outbuf) has exactly nalu_size+4 bytes; the DESTINATION is valid. Only the SOURCE is OOB. The content is then placed into the depayloaded output GstBuffer and forwarded downstream. In relay/transcode pipelines this becomes observable information disclosure. In all pipelines, the OOB read is likely to crash the process (SIGSEGV) when the read range extends into unmapped memory.

Affected: gst-plugins-good 1.28.0 through 1.28.8. Fixed in: 1.28.9 (unreleased as of 2026-10-28, private MR gstreamer-security !136). GStreamer advisory SA-2026-0095.

Reporter: Claude (Anthropic), Ada Logics.
PSIRT ticket: PSIRTSUPT-29444.


Note You need to log in before you can comment on or make changes to this bug.