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 )
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 )
{
// PASS 0
......@@ -431,14 +434,32 @@ static int Demux( demux_t * p_demux )
p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
p_stream->fmt.i_cat == VIDEO_ES )
{
assert( p_stream->p_prepcr_blocks == NULL );
p_stream->i_prepcr_blocks = 0;
p_stream->p_prepcr_blocks = malloc( sizeof(block_t *) * ogg_page_packets( &p_sys->current_page ) );
assert( p_stream->prepcr.pp_blocks == NULL );
b_doprepcr = true;
}
}
int i_real_page_packets = 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 */
if( p_stream->i_secondary_header_packets > 0 )
{
......@@ -480,10 +501,9 @@ static int Demux( demux_t * p_demux )
}
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 );
p_stream->i_previous_pcr = pagestamp;
......@@ -491,9 +511,9 @@ static int Demux( demux_t * p_demux )
int i_prev_blocksize = 0;
#endif
// 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;
dumb_packet.bytes = p_block->i_buffer;
dumb_packet.packet = p_block->p_buffer;
......@@ -532,9 +552,9 @@ static int Demux( demux_t * p_demux )
// PASS 2
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 )
{
case VLC_CODEC_SPEEX:
......@@ -568,8 +588,8 @@ static int Demux( demux_t * p_demux )
p_stream->i_previous_granulepos = ogg_page_granulepos( &p_sys->current_page );
}
FREENULL( p_stream->p_prepcr_blocks );
p_stream->i_prepcr_blocks = 0;
FREENULL(p_stream->prepcr.pp_blocks);
p_stream->prepcr.i_used = 0;
Ogg_SendOrQueueBlocks( p_demux, p_stream, NULL );
......@@ -662,8 +682,9 @@ static void Ogg_ResetStream( logical_stream_t *p_stream )
p_stream->i_previous_granulepos = -1;
p_stream->i_previous_pcr = VLC_TS_UNKNOWN;
ogg_stream_reset( &p_stream->os );
FREENULL( p_stream->p_prepcr_blocks );
p_stream->i_prepcr_blocks = 0;
FREENULL( p_stream->prepcr.pp_blocks );
p_stream->prepcr.i_size = 0;
p_stream->prepcr.i_used = 0;
}
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,
block_t *p_block )
{
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_stream->p_prepcr_blocks )
if ( p_stream->prepcr.pp_blocks )
{
assert( p_stream->p_prepcr_blocks );
p_stream->p_prepcr_blocks[p_stream->i_prepcr_blocks++] = p_block;
assert( p_stream->prepcr.i_size );
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,
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
block_ChainRelease( p_stream->p_preparse_block );
p_stream->p_preparse_block = NULL;
}
free( p_stream->p_prepcr_blocks );
free( p_stream->prepcr.pp_blocks );
free( p_stream );
}
......@@ -2525,7 +2546,7 @@ static void Ogg_DecodeVorbisHeader( logical_stream_t *p_stream,
switch( i_number )
{
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) );
if ( !p_stream->special.vorbis.p_info || !p_stream->special.vorbis.p_comment )
{
......
......@@ -115,8 +115,12 @@ typedef struct logical_stream_s
int i_secondary_header_packets;
/* All blocks which can't be sent because track PCR isn't known yet */
block_t **p_prepcr_blocks;
int i_prepcr_blocks;
struct
{
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 */
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