After two mails to VLC security team and lack of answer I decided to public this research before any patch. Presented here vulns are not too evil (Local DoS) so making them public will not cause any damage for VLC users.
==[ Details ]==
<= VLC media player 2.0.1 contains vulnerabilities in few Demuxers:
1. voc.c – DoS via Divison by 0 2. smf.c – DoS via Infinite loop 3. au.c – DoS via Division by 0
1. Details voc.c – DoS via Divison by 0:
First scenario:
ReadBlockHeader function to handle block data type 0x9 contains the following code:
Line 304: case 9: /* newer data block with channel number and bits resolution */ if( i_block_size < 12 ) goto corrupt; i_block_size -= 12; if( ( stream_Read( p_demux->s, buf, 8 ) < 8 ) || ( stream_Read( p_demux->s, NULL, 4 ) < 4 ) ) goto corrupt; new_fmt.audio.i_rate = GetDWLE( buf ); new_fmt.audio.i_bitspersample = buf[4]; new_fmt.audio.i_channels = buf[5];
If block header at offset 0x5 will be set to 0 then new_fmt.audio.i_channels = 0, what causes:
Line 360: new_fmt.audio.i_bytes_per_frame = new_fmt.audio.i_channels * (new_fmt.audio.i_bitspersample / 8);
that new_fmt.audio.i_bytes_per_frame will be set to 0 and after exit from ReadBlockHeader the following code:
Line 428: while( ( i_offset >= p_sys->i_block_end ) && ( p_sys->i_silence_countdown == 0 ) ) if( ReadBlockHeader( p_demux ) != VLC_SUCCESS ) return 0; if( p_sys->i_silence_countdown == 0 ) { i = ( p_sys->i_block_end - i_offset ) / p_sys->fmt.audio.i_bytes_per_frame; // <- div by 0
in Demux function leads to division by zero and as an end result VLC crash.
Second scenario:
Because at the beginning in ReadBlockHeader function, structure new_fmt (es_format_t) is initialized by zero:
Line 175: es_format_Init( &new_fmt, AUDIO_ES, 0 );
therefore if type of first block will be set to different one where “normal” new_fmt structure initialization occurs e.g 0x6 then at the end of
ReadBlockHeader ,
Line 399: if( p_sys->p_es == NULL ) { memcpy( &p_sys->fmt, &new_fmt, sizeof( p_sys->fmt ) );
new_fmt structure initialized by 0 will be copied to p_sys->fmt which leads to division by zero after return to Demux function like in above scenario.
2. smf.c – DoS via Infinite loop
In Open function we see the following code:
Line 210: for (;;) { stream_Read (stream, head, 8); if (memcmp (head, "MTrk", 4) == 0) break; msg_Dbg (p_this, "skipping unknown SMF chunk"); stream_Read (stream, NULL, GetDWBE (head + 4)); }
it aim is to find „MTrk” ID chunk. But like we can also notice there is lack of checks for stream_Read function indicating that end of stream occurred.
File with malformed or without “MTrk” ID chunk will cause infinite loop and as a result VLC DoS.
3 au.c – DoS via Division by 0
Line 144: /* init fmt */ es_format_Init( &p_sys->fmt, AUDIO_ES, 0 ); p_sys->fmt.audio.i_rate = GetDWBE( &hdr[12] ); p_sys->fmt.audio.i_channels = GetDWBE( &hdr[16] );
setting 0(DWORD) at file offset len(“.snd”)+12 => 16 we set 0 value for i_rate field. Lack of any inspection of this field and its value leads to division by zero at
Line 278: p_sys->i_frame_length = (mtime_t)1000000 * (mtime_t)i_samples / (mtime_t)p_sys->fmt.audio.i_rate;
and as an end result to VLC crash.
==[ Proof of Concept ]==
1. voc.c - DoS via Divison by 0: File sample: http://samples.libav.org/voc/pcm_s16_2/nem.voc First scenario: Change offset 0x23 value from 0x02 to 0x0 Second scenario: Change offset 0x1A value from 0x060C842E to 0x06020000 2. smf.c - DoS via Infinite loop File sample: http://upload.wikimedia.org/wikipedia/commons/6/61/Drum_sample.mid Malform “MTrk” chunk ID anyhow e.g “ATrk”. 3. au.c - DoS via Division by 0 File sample: http://samples.libav.org/au/garelka.au Change offset 0x10 value from 0x00001F40 to 0x00000000