CCExtractor / CCExtractor/ccextractor

[BUG] Three out-of-bounds reads in TS parsing when a packet's adaptation field leaves a short payload (heap overflow in parse_PAT via uint32_t underflow)

Abierto
#2,348 0 comentarios 0 reacciones 0 asignados Ver en GitHub
Lenguaje dominante
C
Estrellas
903
Forks
589
Merge medio
3 d 2 h
PR fusionados (30 d)
10

Descripción

CCExtractor version: master (2364994a)

# Necessary information

- Is this a regression (i.e. did it work before)? **NO** — long-standing.
- What platform did you use? **Linux** (Debian bookworm, x86-64, built from `docker/Dockerfile`). Platform-independent.
- What were the used arguments? `--out=srt` (any output format reproduces it)

# Video links

Inline below — the reproducer is 1,692 bytes (9 TS packets).

# Additional information

## Summary

A transport stream packet whose adaptation field leaves a very short payload drives **three out-of-bounds reads**. All are reachable from stream data, and all are caught by AddressSanitizer.

## 1. `parse_PAT()` — heap-buffer-overflow (the serious one)

https://github.com/CCExtractor/ccextractor/blob/master/src/lib_ccx/ts_tables.c#L646-L653

```c
pointer_field = *(ctx->PID_buffers[0]->buffer);
payload_start = ctx->PID_buffers[0]->buffer + pointer_field + 1;
payload_length = ctx->PID_buffers[0]->buffer_length - (pointer_field + 1);

if (payload_length < 8)
return 0;

section_number = payload_start[6];
```

`pointer_field` is a raw byte from the stream and `buffer_length` is `uint32_t`. When `pointer_field + 1 > buffer_length` the subtraction **underflows to ~4×10⁹**, sails through the `< 8` guard, and `payload_start` is then dereferenced far outside the allocation.

`ts_buffer_psi_packet()` makes a one-byte buffer whenever `adaptation_field_length` is 182 (`payload_length = tspacket + 188 - payload_start` = 1). With `pointer_field` = 0xB7, ASan reports:

```
==1==ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 1
#0 parse_PAT ../src/lib_ccx/ts_tables.c:655
#1 ts_readstream ../src/lib_ccx/ts_functions.c:796
#2 ts_get_more_data ../src/lib_ccx/ts_functions.c:1092
0x602000004cc9 is located 184 bytes to the right of 1-byte region [0x602000004c10,0x602000004c11)
```

This is the same shape as #2322 (unsigned underflow defeating a bounds check).

## 2. `parse_SDT()` — same underflow

https://github.com/CCExtractor/ccextractor/blob/master/src/lib_ccx/ts_tables.c#L951-L953

Identical `buffer_length - (pointer_field + 1)` underflow, and unlike `parse_PAT` there is **no length check at all** before `payload_start[0]`, `[1]`, `[2]` are read.

## 3. `ts_readstream()` — global-buffer-overflow

https://github.com/CCExtractor/ccextractor/blob/master/src/lib_ccx/ts_functions.c#L895-L900

```c
if (payload.pesstart)
{
uint64_t pes_prefix = (payload.start[0] << 16) | (payload.start[1] << 8) | payload.start[2];
uint8_t pes_stream_id = payload.start[3];
```

No `payload.length` check. In `ts_readpacket()`, `adaptation_field_length` of 183 passes the `adaptation_field_length < payload->length` test (183 < 184), so `payload.start` advances to `tspacket + 188` — one past the end of the 188-byte global — and `payload.length` becomes 0.

```
==1==ERROR: AddressSanitizer: global-buffer-overflow
#0 ts_readstream ../src/lib_ccx/ts_functions.c:899
0x... is located 0 bytes to the right of global variable 'tspacket'
defined in '../src/lib_ccx/ts_functions.c:18:15' of size 188
```

## Reproducer

1,692 bytes, 9 TS packets. This is the minimal prefix that still triggers #1 — 8 packets is clean.

```bash
base64 -d > repro.ts <<'B64EOF'
R0AAMLYA////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
AACwDQABwQAAAAHwACqxBLJHUAAwtgD/////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////AAKwEgABwQAA8AHwAALwAfAABc5VM0dQATC2AP//////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////AAAB4AA/gYAFIQALfkEAAAGz
LQHgJP//4AAAAAG4ggAgQAAAAQAAD//4AAABskdBOTQDQf/8lCD/AAABAQAAAAAAAAAAR1ABMbYA
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/////////////////////////wAAAeAAK4GABSEAC5W3AAABAABP//gAAAGyR0E5NANB//yUrv8A
AAEBAAAAAAAAAABHUAEytgD/////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////AAAB4AArgYAFIQALrS0AAAEAAI//
+AAAAbJHQTk0A0H//JRw/wAAAQEAAAAAAAAAAEdQATO2AP//////////////////////////////
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////8AAAHg
ACuBgAUhAAvEowAAAQAAz//4AAABskdBOTQDQf/8Rkn/AAABAQAAAAAAAAAAR1ABNLYA////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/////////////////wAAAeAAK4GABSEAC9wZAAABAAEP//gAAAGyR0E5NANB//xS0/8AAAEBAAAA
AAAAAABHUAE1tgD/////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////AAAB4AArgYAFIQAL848AAAEAAU//+AAAAbJH
QTk0A0H//FQg/wAAAQEAAAAAAAAAAEdQATa2AP//////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////8AAAHgACuBgAUh
AA0LBQAAAQABj//4AAABskdBOTQDQf/8VNP/AAABAQAAAAAAAAAA
B64EOF
ccextractor repro.ts --out=srt -o out.srt
```
sha256 `e0e1507623a14e4d938f0f96bfaee75dc6ec3b681e2fc5ee25f00adac8ab76ea`

It is a synthetic MPEG-2 TS (PAT + PMT + CEA-608 in ATSC A/53 `GA94` user_data) with every adaptation field set to 182. A plain build processes it without complaint — the reads are silent — so a sanitizer build is needed to see it:

```bash
# in linux/
./build -debug # adds -fsanitize=address
```

For #3, the same file with `adaptation_field_length` set to 183 instead of 182 triggers the `tspacket` overflow. Happy to attach that variant too, or the generator script, if useful for the regression suite.

## Suggested fix

Bounds-check `pointer_field` against `buffer_length` before the subtraction in both `parse_PAT` and `parse_SDT`, and require `payload.length >= 14` before the PES/PTS read in `ts_readstream` (`get_pts()` reads through `buffer[13]`).

The tree already has exactly this guard at `ts_tables_epg.c:1642`:

```c
if ((size_t)pointer_field + 1 < (size_t)ctx->epg_buffers[i].buffer_length)
```

PR follows.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.