Attacker Value
Unknown
(1 user assessed)
Exploitability
Unknown
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
0

CVE-2019-13962 avcodec lavc_CopyPicture Heap Buffer Overflow

Last updated February 13, 2020
Add MITRE ATT&CK tactics and techniques that apply to this CVE.

Description

VLC media player is a free and open-source portable cross-platform media player software developed by the VideoLAN project. VLC is available for desktop operating systems and mobile platforms, such as Android, iOS, iPadOS, Wizen, Windows 10 Mobile, and Windows Phone. It is also available on digital distribution platforms such as Apple’s App Store, Google Play, and Microsoft Store. It supports many audio and video compression methods and file formats, and can be used to stream media over computer networks.

A vulnerability was found in the AV codec’s Iavc_CopyPicture function. A malicious video file can be crafted with an invalid width and height, and cause a heap based buffer overflow.

Versions 3.0.7 and prior are vulnerable.

Add Assessment

1
Technical Analysis

CVE-2019-13962 avcodec lavc_CopyPicture Heap Buffer Overflow

VLC media player is a free and open-source portable cross-platform media player software developed by the VideoLAN project. VLC is available for desktop operating systems and mobile platforms, such as Android, iOS, iPadOS, Wizen, Windows 10 Mobile, and Windows Phone. It is also available on digital distribution platforms such as Apple’s App Store, Google Play, and Microsoft Store. It supports many audio and video compression methods and file formats, and can be used to stream media over computer networks.

A vulnerability was found in the AV codec’s Iavc_CopyPicture function. A malicious video file can be crafted with an invalid width and height, and cause a heap based buffer overflow.

Versions 3.0.7 and prior are vulnerable.

Technical Details

In the AV codec, when a video is being decoded, it is done frame by frame (or block). In each frame, the lavc_CopyPicture function is called (found in modules/codec/avcodec/video.c:1177)

        picture_t *p_pic = frame->opaque;
        if( p_pic == NULL )
        {   /* When direct rendering is not used, get_format() and get_buffer()
             * might not be called. The output video format must be set here
             * then picture buffer can be allocated. */
            if (p_sys->p_va == NULL
             && lavc_UpdateVideoFormat(p_dec, p_context, p_context->pix_fmt,
                                       p_context->pix_fmt) == 0)
                p_pic = decoder_NewPicture(p_dec);

            if( !p_pic )
            {
                av_frame_free(&frame);
                break;
            }

            /* Fill picture_t from AVFrame */
            if( lavc_CopyPicture( p_dec, p_pic, frame ) != VLC_SUCCESS )
            {
                av_frame_free(&frame);
                picture_Release( p_pic );
                break;
            }
        }

The lavc_CopyPicture is meant for copying a picture from the libavcodec-allocate buffer to a picture_t. In this function, there is a check:

static int lavc_CopyPicture(decoder_t *dec, picture_t *pic, AVFrame *frame)
{
...
else if (fourcc != pic->format.i_chroma
     || frame->width > (int) pic->format.i_width
     || frame->height > (int) pic->format.i_height) // BUG: CVE-2019-13962
    {
        msg_Warn(dec, "dropping frame because the vout changed");
        return VLC_EGENERIC;
    }
...

The check is actually broken because they are user controlled; The fields found in picture_t may not actually match the values of AVFrame. If done correctly, we could get past this check, reach this part of the code, and trigger the bug:

    for (int plane = 0; plane < pic->i_planes; plane++)
    {
        const uint8_t *src = frame->data[plane];
        uint8_t *dst = pic->p[plane].p_pixels;
        size_t src_stride = frame->linesize[plane];
        size_t dst_stride = pic->p[plane].i_pitch;
        size_t size = __MIN(src_stride, dst_stride);

        for (int line = 0; line < pic->p[plane].i_visible_lines; line++)
        {
            memcpy(dst, src, size);
            src += src_stride;
            dst += dst_stride;
        }
    }

At this point, it is possible to read more than expected from source.

A proof of concept is available from the original advisory: https://trac.videolan.org/vlc/ticket/22240

General Information

Additional Info

Technical Analysis