Analysis of CVE-2019-13602: VLC Media Player Integer Underflow

On the 28th of June (2019) a commit was released by Rémi Denis-Courmont fixing an integer underflow vulnerability in the "MP4 demuxer" of VLC. A "demuxer" is a module responsible for extracting the contents of a given file format, in this case MP4. It was given the CVE identifier CVE-2019-13602.

The offending code in question is a complicated giant if statement:

uint32_t i_bytes = 0; ... if ( i_remaining < 10 || !(i_bytes = GetDWBE(p_block->p_buffer)) || (i_bytes > i_remaining) || memcmp("cdat", &p_block->p_buffer[4], 4) || !(p_newblock = block_Alloc( i_remaining * 3 - 8 )) ) { p_block->i_buffer = 0; return p_block; }

The variable i_bytes is an unsigned 32-bit integer. When an integer is unsigned, it means its value can never be negative and any attempts to do so will wrap around (underflow) resulting in an unknown state.

The conditional never checks that i_bytes is large enough, only that it is non-zero and greater than i_remaining (itself being less than 10). Why is that a problem? After this check we see the following:

i_bytes -= 8;

This is where the underflow occurs. Due to i_bytes being an unsigned integer, the moment it is less than zero it will wrap around to the maximum value. Say for instance i_bytes was 3 before this code executes, the result of the subtraction will end up as 4,294,967,291.

Simply by checking if i_bytes is greater than (or equal to) 10 the underflow can no longer happen. Here is the patch that fixes the code:

i_bytes = GetDWBE(p_block->p_buffer); if ( 10 < i_bytes || i_bytes < i_remaining || memcmp("cdat", &p_block->p_buffer[4], 4) || (p_newblock = block_Alloc(i_remaining * 3 - 8)) == NULL)

It is not known whether this could lead to arbitrary code execution but at the very least it can result in a denial of service and should be treated as though it could be exploited. The vulnerability affects all versions of VLC up to and including 3.0.7.1 so look to update your VLC version to the latest.