From 9fc1031ac2e8691e0140854d727b58cb62431b2b Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Wed, 24 Apr 2019 21:14:19 +0200 Subject: [PATCH] avcodec/pnm_parser: Remember the size of the image and do not reparse the header Fixes: Timeout (11sec -> 60ms) Fixes: 14270/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_PAM_fuzzer-5734809634078720 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Reviewed-by: Paul B Mahol Signed-off-by: Michael Niedermayer --- libavcodec/pnm_parser.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/libavcodec/pnm_parser.c b/libavcodec/pnm_parser.c index 95241c30b3..210a8a048e 100644 --- a/libavcodec/pnm_parser.c +++ b/libavcodec/pnm_parser.c @@ -24,19 +24,35 @@ #include "parser.h" //for ParseContext #include "pnm.h" +typedef struct PNMParseContext { + ParseContext pc; + int remaining_bytes; +}PNMParseContext; static int pnm_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { - ParseContext *pc = s->priv_data; + PNMParseContext *pnmpc = s->priv_data; + ParseContext *pc = &pnmpc->pc; PNMContext pnmctx; - int next; + int next = END_NOT_FOUND; int skip = 0; for (; pc->overread > 0; pc->overread--) { pc->buffer[pc->index++]= pc->buffer[pc->overread_index++]; } + + if (pnmpc->remaining_bytes) { + int inc = FFMIN(pnmpc->remaining_bytes, buf_size); + skip += inc; + pnmpc->remaining_bytes -= inc; + + if (!pnmpc->remaining_bytes) + next = skip; + goto end; + } + retry: if (pc->index) { pnmctx.bytestream_start = @@ -47,7 +63,6 @@ retry: pnmctx.bytestream = (uint8_t *) buf + skip; /* casts avoid warnings */ pnmctx.bytestream_end = (uint8_t *) buf + buf_size - skip; } - next = END_NOT_FOUND; if (ff_pnm_decode_header(avctx, &pnmctx) < 0) { if (pnmctx.bytestream < pnmctx.bytestream_end) { if (pc->index) { @@ -79,9 +94,11 @@ retry: } if (next != END_NOT_FOUND && pnmctx.bytestream_start != buf + skip) next -= pc->index; - if (next > buf_size) + if (next > buf_size) { + pnmpc->remaining_bytes = next - buf_size; next = END_NOT_FOUND; - + } +end: if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { *poutbuf = NULL; *poutbuf_size = 0; @@ -95,7 +112,7 @@ retry: AVCodecParser ff_pnm_parser = { .codec_ids = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM, AV_CODEC_ID_PBM, AV_CODEC_ID_PAM }, - .priv_data_size = sizeof(ParseContext), + .priv_data_size = sizeof(PNMParseContext), .parser_parse = pnm_parse, .parser_close = ff_parse_close, };