[Security] Heap buffer overflow (OOB read past GPAC sample buffer) in process_avc_sample() at mp4.c:99 when parsing a crafted MP4 file
メンテナーはふだん 2 日以内に返信
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 74/100
調査の方向性
src/lib_ccx/mp4.c の process_avc_sample() で、NAL 長のチェックと 99~100 行目の読み取りのあたりから始めてください。まず周辺のサンプル処理コードを読んでください。添付された不正な MP4 を AddressSanitizer で使って再現し、その後、サンプルバイトへのアクセスや do_NAL() の呼び出しより前に無効な長さが拒否されることを確認してください。不正な入力が範囲外読み取りなしで終了し、有効な avc1 サンプルが引き続き正常に処理されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
1. Summary
CCExtractor (master commit d7eb132e15f4d1e2c40f4655349596b2b8f708de, version string 0.96.5) performs an out-of-bounds read while parsing a crafted MP4 file. During GPAC-based MP4 processing of an AVC video track, process_avc_sample() (src/lib_ccx/mp4.c) walks the sample bytes NAL by NAL. The bounds check before using the NAL length is computed in 32-bit unsigned arithmetic (mp4.c:82, "i + nal_length <= previous_index || i + nal_length > s->dataLength"), so a nal_length value close to UINT32_MAX wraps around and passes both comparisons while the index i reaches s->dataLength. Line 99 then reads s->data[i] one byte past the end of the GPAC sample buffer ("s_nalu_stats.type[s->data[i] & 0x1F] += 1;"), and line 100 additionally passes the out-of-range pointer/length pair to do_NAL(). Under AddressSanitizer the process aborts with "heap-buffer-overflow ... READ of size 1 ... 0 bytes to the right of 892-byte region ... in process_avc_sample" at mp4.c:99:22.
2. Affected version / environment
- Project: CCExtractor (https://github.com/CCExtractor/ccextractor)
- Version: version string 0.96.5, master branch commit d7eb132e15f4d1e2c40f4655349596b2b8f708de (source dated 2026-10-17, binary compiled 2026-10-26)
- Environment: Linux x86_64 (Ubuntu container), ccextractor built with AddressSanitizer, statically linked; libGPAC 2.0; default CLI options, output target .srt
- Component: src/lib_ccx/mp4.c:99 (process_avc_sample), reached via process_avc_track (mp4.c:295) and processmp4 (mp4.c:989) through the GPAC MP4 demux path
3. Steps to reproduce
1. Build ccextractor at master commit d7eb132e15f4d1e2c40f4655349596b2b8f708de with AddressSanitizer.
2. Save the attached crash-input.bin (SHA-256 9d42a6cb84ce7989f69e897a7b94d4e694fd90ffecd1ddf5642746ca9dfe64b2, a malformed MP4 file, 85,748 bytes).
3. Run: ccextractor crash-input.bin
(verification used: env ASAN_OPTIONS=abort_on_error=0:symbolize=1:detect_leaks=0:allocator_may_return_null=1:print_legend=0:malloc_context_size=0 /lh/ccextractor/src/build/ccextractor /lh/tmp/poc-export/ccx-mp4avc/crash-input.bin inside the container)
4. Observe the process abort with an AddressSanitizer heap-buffer-overflow report while "Processing track 1, type=vide subtype=avc1".
5. Negative control: a valid MP4 file with an avc1 track (negative-control.bin, SHA-256 c4e5198b915b07d943983858a3c5f339b9d5aa77151eaca1e028175c0317f4d7) takes the same GPAC path ("Processing track 1, type=vide subtype=avc1") and completes with no sanitizer report, confirming the crash is input-specific.
4. Expected behavior
ccextractor should reject the malformed NAL length (32-bit wrap-around defeat of the bounds check), skip or report the corrupted sample, and exit normally without reading past the end of the GPAC sample buffer.
5. Actual behavior
=================================================================
==2938641==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6180000063fc at pc 0x55a148390d9f bp 0x7ffd5e0f28d0 sp 0x7ffd5e0f28c8
READ of size 1 at 0x6180000063fc thread T0
#0 0x55a148390d9e in process_avc_sample /lh/ccextractor/src/src/lib_ccx/mp4.c:99:22
#1 0x55a148390d9e in process_avc_track /lh/ccextractor/src/src/lib_ccx/mp4.c:295:13
#2 0x55a148390d9e in processmp4 /lh/ccextractor/src/src/lib_ccx/mp4.c:989:9
#3 0x55a14808c4e0 in start_ccx /lh/ccextractor/src/src/ccextractor.c:252:12
0x6180000063fc is located 0 bytes to the right of 892-byte region [0x618000006080,0x6180000063fc)
allocated by thread T0 here:
#0 0x55a147efe28b in malloc (/lh/ccextractor/src/build/ccextractor+0x19928b) (BuildId: 7698bf0a2d6a1980221851c4e3b7738245c921f8)
SUMMARY: AddressSanitizer: heap-buffer-overflow /lh/ccextractor/src/src/lib_ccx/mp4.c:99:22 in process_avc_sample
6. Impact
Out-of-bounds read on the heap (CWE-125). The read byte past the GPAC sample buffer is used as an NAL-type statistic index, and the same out-of-range cursor/length pair is then handed to do_NAL() (mp4.c:100), which parses attacker-reachable out-of-bounds memory as NAL content; under AddressSanitizer the process aborts deterministically, and outside the sanitizer the oversized NAL parse walks into unmapped memory and crashes. Automated caption-extraction or transcoding pipelines that accept user media can therefore be crashed by a single crafted file. No write primitive is demonstrated; information disclosure was not observed (the read value only increments an internal counter), and the conservative CVSS impact ratings are documented in the attached report.
7. Suggested fix
Perform the end-of-NAL bounds check in wrap-safe (64-bit) arithmetic, e.g.
const u32 previous_index = i;
i += c->nal_unit_size;
[poc.zip](https://github.com/user-attachments/files/34296733/poc.zip)
if ((uint64_t)i + nal_length <= previous_index || (uint64_t)i + nal_length > s->dataLength)
return status;
and additionally reject nal_length values that exceed the remaining sample bytes before line 99 reads s->data[i] and before do_NAL() is called at line 100. An equivalent alternative is to validate `nal_length <= s->dataLength - i` explicitly after reading the length field.
8. Additional context (PoC / logs, redacted)
- Attached: crash-input.bin (malformed MP4, ftyp/free/mdat boxes, one avc1 video track; SHA-256 9d42a6cb84ce7989f69e897a7b94d4e694fd90ffecd1ddf5642746ca9dfe64b2)
- Negative control attached: negative-control.bin (valid MP4 with avc1 track, SHA-256 c4e5198b915b07d943983858a3c5f339b9d5aa77151eaca1e028175c0317f4d7) — same code path, runs clean
- Crash discovered by coverage-guided fuzzing of the master build (AFL crash id:000028 of the campaign); full sanitizer transcript archived in the verification environment; terminal screenshots of the live reproduction are available on request.
- Distinct from the NULL pointer dereference in sei_message() (src/lib_ccx/avc_functions.c:395): different function, different source location, different defect class.
- No reproduction was attempted on any other version; affected range is therefore not asserted beyond the tested commit.
- 主要言語
- C
- スター
- 913
- フォーク
- 603
- 平均マージ
- 1日 10時間
- マージ済み PR(30日)
- 24
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
CCExtractor/ccextractor のほかの issue
-
[BUG] DVB subtitle decoder: heap-buffer-overflow write in dvbsub_parse_clut_segment via unbounded entry_id対応中かも @Aditya-Saroha が 4 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
CCExtractor/ccextractor#2440 ·
メンテナーはふだん 2 日以内に返信
-
Heap OOB read in parse_ad_cdp: cc_count not bounded by packet length対応中かも @Aditya-Saroha が 4 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
CCExtractor/ccextractor#2425 · コメント 3 件 ·
メンテナーはふだん 2 日以内に返信
-
[BUG] Heap buffer overflow in parse_PMT with C0/C1 section length対応中かも @kun-codes が 14 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
CCExtractor/ccextractor#2419 ·
メンテナーはふだん 2 日以内に返信
-
[BUG] Filename sequence expansion (`+`) panics on numeric values exceeding `i32::MAX`対応中かも @muntasir-396 が 17 日前に担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
CCExtractor/ccextractor#2402 ·
メンテナーはふだん 2 日以内に返信
-
難易度 3/5 1〜2日 初心者へのやさしさ 65/100
CCExtractor/ccextractor#2450 · コメント 3 件 ·
メンテナーはふだん 2 日以内に返信
CCExtractor/ccextractor の issue をすべて見る
似ている issue
-
XPM values line with more than one space between numbers raises ValueError対応中かも このイシューにリンクされたプルリクエストがオープン中、またはマージ済みです。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
python-pillow/Pillow#10429 ·
メンテナーはふだん 1 日以内に返信
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 83/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
メンテナーはふだん 9 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
containers/bubblewrap#826 ·
メンテナーはふだん 1 日以内に返信