[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,449 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 2 日以内に返信

@yasar710 がすでに取り組んでいます。

2026年11月4日 から。

  • #2453 @yasar710 による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
74/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
c
領域
backend, security

調査の方向性

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

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

CCExtractor/ccextractor のほかの issue

CCExtractor/ccextractor の issue をすべて見る

似ている issue

C の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。