Commit message: avcodec/parser: reset indexes on realloc failure

Fixes Ticket2982

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
CVE: CVE-2013-7023
CWE: CWE-119
Vulnerability description: The ff_combine_frame function in libavcodec/parser.c in FFmpeg before 2.1 does not properly handle certain memory-allocation errors, which allows remote attackers to cause a denial of service (out-of-bounds array access) or possibly have unspecified other impact via crafted data.

Project: FFmpeg
File: parser.c

int av_parser_change(AVCodecParserContext *s,
                     AVCodecContext *avctx,
                     uint8_t **poutbuf, int *poutbuf_size,
                     const uint8_t *buf, int buf_size, int keyframe){

    if(s && s->parser->split){
        if((avctx->flags & CODEC_FLAG_GLOBAL_HEADER) || (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER)){
            int i= s->parser->split(avctx, buf, buf_size);
            buf += i;
            buf_size -= i;
        }
    }

    /* cast to avoid warning about discarding qualifiers */
    *poutbuf= (uint8_t *) buf;
    *poutbuf_size= buf_size;
    if(avctx->extradata){
        if(  (keyframe && (avctx->flags2 & CODEC_FLAG2_LOCAL_HEADER))
            /*||(s->pict_type != AV_PICTURE_TYPE_I && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_NOKEY))*/
            /*||(? && (s->flags & PARSER_FLAG_DUMP_EXTRADATA_AT_BEGIN)*/){
            int size= buf_size + avctx->extradata_size;
            *poutbuf_size= size;
            *poutbuf= av_malloc(size + FF_INPUT_BUFFER_PADDING_SIZE);

            memcpy(*poutbuf, avctx->extradata, avctx->extradata_size);
            memcpy((*poutbuf) + avctx->extradata_size, buf, buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
            return 1;
        }
    }

    return 0;
}

Project: FFmpeg
File: parser.c

void av_parser_close(AVCodecParserContext *s)
{
    if(s){
        if (s->parser->parser_close)
            s->parser->parser_close(s);
        av_free(s->priv_data);
        av_free(s);
    }
}

Project: FFmpeg
File: parser.c

AVCodecParserContext *av_parser_init(int codec_id)
{
    AVCodecParserContext *s = NULL;
    AVCodecParser *parser;
    int ret;

    if(codec_id == AV_CODEC_ID_NONE)
        return NULL;

    for(parser = av_first_parser; parser != NULL; parser = parser->next) {
        if (parser->codec_ids[0] == codec_id ||
            parser->codec_ids[1] == codec_id ||
            parser->codec_ids[2] == codec_id ||
            parser->codec_ids[3] == codec_id ||
            parser->codec_ids[4] == codec_id)
            goto found;
    }
    return NULL;
 found:
    s = av_mallocz(sizeof(AVCodecParserContext));
    if (!s)
        goto err_out;
    s->parser = parser;
    s->priv_data = av_mallocz(parser->priv_data_size);
    if (!s->priv_data)
        goto err_out;
    s->fetch_timestamp=1;
    s->pict_type = AV_PICTURE_TYPE_I;
    if (parser->parser_init) {
        ret = parser->parser_init(s);
        if (ret != 0)
            goto err_out;
    }
    s->key_frame = -1;
    s->convergence_duration = 0;
    s->dts_sync_point       = INT_MIN;
    s->dts_ref_dts_delta    = INT_MIN;
    s->pts_dts_delta        = INT_MIN;
    return s;

err_out:
    if (s)
        av_freep(&s->priv_data);
    av_free(s);
    return NULL;
}

Project: FFmpeg
File: parser.c

AVCodecParser* av_parser_next(AVCodecParser *p){
    if(p) return p->next;
    else  return av_first_parser;
}

Project: FFmpeg

void ff_fetch_timestamp(AVCodecParserContext *s, int off, int remove){
    int i;

    s->dts= s->pts= AV_NOPTS_VALUE;
    s->pos= -1;
    s->offset= 0;
    for(i = 0; i < AV_PARSER_PTS_NB; i++) {
        if (   s->cur_offset + off >= s->cur_frame_offset[i]
            && (s->frame_offset < s->cur_frame_offset[i] ||
              (!s->frame_offset && !s->next_frame_offset)) // first field/frame
            && /*s->next_frame_offset + off <*/  s->cur_frame_end[i]){
            s->dts= s->cur_frame_dts[i];
            s->pts= s->cur_frame_pts[i];
            s->pos= s->cur_frame_pos[i];
            s->offset = s->next_frame_offset - s->cur_frame_offset[i];
            if(remove)
                s->cur_frame_offset[i]= INT64_MAX;
            if(s->cur_offset + off < s->cur_frame_end[i])
                break;
        }
    }
}

Project: FFmpeg
File: parser.c

int ff_mpeg4video_split(AVCodecContext *avctx,
                           const uint8_t *buf, int buf_size)
{
    int i;
    uint32_t state= -1;

    for(i=0; i<buf_size; i++){
        state= (state<<8) | buf[i];
        if(state == 0x1B3 || state == 0x1B6)
            return i-3;
    }
    return 0;
}

Project: FFmpeg
File: parser.c

void ff_parse_close(AVCodecParserContext *s)
{
    ParseContext *pc = s->priv_data;

    av_freep(&pc->buffer);
}