CVE-2019-13962 avcodec lavc_CopyPicture Heap Buffer Overflow

2019-08-19T21:38:49
ID AKB:4AA126B3-F93D-4E11-B00B-01EEC76A98C1
Type attackerkb
Reporter AttackerKB
Modified 2020-02-13T17:12:25

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.

Recent assessments:

wchen-r7 at 2019-09-12T18:06:46.913387Z reported:

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)

```c 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:

c 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:

```c 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 &lt; pic-&gt;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