[vlc-commits] [Git][videolan/vlc][3.0.x] 11 commits: demux: ogg: keep the map sizes when they are set
Thomas Guillem (@tguillem)
gitlab at videolan.org
Thu Nov 13 15:05:06 UTC 2025
Thomas Guillem pushed to branch 3.0.x at VideoLAN / VLC
Commits:
b3a03a21 by Steve Lhomme at 2025-11-13T16:03:22+01:00
demux: ogg: keep the map sizes when they are set
The p_old_map/p_new_map sizes should match their buffer size.
By default the channel counts are zero which considers the old/new maps match.
The channel count read may be updated but not the channel mapping.
We need to check the channel count match and the mapping matches.
Fixes https://code.videolan.org/videolan/vlc/-/issues/29314
- - - - -
82c10bb0 by Steve Lhomme at 2025-11-13T16:03:22+01:00
cvdbsub: don't use metadata offset if bigger than whole SPU
ParseMetaInfo() will not parse anything in that case as p == p_end.
The image will use the whole of the SPU buffer, potentially containing
metadata at the end. But the reading in RenderImage() is constrained by the width/height
so it won't use these data.
Fixes https://code.videolan.org/videolan/vlc/-/issues/29325
- - - - -
b728f207 by Steve Lhomme at 2025-11-13T16:03:23+01:00
demux: ty: stop read chunk if offset is past the data
Fixes https://code.videolan.org/videolan/vlc/-/issues/29316
- - - - -
ee89f0f7 by Steve Lhomme at 2025-11-13T16:03:23+01:00
demux: ty: don't check for S1/S2 if the offsets are too large
- - - - -
fa562df8 by Steve Lhomme at 2025-11-13T16:03:23+01:00
demux: ty: don't look for ES header past the input buffer boundaries
- - - - -
96f32bb6 by Stanislav Fort at 2025-11-13T16:03:23+01:00
cea708: fix OOB write in CEA-708 RTL window scroll
Fixes #29323
- - - - -
7cda527f by Stanislav Fort at 2025-11-13T16:03:23+01:00
cea708: use 4-byte stride for 4-byte character cells
Fixes corruption/OOB.
Fixes #29326
- - - - -
6e585a4d by Stanislav Fort at 2025-11-13T16:03:23+01:00
cea708: fix OOB write in CEA-708 LTR window scroll
Due to wrong bound check
Fixes #29375
- - - - -
e5d01c1a by Stanislav Fort at 2025-11-13T16:03:23+01:00
cea708: fix Window_MinCol()/Window_MaxCol() indexes
Refs #29328
- - - - -
153a13b9 by Stanislav Fort at 2025-11-13T16:03:23+01:00
cea708: fix CEA708_Window_Truncate()
Make truncation actually drop one column in LTR/RTL (adjust
lastcol/firstcol; delete rows only when they become empty).
Fixes #29328
- - - - -
f7745d07 by Stanislav Fort at 2025-11-13T16:03:23+01:00
oggspots: fix OOB read (unchecked image offset)
Fixes #29319
- - - - -
5 changed files:
- modules/codec/cea708.c
- modules/codec/cvdsub.c
- modules/codec/oggspots.c
- modules/demux/ogg.c
- modules/demux/ty.c
Changes:
=====================================
modules/codec/cea708.c
=====================================
@@ -556,7 +556,7 @@ static uint8_t CEA708_Window_MinCol( const cea708_window_t *p_w )
uint8_t i_min = CEA708_WINDOW_MAX_COLS;
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
- const cea708_text_row_t *p_row = p_w->rows[p_w->row];
+ const cea708_text_row_t *p_row = p_w->rows[i];
if( p_row && p_row->firstcol < i_min )
i_min = p_row->firstcol;
}
@@ -568,7 +568,7 @@ static uint8_t CEA708_Window_MaxCol( const cea708_window_t *p_w )
uint8_t i_max = 0;
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
- const cea708_text_row_t *p_row = p_w->rows[p_w->row];
+ const cea708_text_row_t *p_row = p_w->rows[i];
if( p_row && p_row->lastcol > i_max )
i_max = p_row->lastcol;
}
@@ -600,6 +600,8 @@ static void CEA708_Window_Truncate( cea708_window_t *p_w, int i_direction )
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
cea708_text_row_t *row = p_w->rows[i];
+ if (!row)
+ continue;
if( row->lastcol == i_max )
{
if( row->firstcol >= row->lastcol )
@@ -611,6 +613,12 @@ static void CEA708_Window_Truncate( cea708_window_t *p_w, int i_direction )
else if( i == p_w->i_lastrow )
p_w->i_lastrow--;
}
+ else
+ {
+ /* Drop rightmost column */
+ row->lastcol--;
+ }
+
}
}
}
@@ -621,6 +629,8 @@ static void CEA708_Window_Truncate( cea708_window_t *p_w, int i_direction )
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
cea708_text_row_t *row = p_w->rows[i];
+ if (!row)
+ continue;
if( row->firstcol == i_min )
{
if( row->firstcol >= row->lastcol )
@@ -632,6 +642,12 @@ static void CEA708_Window_Truncate( cea708_window_t *p_w, int i_direction )
else if( i == p_w->i_lastrow )
p_w->i_lastrow--;
}
+ else
+ {
+ /* Drop leftmost column */
+ row->firstcol++;
+ }
+
}
}
}
@@ -662,15 +678,20 @@ static void CEA708_Window_Scroll( cea708_window_t *p_w )
{
case CEA708_WA_DIRECTION_LTR:
/* Move RIGHT */
- if( CEA708_Window_MaxCol( p_w ) == CEA708_WINDOW_MAX_ROWS - 1 )
+ if( CEA708_Window_MaxCol( p_w ) == CEA708_WINDOW_MAX_COLS - 1 )
CEA708_Window_Truncate( p_w, CEA708_WA_DIRECTION_LTR );
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
cea708_text_row_t *row = p_w->rows[i];
+ if( !row )
+ continue;
if( row->lastcol < row->firstcol ) /* should not happen */
continue;
- memmove( &row->characters[row->firstcol + 1], &row->characters[row->firstcol],
- (row->lastcol - row->firstcol + 1) * 4U );
+
+ size_t start = (size_t) row->firstcol * 4U;
+ size_t count = (size_t) (row->lastcol - row->firstcol + 1) * 4U;
+ memmove( &row->characters[start + 4U], &row->characters[start],
+ count );
memmove( &row->styles[row->firstcol + 1], &row->styles[row->firstcol],
(row->lastcol - row->firstcol + 1) * sizeof(cea708_pen_style_t) );
row->firstcol++;
@@ -684,14 +705,21 @@ static void CEA708_Window_Scroll( cea708_window_t *p_w )
for( int i=p_w->i_firstrow; i <= p_w->i_lastrow; i++ )
{
cea708_text_row_t *row = p_w->rows[i];
+ if( !row )
+ continue;
if( row->lastcol < row->firstcol ) /* should not happen */
continue;
- memmove( &row->characters[row->firstcol - 1], &row->characters[row->firstcol],
- (row->lastcol - row->firstcol + 1) * 4U );
- memmove( &row->styles[row->firstcol - 1], &row->styles[row->firstcol],
- (row->lastcol - row->firstcol + 1) * sizeof(cea708_pen_style_t) );
- row->firstcol--;
- row->lastcol--;
+ if( row->firstcol > 0 )
+ {
+ size_t start = (size_t) row->firstcol * 4U;
+ size_t count = (size_t) (row->lastcol - row->firstcol + 1) * 4U;
+ memmove( &row->characters[start -4U], &row->characters[start],
+ count );
+ memmove( &row->styles[row->firstcol - 1], &row->styles[row->firstcol],
+ (row->lastcol - row->firstcol + 1) * sizeof(cea708_pen_style_t) );
+ row->firstcol--;
+ row->lastcol--;
+ }
}
break;
case CEA708_WA_DIRECTION_TB:
=====================================
modules/codec/cvdsub.c
=====================================
@@ -315,9 +315,11 @@ static void ParseHeader( decoder_t *p_dec, block_t *p_block )
p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
- /* FIXME: check data sanity */
p_sys->metadata_offset = (p[0] << 8) + p[1]; p +=2;
- p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
+ if ( p_sys->i_spu_size > p_sys->metadata_offset )
+ p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
+ else
+ p_sys->metadata_length = 0; // unusable metadata
p_sys->i_image_offset = 4;
p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
=====================================
modules/codec/oggspots.c
=====================================
@@ -354,6 +354,12 @@ static picture_t* DecodePacket(decoder_t* p_dec, block_t* p_block)
goto error;
}
+ if (i_img_offset > p_block->i_buffer) {
+ msg_Dbg(p_dec, "Invalid byte offset: %u exceeds packet size %zu",
+ i_img_offset, p_block->i_buffer);
+ goto error;
+ }
+
/* Image format */
if ( !memcmp(&p_block->p_buffer[4], "PNG", 3) ) {
p_dec->fmt_in.video.i_chroma = VLC_CODEC_PNG;
=====================================
modules/demux/ogg.c
=====================================
@@ -2424,9 +2424,11 @@ static bool Ogg_IsOpusFormatCompatible( const es_format_t *p_new,
int i_new_stream_count;
int i_old_coupled_count;
int i_new_coupled_count;
+ size_t i_old_map_size, i_new_map_size;
p_old_head = pp_old_data[0];
i_old_channel_count = i_old_stream_count = i_old_coupled_count = 0;
p_old_map = default_map;
+ i_old_map_size = ARRAY_SIZE(default_map);
if( pi_old_size[0] >= 19 && p_old_head[8] <= 15 )
{
i_old_channel_count = p_old_head[9];
@@ -2442,6 +2444,7 @@ static bool Ogg_IsOpusFormatCompatible( const es_format_t *p_new,
i_old_stream_count = p_old_head[19];
i_old_coupled_count = p_old_head[20];
p_old_map = p_old_head + 21;
+ i_old_map_size = i_old_channel_count;
}
break;
}
@@ -2449,6 +2452,7 @@ static bool Ogg_IsOpusFormatCompatible( const es_format_t *p_new,
p_new_head = (unsigned char *)pp_new_data[0];
i_new_channel_count = i_new_stream_count = i_new_coupled_count = 0;
p_new_map = default_map;
+ i_new_map_size = ARRAY_SIZE(default_map);
if( pi_new_size[0] >= 19 && p_new_head[8] <= 15 )
{
i_new_channel_count = p_new_head[9];
@@ -2464,6 +2468,7 @@ static bool Ogg_IsOpusFormatCompatible( const es_format_t *p_new,
i_new_stream_count = p_new_head[19];
i_new_coupled_count = p_new_head[20];
p_new_map = p_new_head+21;
+ i_new_map_size = i_new_channel_count;
}
break;
}
@@ -2471,8 +2476,9 @@ static bool Ogg_IsOpusFormatCompatible( const es_format_t *p_new,
b_match = i_old_channel_count == i_new_channel_count &&
i_old_stream_count == i_new_stream_count &&
i_old_coupled_count == i_new_coupled_count &&
+ i_old_map_size == i_new_map_size &&
memcmp(p_old_map, p_new_map,
- i_new_channel_count*sizeof(*p_new_map)) == 0;
+ i_new_map_size*sizeof(*p_new_map)) == 0;
}
return b_match;
=====================================
modules/demux/ty.c
=====================================
@@ -265,7 +265,7 @@ struct demux_sys_t
static int get_chunk_header(demux_t *);
static vlc_tick_t get_pts( const uint8_t *buf );
static int find_es_header( const uint8_t *header,
- const uint8_t *buffer, int i_search_len );
+ const uint8_t *buffer, size_t buffer_len, size_t i_search_len );
static int ty_stream_seek_pct(demux_t *p_demux, double seek_pct);
static int ty_stream_seek_time(demux_t *, uint64_t);
@@ -585,11 +585,11 @@ static vlc_tick_t get_pts( const uint8_t *buf )
/* =========================================================================== */
static int find_es_header( const uint8_t *header,
- const uint8_t *buffer, int i_search_len )
+ const uint8_t *buffer, size_t buffer_len, size_t i_search_len )
{
- int count;
+ size_t count;
- for( count = 0; count < i_search_len; count++ )
+ for( count = 0; count < i_search_len && count + 4 < buffer_len; count++ )
{
if( !memcmp( &buffer[count], header, 4 ) )
return count;
@@ -700,7 +700,7 @@ static int DemuxRecVideo( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
* on S1, only 0x06 has PES. On S2, however, most all do.
* Do NOT Pass the PES Header to the MPEG2 codec */
size_t search_len = __MIN(l_rec_size - sizeof(ty_VideoPacket), 5);
- esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, search_len );
+ esOffset1 = find_es_header( ty_VideoPacket, p_block_in->p_buffer, p_block_in->i_buffer, search_len );
if( esOffset1 != -1 )
{
//msg_Dbg(p_demux, "Video PES hdr in pkt type 0x%02x at offset %d",
@@ -871,10 +871,10 @@ static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
/* get the PTS out of this PES header (MPEG or AC3) */
if (p_sys->audio_type == TIVO_AUDIO_MPEG)
esOffset1 = find_es_header(ty_MPEGAudioPacket,
- p_sys->pes_buffer, 5);
+ p_sys->pes_buffer, ARRAY_SIZE(p_sys->pes_buffer), 5);
else
esOffset1 = find_es_header(ty_AC3AudioPacket,
- p_sys->pes_buffer, 5);
+ p_sys->pes_buffer, ARRAY_SIZE(p_sys->pes_buffer), 5);
if (esOffset1 < 0)
{
/* god help us; something's really wrong */
@@ -910,7 +910,7 @@ static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
/* MPEG Audio with PES Header, either SA or DTiVo */
/* ================================================ */
esOffset1 = find_es_header( ty_MPEGAudioPacket,
- p_block_in->p_buffer, 5 );
+ p_block_in->p_buffer, p_block_in->i_buffer, 5 );
/*msg_Dbg(p_demux, "buffer has %#02x %#02x %#02x %#02x",
p_block_in->p_buffer[0], p_block_in->p_buffer[1],
@@ -971,7 +971,7 @@ static int DemuxRecAudio( demux_t *p_demux, ty_rec_hdr_t *rec_hdr, block_t *p_bl
/* DTiVo AC3 Audio Data with PES Header */
/* ================================================ */
esOffset1 = find_es_header( ty_AC3AudioPacket,
- p_block_in->p_buffer, 5 );
+ p_block_in->p_buffer, p_block_in->i_buffer, 5 );
#if 0
msg_Dbg(p_demux, "buffer has "
@@ -1770,6 +1770,7 @@ static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
{
demux_sys_t *p_sys = p_demux->p_sys;
int i_num_recs, i;
+ size_t chunk_size = CHUNK_SIZE;
ty_rec_hdr_t *p_hdrs;
int i_num_6e0, i_num_be0, i_num_9c0, i_num_3c0;
int i_payload_size;
@@ -1787,6 +1788,7 @@ static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
}
p_chunk += CHUNK_HEADER_SIZE; /* skip past rec count & SEQ bytes */
+ chunk_size -= CHUNK_HEADER_SIZE;
//msg_Dbg(p_demux, "probe: chunk has %d recs", i_num_recs);
p_hdrs = parse_chunk_headers(p_chunk, i_num_recs, &i_payload_size);
if (unlikely(p_hdrs == NULL))
@@ -1851,12 +1853,13 @@ static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
p_hdrs[i].l_rec_size > 15) {
/* first make sure we're aligned */
int i_pes_offset = find_es_header(ty_MPEGAudioPacket,
- &p_chunk[i_data_offset], 5);
+ &p_chunk[i_data_offset], chunk_size - i_data_offset, 5);
if (i_pes_offset >= 0) {
/* pes found. on SA, PES has hdr data at offset 6, not PTS. */
//msg_Dbg(p_demux, "probe: mpeg es header found in rec %d at offset %d",
//i, i_pes_offset);
- if ((p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
+ if (i_data_offset + 6 + i_pes_offset < chunk_size &&
+ (p_chunk[i_data_offset + 6 + i_pes_offset] & 0x80) == 0x80) {
/* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */
if (p_sys->tivo_series == TIVO_SERIES1)
msg_Dbg(p_demux, "detected Stand-Alone Tivo" );
@@ -1872,6 +1875,11 @@ static int analyze_chunk(demux_t *p_demux, const uint8_t *p_chunk)
}
}
i_data_offset += p_hdrs[i].l_rec_size;
+ if (i_data_offset > chunk_size)
+ {
+ msg_Dbg(p_demux, "rec[%d] overflows the size of the records %ld, aborting", i, p_hdrs[i].l_rec_size);
+ break;
+ }
}
}
free(p_hdrs);
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/d0adf4fbb02555447fa6880a53c4f29a1629d7d5...f7745d071ba5b7164bb06c22322dcfd278e384da
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/d0adf4fbb02555447fa6880a53c4f29a1629d7d5...f7745d071ba5b7164bb06c22322dcfd278e384da
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list