Commit c0d29437 authored by Francois Cartegnie's avatar Francois Cartegnie Committed by Jean-Baptiste Kempf

demux: ogg: fix packet count heap overflow (fix #12265)

(cherry picked from commit 5e009c7210154b56212e65299dfd92dd85e55b9e)
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 6f1e0a1c
...@@ -423,6 +423,9 @@ static int Demux( demux_t * p_demux ) ...@@ -423,6 +423,9 @@ static int Demux( demux_t * p_demux )
p_sys->current_page.body_len ) p_sys->current_page.body_len )
); );
const int i_page_packets = ogg_page_packets( &p_sys->current_page );
bool b_doprepcr = false;
if ( p_stream->i_pcr < VLC_TS_0 && ogg_page_granulepos( &p_sys->current_page ) > 0 ) if ( p_stream->i_pcr < VLC_TS_0 && ogg_page_granulepos( &p_sys->current_page ) > 0 )
{ {
// PASS 0 // PASS 0
...@@ -431,14 +434,32 @@ static int Demux( demux_t * p_demux ) ...@@ -431,14 +434,32 @@ static int Demux( demux_t * p_demux )
p_stream->fmt.i_codec == VLC_CODEC_SPEEX || p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
p_stream->fmt.i_cat == VIDEO_ES ) p_stream->fmt.i_cat == VIDEO_ES )
{ {
assert( p_stream->p_prepcr_blocks == NULL ); assert( p_stream->prepcr.pp_blocks == NULL );
p_stream->i_prepcr_blocks = 0; b_doprepcr = true;
p_stream->p_prepcr_blocks = malloc( sizeof(block_t *) * ogg_page_packets( &p_sys->current_page ) );
} }
} }
int i_real_page_packets = 0;
while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 ) while( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
{ {
i_real_page_packets++;
int i_max_packets = __MAX(i_page_packets, i_real_page_packets);
if ( b_doprepcr && p_stream->prepcr.i_size < i_max_packets )
{
/* always double alloc for performance */
i_max_packets = __MAX( i_max_packets << 1, 255 );
/* alloc or realloc */
block_t **pp_realloc = realloc( p_stream->prepcr.pp_blocks,
sizeof(block_t *) * i_max_packets );
if ( !pp_realloc )
{
/* drop it then */
continue;
}
p_stream->prepcr.i_size = i_max_packets;
p_stream->prepcr.pp_blocks = pp_realloc;
}
/* Read info from any secondary header packets, if there are any */ /* Read info from any secondary header packets, if there are any */
if( p_stream->i_secondary_header_packets > 0 ) if( p_stream->i_secondary_header_packets > 0 )
{ {
...@@ -480,10 +501,9 @@ static int Demux( demux_t * p_demux ) ...@@ -480,10 +501,9 @@ static int Demux( demux_t * p_demux )
} }
Ogg_DecodePacket( p_demux, p_stream, &oggpacket ); Ogg_DecodePacket( p_demux, p_stream, &oggpacket );
} }
if ( p_stream->p_prepcr_blocks ) if ( p_stream->prepcr.pp_blocks )
{ {
int64_t pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream, ogg_page_granulepos( &p_sys->current_page ), false ); int64_t pagestamp = Oggseek_GranuleToAbsTimestamp( p_stream, ogg_page_granulepos( &p_sys->current_page ), false );
p_stream->i_previous_pcr = pagestamp; p_stream->i_previous_pcr = pagestamp;
...@@ -491,9 +511,9 @@ static int Demux( demux_t * p_demux ) ...@@ -491,9 +511,9 @@ static int Demux( demux_t * p_demux )
int i_prev_blocksize = 0; int i_prev_blocksize = 0;
#endif #endif
// PASS 1 // PASS 1
for( int i=0; i<p_stream->i_prepcr_blocks; i++ ) for( int i=0; i<p_stream->prepcr.i_used; i++ )
{ {
block_t *p_block = p_stream->p_prepcr_blocks[i]; block_t *p_block = p_stream->prepcr.pp_blocks[i];
ogg_packet dumb_packet; ogg_packet dumb_packet;
dumb_packet.bytes = p_block->i_buffer; dumb_packet.bytes = p_block->i_buffer;
dumb_packet.packet = p_block->p_buffer; dumb_packet.packet = p_block->p_buffer;
...@@ -532,9 +552,9 @@ static int Demux( demux_t * p_demux ) ...@@ -532,9 +552,9 @@ static int Demux( demux_t * p_demux )
// PASS 2 // PASS 2
bool b_fixed = false; bool b_fixed = false;
for( int i=p_stream->i_prepcr_blocks - 1; i>=0; i-- ) for( int i=p_stream->prepcr.i_used - 1; i>=0; i-- )
{ {
block_t *p_block = p_stream->p_prepcr_blocks[i]; block_t *p_block = p_stream->prepcr.pp_blocks[i];
switch( p_stream->fmt.i_codec ) switch( p_stream->fmt.i_codec )
{ {
case VLC_CODEC_SPEEX: case VLC_CODEC_SPEEX:
...@@ -568,8 +588,8 @@ static int Demux( demux_t * p_demux ) ...@@ -568,8 +588,8 @@ static int Demux( demux_t * p_demux )
p_stream->i_previous_granulepos = ogg_page_granulepos( &p_sys->current_page ); p_stream->i_previous_granulepos = ogg_page_granulepos( &p_sys->current_page );
} }
FREENULL( p_stream->p_prepcr_blocks ); FREENULL(p_stream->prepcr.pp_blocks);
p_stream->i_prepcr_blocks = 0; p_stream->prepcr.i_used = 0;
Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL ); Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL );
...@@ -662,8 +682,9 @@ static void Ogg_ResetStream( logical_stream_t *p_stream ) ...@@ -662,8 +682,9 @@ static void Ogg_ResetStream( logical_stream_t *p_stream )
p_stream->i_previous_granulepos = -1; p_stream->i_previous_granulepos = -1;
p_stream->i_previous_pcr = VLC_TS_UNKNOWN; p_stream->i_previous_pcr = VLC_TS_UNKNOWN;
ogg_stream_reset( &p_stream->os ); ogg_stream_reset( &p_stream->os );
FREENULL( p_stream->p_prepcr_blocks ); FREENULL( p_stream->prepcr.pp_blocks );
p_stream->i_prepcr_blocks = 0; p_stream->prepcr.i_size = 0;
p_stream->prepcr.i_used = 0;
} }
static void Ogg_ResetStreamsHelper( demux_sys_t *p_sys ) static void Ogg_ResetStreamsHelper( demux_sys_t *p_sys )
...@@ -1050,13 +1071,13 @@ static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -1050,13 +1071,13 @@ static void Ogg_SendOrQueueBlocks( demux_t *p_demux, logical_stream_t *p_stream,
block_t *p_block ) block_t *p_block )
{ {
demux_sys_t *p_ogg = p_demux->p_sys; demux_sys_t *p_ogg = p_demux->p_sys;
if ( !p_stream->p_es || p_stream->p_prepcr_blocks || p_stream->i_pcr == VLC_TS_UNKNOWN ) if ( !p_stream->p_es || p_stream->prepcr.pp_blocks || p_stream->i_pcr == VLC_TS_UNKNOWN )
{ {
if ( !p_block ) return; if ( !p_block ) return;
if ( p_stream->p_prepcr_blocks ) if ( p_stream->prepcr.pp_blocks )
{ {
assert( p_stream->p_prepcr_blocks ); assert( p_stream->prepcr.i_size );
p_stream->p_prepcr_blocks[p_stream->i_prepcr_blocks++] = p_block; p_stream->prepcr.pp_blocks[p_stream->prepcr.i_used++] = p_block;
} }
DemuxDebug( msg_Dbg( p_demux, "block prepcr append > pts %"PRId64" spcr %"PRId64" pcr %"PRId64, DemuxDebug( msg_Dbg( p_demux, "block prepcr append > pts %"PRId64" spcr %"PRId64" pcr %"PRId64,
p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); ) p_block->i_pts, p_stream->i_pcr, p_ogg->i_pcr ); )
...@@ -2181,7 +2202,7 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea ...@@ -2181,7 +2202,7 @@ static void Ogg_LogicalStreamDelete( demux_t *p_demux, logical_stream_t *p_strea
block_ChainRelease( p_stream->p_preparse_block ); block_ChainRelease( p_stream->p_preparse_block );
p_stream->p_preparse_block = NULL; p_stream->p_preparse_block = NULL;
} }
free( p_stream->p_prepcr_blocks ); free( p_stream->prepcr.pp_blocks );
free( p_stream ); free( p_stream );
} }
...@@ -2525,7 +2546,7 @@ static void Ogg_DecodeVorbisHeader( logical_stream_t *p_stream, ...@@ -2525,7 +2546,7 @@ static void Ogg_DecodeVorbisHeader( logical_stream_t *p_stream,
switch( i_number ) switch( i_number )
{ {
case VORBIS_HEADER_IDENTIFICATION: case VORBIS_HEADER_IDENTIFICATION:
p_stream->special.vorbis.p_info = malloc( sizeof(vorbis_info) ); p_stream->special.vorbis.p_info = calloc( 1, sizeof(vorbis_info) );
p_stream->special.vorbis.p_comment = malloc( sizeof(vorbis_comment) ); p_stream->special.vorbis.p_comment = malloc( sizeof(vorbis_comment) );
if ( !p_stream->special.vorbis.p_info || !p_stream->special.vorbis.p_comment ) if ( !p_stream->special.vorbis.p_info || !p_stream->special.vorbis.p_comment )
{ {
......
...@@ -115,8 +115,12 @@ typedef struct logical_stream_s ...@@ -115,8 +115,12 @@ typedef struct logical_stream_s
int i_secondary_header_packets; int i_secondary_header_packets;
/* All blocks which can't be sent because track PCR isn't known yet */ /* All blocks which can't be sent because track PCR isn't known yet */
block_t **p_prepcr_blocks; struct
int i_prepcr_blocks; {
block_t **pp_blocks;
uint8_t i_size; /* max 255 */
uint8_t i_used;
} prepcr;
/* All blocks that are queued because ES isn't created yet */ /* All blocks that are queued because ES isn't created yet */
block_t *p_preparse_block; block_t *p_preparse_block;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment