summaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorLynne <dev@lynne.ee>2019-03-07 18:15:23 +0000
committerLynne <dev@lynne.ee>2020-05-26 10:23:13 +0100
commitb8d9bc2e87ef19cfc26cdbdc94062a5ce3201f6c (patch)
treebef1002fbedf46bd72eb1847b12a8d5c69bfafda /libavcodec
parente69f407b52110387800ee0531aa78e213b214150 (diff)
pngdec: add ability to check chunk CRC
By default now, if AV_EF_CRCCHECK or AV_EF_IGNORE_ERR are enabled the decoder will skip the chunk and carry on with the next one. This should make the decoder able to decode more corrupt files because the functions which decode individual chunks will very likely error out if fed invalid data and stop the decoding of the entire image.
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/pngdec.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c
index 86f885bbee..ff3882a58d 100644
--- a/libavcodec/pngdec.c
+++ b/libavcodec/pngdec.c
@@ -23,6 +23,7 @@
#include "libavutil/avassert.h"
#include "libavutil/bprint.h"
+#include "libavutil/crc.h"
#include "libavutil/imgutils.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/stereo3d.h"
@@ -1179,6 +1180,7 @@ static int handle_p_frame_apng(AVCodecContext *avctx, PNGDecContext *s,
static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
AVFrame *p, AVPacket *avpkt)
{
+ const AVCRC *crc_tab = av_crc_get_table(AV_CRC_32_IEEE_LE);
AVDictionary **metadatap = NULL;
uint32_t tag, length;
int decode_next_dat = 0;
@@ -1213,6 +1215,21 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s,
ret = AVERROR_INVALIDDATA;
goto fail;
}
+ if (avctx->err_recognition & (AV_EF_CRCCHECK | AV_EF_IGNORE_ERR)) {
+ uint32_t crc_sig = AV_RB32(s->gb.buffer + length + 4);
+ uint32_t crc_cal = ~av_crc(crc_tab, UINT32_MAX, s->gb.buffer, length + 4);
+ if (crc_sig ^ crc_cal) {
+ av_log(avctx, AV_LOG_ERROR, "CRC mismatch in chunk");
+ if (avctx->err_recognition & AV_EF_EXPLODE) {
+ av_log(avctx, AV_LOG_ERROR, ", quitting\n");
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
+ av_log(avctx, AV_LOG_ERROR, ", skipping\n");
+ bytestream2_skip(&s->gb, 4); /* tag */
+ goto skip_tag;
+ }
+ }
tag = bytestream2_get_le32(&s->gb);
if (avctx->debug & FF_DEBUG_STARTCODE)
av_log(avctx, AV_LOG_DEBUG, "png: tag=%s length=%u\n",