[FFmpeg-devel] [PATCH] add Weston Capture demuxer, parser and decoder

Tomas Härdin tjoppen at acc.umu.se
Sun Sep 10 22:53:12 EEST 2017


On Sun, 2017-09-10 at 21:03 +0200, Paul B Mahol wrote:
> +static av_cold int wcap_decode_init(AVCodecContext *avctx)
> +{
> +    WCAPContext *s = avctx->priv_data;
> +    uint32_t format;
> +
> +    if (avctx->extradata && avctx->extradata_size >= 4) {
> +        format = AV_RL32(avctx->extradata);
> +
> +        switch (format) {
> +        case 0x34325852: avctx->pix_fmt = AV_PIX_FMT_RGB0; break;
> +        case 0x34325842: avctx->pix_fmt = AV_PIX_FMT_BGR0; break;
> +        case 0x34325258: avctx->pix_fmt = AV_PIX_FMT_0RGB; break;
> +        case 0x34324258: avctx->pix_fmt = AV_PIX_FMT_0BGR; break;
> +        }

default: return AVERROR_INVALIDDATA ?

> +    }
> +
> +    s->frame = av_frame_alloc();
> +    if (!s->frame)
> +        return AVERROR(ENOMEM);
> +
> +    return 0;
> +}
> +
> +static void clear(AVCodecContext *avctx)
> +{
> +    WCAPContext *s = avctx->priv_data;
> +    int y;
> +
> +    if (!s->frame->buf[0])
> +        return;
> +
> +    for (y = 0; y < avctx->height; y++) {
> +        memset(s->frame->data[0] + y * s->frame->linesize[0], 0,
> avctx->width * 4);
> +    }
> +}

Wasn't there a AVFrame clear function added to lavu recently?

> +
> +static int wcap_decode_frame(AVCodecContext *avctx, void *data,
> +                            int *got_frame, AVPacket *avpkt)
> +{
> +    WCAPContext *s = avctx->priv_data;
> +    AVFrame *frame = s->frame;
> +    uint32_t nrects, x1, y1, x2, y2;
> +    int ret, n, i, k, x;
> +    GetByteContext gb;
> +    uint8_t *dst;
> +
> +    if ((ret = av_image_check_size(avctx->width, avctx->height, 0,
> NULL)) < 0)
> +        return ret;
> +
> +    bytestream2_init(&gb, avpkt->data, avpkt->size);
> +
> +    if ((ret = ff_reget_buffer(avctx, frame)) < 0)
> +        return ret;
> +
> +    if (avpkt->flags & AV_PKT_FLAG_KEY) {
> +        clear(avctx);
> +    }
> +
> +    bytestream2_skip(&gb, 4);
> +    nrects = bytestream2_get_le32(&gb);
> +
> +    for (n = 0; n < nrects; n++) {

n is signed, nrects is unsigned -> infinite loop for any value >=
0x80000000

Might want to bound nrecs <= avpkt->size / 20 too, or check if
the GetByteContext ran out of bits

> +        x1 = bytestream2_get_le32(&gb);
> +        y1 = bytestream2_get_le32(&gb);
> +        x2 = bytestream2_get_le32(&gb);
> +        y2 = bytestream2_get_le32(&gb);
> +
> +        if (x1 >= x2 || y1 >= y2 || x2 > avctx->width || y2 > avctx-
> >height ||
> +            (x2 - x1) > avctx->width || (y2 - y1) > avctx->height)
> +            return AVERROR_INVALIDDATA;
> +
> +        x = x1;
> +        dst = frame->data[0] + (avctx->height - y1 - 1) * frame-
> >linesize[0];
> +
> +        for (i = 0; i < (x2 - x1) * (y2 - y1);) {

Frames can't be larger than 2 Gi pixels, right?

> +            unsigned v = bytestream2_get_le32(&gb);
> +            int run_len = v >> 24;
> +
> +            if (run_len < 0xE0)
> +                run_len++;
> +            else
> +                run_len = 1 << (run_len - 0xE0 + 7);

This overflows on 32-bit if run_len >= 0xF8

(holy crap, C's lack of static checks is annoying)

> +
> +            i += run_len;
> +            for (k = 0; k < run_len; k++) {
> +                dst[x*4 + 1] += v & 0xFF;
> +                dst[x*4 + 2] += (v >> 8) & 0xFF;
> +                dst[x*4 + 3] += (v >> 16) & 0xFF;
> +                x++;
> +                if (x == x2) {
> +                    x = x1;
> +                    dst -= frame->linesize[0];
> +                }

This can easily write past the end of the frame


/Tomas
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20170910/04cd4490/attachment.sig>


More information about the ffmpeg-devel mailing list