Commit c69aff7454 for ffmpeg
commit c69aff745431c73e546bdad988ec23f74c79979c
Author: Michael Niedermayer <michael@niedermayer.cc>
Date: Sat Oct 10 05:23:52 2026 +0200
avcodec/exif: stop following an IFD chain that loops
Stop at the first offset that was already parsed.
Timeout Replicated through API
Fixes: Timeout
Fixes: 561208791/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_SMVJPEG_fuzzer-5447460856856576
Fixes: PrLc2prh3sxt
Regression since: 784aa09fa8222f6704d953b5035f8d0f0bec1623
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
diff --git a/libavcodec/exif.c b/libavcodec/exif.c
index f5cb3330af..8169c4f40d 100644
--- a/libavcodec/exif.c
+++ b/libavcodec/exif.c
@@ -932,6 +932,8 @@ int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size,
* parse IFD0 here. If the return value is positive that tells us
* there is subimage metadata, but we don't parse that IFD here
*/
+ int ifd_offsets[17] = { bytestream2_tell(&gbytes) };
+ int nb_ifds = 1;
ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, ifd, 0);
if (ret < 0) {
av_log(logctx, AV_LOG_ERROR, "error decoding EXIF data: %s\n", av_err2str(ret));
@@ -945,6 +947,13 @@ int av_exif_parse_buffer(void *logctx, const uint8_t *buf, size_t size,
/* cap at 16 extra IFDs for sanity/parse security */
for (int extra_tag = 0xFFFCu; extra_tag > 0xFFECu; extra_tag--) {
AVExifMetadata extra_ifd = { 0 };
+ for (int i = 0; i < nb_ifds; i++) {
+ if (ifd_offsets[i] == next) {
+ av_log(logctx, AV_LOG_WARNING, "EXIF IFD chain loops back to offset %d\n", next);
+ goto finish;
+ }
+ }
+ ifd_offsets[nb_ifds++] = next;
ret = exif_parse_ifd_list(logctx, &gbytes, le, 0, &extra_ifd, 1);
if (ret < 0) {
av_exif_free(&extra_ifd);