PR #22415 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22415 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22415.patch
>From 5acd4d17cc272f22de08785491a2e8e14c85cd73 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Wed, 20 Aug 2025 17:07:50 -0300 Subject: [PATCH 1/7] avformat/mov: make items referencing items generic Signed-off-by: James Almer <[email protected]> (cherry picked from commit 74e430202d933284fc38b591d4b3a12464e8aec6) --- libavformat/isom.h | 9 +++++-- libavformat/mov.c | 67 +++++++++++++++++++++------------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/libavformat/isom.h b/libavformat/isom.h index 94c9c65989..55bc2827b4 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -286,8 +286,15 @@ typedef struct MOVStreamContext { int iamf_stream_offset; } MOVStreamContext; +typedef struct HEIFItemRef { + uint32_t type; + int item_id; +} HEIFItemRef; + typedef struct HEIFItem { AVStream *st; + HEIFItemRef *iref_list; + int nb_iref_list; char *name; int item_id; int64_t extent_length; @@ -376,8 +383,6 @@ typedef struct MOVContext { int nb_heif_item; HEIFGrid *heif_grid; int nb_heif_grid; - int* thmb_item_id; - int nb_thmb_item; int64_t idat_offset; int interleaved_read; } MOVContext; diff --git a/libavformat/mov.c b/libavformat/mov.c index 49498eda77..dc082b3500 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -188,14 +188,14 @@ static int mov_read_mac_string(MOVContext *c, AVIOContext *pb, int len, } /** - * Get the current item in the parsing process. + * Get the requested item. */ -static HEIFItem *heif_cur_item(MOVContext *c) +static HEIFItem *get_heif_item(MOVContext *c, unsigned id) { HEIFItem *item = NULL; for (int i = 0; i < c->nb_heif_item; i++) { - if (!c->heif_item[i] || c->heif_item[i]->item_id != c->cur_item_id) + if (!c->heif_item[i] || c->heif_item[i]->item_id != id) continue; item = c->heif_item[i]; @@ -220,7 +220,7 @@ static AVStream *get_curr_st(MOVContext *c) if (c->cur_item_id == -1) return c->fc->streams[c->fc->nb_streams-1]; - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); if (item) st = item->st; @@ -1245,7 +1245,7 @@ static int mov_read_clap(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVRational pc_x, pc_y; uint64_t top, bottom, left, right; - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); st = get_curr_st(c); if (!st) return 0; @@ -2078,7 +2078,7 @@ static int mov_read_colr(MOVContext *c, AVIOContext *pb, MOVAtom atom) st = get_curr_st(c); if (!st) { - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); if (!item) return 0; } @@ -9095,30 +9095,33 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version) static int mov_read_iref_thmb(MOVContext *c, AVIOContext *pb, int version) { - int *thmb_item_id; + HEIFItem *from_item = NULL; int entries; - int to_item_id, from_item_id = version ? avio_rb32(pb) : avio_rb16(pb); + int from_item_id = version ? avio_rb32(pb) : avio_rb16(pb); + const HEIFItemRef ref = { MKTAG('t','h','m','b'), from_item_id }; + + from_item = get_heif_item(c, from_item_id); + if (!from_item) { + av_log(c->fc, AV_LOG_ERROR, "Missing stream referenced by thmb item\n"); + return AVERROR_INVALIDDATA; + } entries = avio_rb16(pb); - if (entries > 1) { - avpriv_request_sample(c->fc, "thmb in iref referencing several items"); - return AVERROR_PATCHWELCOME; - } /* 'to' item ids */ - to_item_id = version ? avio_rb32(pb) : avio_rb16(pb); + for (int i = 0; i < entries; i++) { + HEIFItem *item = get_heif_item(c, version ? avio_rb32(pb) : avio_rb16(pb)); + if (!item) { + av_log(c->fc, AV_LOG_WARNING, "Missing stream referenced by thmb item\n"); + continue; + } - if (to_item_id != c->primary_item_id) - return 0; + if (!av_dynarray2_add((void **)&item->iref_list, &item->nb_iref_list, + sizeof(*item->iref_list), (const uint8_t *)&ref)) + return AVERROR(ENOMEM); + } - /* Put thumnbail IDs into an array */ - thmb_item_id = av_dynarray2_add((void **)&c->thmb_item_id, &c->nb_thmb_item, - sizeof(*c->thmb_item_id), - (const void *)&from_item_id); - if (!thmb_item_id) - return AVERROR(ENOMEM); - - av_log(c->fc, AV_LOG_TRACE, "thmb: from_item_id %d, entries %d, nb_thmb: %d\n", - from_item_id, entries, c->nb_thmb_item); + av_log(c->fc, AV_LOG_TRACE, "thmb: from_item_id %d, entries %d\n", + from_item_id, entries); return 0; } @@ -9174,7 +9177,7 @@ static int mov_read_ispe(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "ispe: item_id %d, width %u, height %u\n", c->cur_item_id, width, height); - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); if (item) { item->width = width; item->height = height; @@ -9193,7 +9196,7 @@ static int mov_read_irot(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "irot: item_id %d, angle %u\n", c->cur_item_id, angle); - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); if (item) { // angle * 90 specifies the angle (in anti-clockwise direction) // in units of degrees. @@ -9213,7 +9216,7 @@ static int mov_read_imir(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "imir: item_id %d, axis %u\n", c->cur_item_id, axis); - item = heif_cur_item(c); + item = get_heif_item(c, c->cur_item_id); if (item) { item->hflip = axis; item->vflip = !axis; @@ -9978,6 +9981,7 @@ static int mov_read_close(AVFormatContext *s) if (!mov->heif_item[i]) continue; av_freep(&mov->heif_item[i]->name); + av_freep(&mov->heif_item[i]->iref_list); av_freep(&mov->heif_item[i]->icc_profile); av_freep(&mov->heif_item[i]); } @@ -9988,7 +9992,6 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->heif_grid[i].tile_item_list); } av_freep(&mov->heif_grid); - av_freep(&mov->thmb_item_id); return 0; } @@ -10453,13 +10456,6 @@ static int mov_parse_heif_items(AVFormatContext *s) if (!item) continue; if (!item->st) { - for (int j = 0; j < mov->nb_thmb_item; j++) { - if (item->item_id == mov->thmb_item_id[j]) { - av_log(s, AV_LOG_ERROR, "HEIF thumbnail ID %d doesn't reference a stream\n", - item->item_id); - return AVERROR_INVALIDDATA; - } - } continue; } if (item->is_idat_relative) { @@ -10625,7 +10621,6 @@ static int mov_read_header(AVFormatContext *s) mov->fc = s; mov->trak_index = -1; - mov->thmb_item_id = NULL; mov->primary_item_id = -1; mov->cur_item_id = -1; /* .mov and .mp4 aren't streamable anyway (only progressive download if moov is before mdat) */ -- 2.52.0 >From 19df26bc82064646fbc8a4cc92f294237bfd5267 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Fri, 21 Nov 2025 16:58:13 -0300 Subject: [PATCH 2/7] avformat/mov: don't parse reserved ISOBMFF fields as if they were QT Signed-off-by: James Almer <[email protected]> (cherry picked from commit c0044ec9c4e5eacb5aa58a75f67b1ad857147437) --- libavformat/mov.c | 10 ++++++++++ tests/ref/fate/h264_redundant_pps-side_data | 4 ++-- tests/ref/fate/h264_redundant_pps-side_data2 | 4 ++-- tests/ref/fate/matroska-alac-remux | 4 ++-- tests/ref/fate/matroska-dovi-write-config7 | 4 ++-- tests/ref/fate/mov-mp4-iamf-5_1_4 | 2 -- tests/ref/fate/mov-mp4-iamf-7_1_4-video-first | 2 -- tests/ref/fate/mov-mp4-iamf-7_1_4-video-last | 2 -- tests/ref/fate/mov-mp4-iamf-ambisonic_1 | 2 -- tests/ref/fate/mov-mp4-iamf-stereo | 2 -- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index dc082b3500..b724c310ef 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2676,12 +2676,18 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, * read in ff_mov_read_stsd_entries() */ stsd_start = avio_tell(pb) - 16; + if (c->isom) { + avio_skip(pb, 2); /* pre_defined */ + avio_skip(pb, 2); /* reserved */ + avio_skip(pb, 12); /* pre_defined */ + } else { avio_rb16(pb); /* version */ avio_rb16(pb); /* revision level */ id = avio_rl32(pb); /* vendor */ av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); avio_rb32(pb); /* temporal quality */ avio_rb32(pb); /* spatial quality */ + } st->codecpar->width = avio_rb16(pb); /* width */ st->codecpar->height = avio_rb16(pb); /* height */ @@ -2731,9 +2737,13 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, AVDictionaryEntry *compatible_brands = av_dict_get(c->fc->metadata, "compatible_brands", NULL, AV_DICT_MATCH_CASE); int channel_count; + if (c->isom) + avio_skip(pb, 6); /* reserved */ + else { avio_rb16(pb); /* revision level */ id = avio_rl32(pb); /* vendor */ av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); + } channel_count = avio_rb16(pb); diff --git a/tests/ref/fate/h264_redundant_pps-side_data b/tests/ref/fate/h264_redundant_pps-side_data index 1f4684bf5b..0f41dcde48 100644 --- a/tests/ref/fate/h264_redundant_pps-side_data +++ b/tests/ref/fate/h264_redundant_pps-side_data @@ -1,5 +1,5 @@ -92fe70291f72acf94ba56b426bbaccb0 *tests/data/fate/h264_redundant_pps-side_data.nut -596100 tests/data/fate/h264_redundant_pps-side_data.nut +18c64ec6b4f0cc39c5f8f3564b372fef *tests/data/fate/h264_redundant_pps-side_data.nut +596084 tests/data/fate/h264_redundant_pps-side_data.nut #extradata 0: 34, 0x850408e3 #tb 0: 1/48000 #media_type 0: video diff --git a/tests/ref/fate/h264_redundant_pps-side_data2 b/tests/ref/fate/h264_redundant_pps-side_data2 index 7484fbeb07..820583628b 100644 --- a/tests/ref/fate/h264_redundant_pps-side_data2 +++ b/tests/ref/fate/h264_redundant_pps-side_data2 @@ -1,5 +1,5 @@ -dd953f8d95d2927703ce9593a07fe2e7 *tests/data/fate/h264_redundant_pps-side_data2.nut -5162 tests/data/fate/h264_redundant_pps-side_data2.nut +f94ed2c25b6bbe63160743f08de33665 *tests/data/fate/h264_redundant_pps-side_data2.nut +5138 tests/data/fate/h264_redundant_pps-side_data2.nut #tb 0: 1/25 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/matroska-alac-remux b/tests/ref/fate/matroska-alac-remux index 9b73263acd..1e7a5b4c8e 100644 --- a/tests/ref/fate/matroska-alac-remux +++ b/tests/ref/fate/matroska-alac-remux @@ -1,5 +1,5 @@ -90c54a00ad8662c3eb93150791fa8328 *tests/data/fate/matroska-alac-remux.matroska -1293824 tests/data/fate/matroska-alac-remux.matroska +6075eb35f53692596194f3b0175cb184 *tests/data/fate/matroska-alac-remux.matroska +1293794 tests/data/fate/matroska-alac-remux.matroska #extradata 0: 36, 0x562b05d8 #tb 0: 1/1000 #media_type 0: audio diff --git a/tests/ref/fate/matroska-dovi-write-config7 b/tests/ref/fate/matroska-dovi-write-config7 index 5f3e000279..edb6757c68 100644 --- a/tests/ref/fate/matroska-dovi-write-config7 +++ b/tests/ref/fate/matroska-dovi-write-config7 @@ -1,5 +1,5 @@ -7adef53df9e14358e0b99f8a829e2d97 *tests/data/fate/matroska-dovi-write-config7.matroska -72700 tests/data/fate/matroska-dovi-write-config7.matroska +adafbb4d021db027f4ae4ef7ca1c56c2 *tests/data/fate/matroska-dovi-write-config7.matroska +72640 tests/data/fate/matroska-dovi-write-config7.matroska #extradata 0: 116, 0x2b8d1669 #extradata 1: 116, 0x2b8d1669 #tb 0: 1/1000 diff --git a/tests/ref/fate/mov-mp4-iamf-5_1_4 b/tests/ref/fate/mov-mp4-iamf-5_1_4 index 18a1f5337f..9eaa5ee42d 100644 --- a/tests/ref/fate/mov-mp4-iamf-5_1_4 +++ b/tests/ref/fate/mov-mp4-iamf-5_1_4 @@ -160,7 +160,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 @@ -395,7 +394,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 diff --git a/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first index d5a1fe1cad..55cadb3d02 100644 --- a/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first +++ b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-first @@ -207,7 +207,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=1 id=0x2 @@ -465,7 +464,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=1 id=0x2 diff --git a/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last index caf89d41f6..80c924c821 100644 --- a/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last +++ b/tests/ref/fate/mov-mp4-iamf-7_1_4-video-last @@ -207,7 +207,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x9 @@ -465,7 +464,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x9 diff --git a/tests/ref/fate/mov-mp4-iamf-ambisonic_1 b/tests/ref/fate/mov-mp4-iamf-ambisonic_1 index d0877f73c7..b6f14099c3 100644 --- a/tests/ref/fate/mov-mp4-iamf-ambisonic_1 +++ b/tests/ref/fate/mov-mp4-iamf-ambisonic_1 @@ -99,7 +99,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 @@ -264,7 +263,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 diff --git a/tests/ref/fate/mov-mp4-iamf-stereo b/tests/ref/fate/mov-mp4-iamf-stereo index ca8f6a76f5..85e6e3efbb 100644 --- a/tests/ref/fate/mov-mp4-iamf-stereo +++ b/tests/ref/fate/mov-mp4-iamf-stereo @@ -52,7 +52,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 @@ -187,7 +186,6 @@ DISPOSITION:still_image=0 DISPOSITION:multilayer=0 TAG:language=und TAG:handler_name=SoundHandler -TAG:vendor_id=[0][0][0][0] [STREAM] index=0 id=0x0 -- 2.52.0 >From 85a32c764bb9ae664d0ce391c3d1c75d70f65002 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sun, 23 Nov 2025 17:01:39 -0300 Subject: [PATCH 3/7] avformat/mov: reindent after the previous change Signed-off-by: James Almer <[email protected]> (cherry picked from commit fd4e86be9ec88ffbe4deb12339ca42575d69ca68) --- libavformat/mov.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index b724c310ef..8dd72b7c2a 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -2681,12 +2681,12 @@ static void mov_parse_stsd_video(MOVContext *c, AVIOContext *pb, avio_skip(pb, 2); /* reserved */ avio_skip(pb, 12); /* pre_defined */ } else { - avio_rb16(pb); /* version */ - avio_rb16(pb); /* revision level */ - id = avio_rl32(pb); /* vendor */ - av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); - avio_rb32(pb); /* temporal quality */ - avio_rb32(pb); /* spatial quality */ + avio_rb16(pb); /* version */ + avio_rb16(pb); /* revision level */ + id = avio_rl32(pb); /* vendor */ + av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); + avio_rb32(pb); /* temporal quality */ + avio_rb32(pb); /* spatial quality */ } st->codecpar->width = avio_rb16(pb); /* width */ @@ -2740,9 +2740,9 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, if (c->isom) avio_skip(pb, 6); /* reserved */ else { - avio_rb16(pb); /* revision level */ - id = avio_rl32(pb); /* vendor */ - av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); + avio_rb16(pb); /* revision level */ + id = avio_rl32(pb); /* vendor */ + av_dict_set(&st->metadata, "vendor_id", av_fourcc2str(id), 0); } channel_count = avio_rb16(pb); -- 2.52.0 >From 7399d533acba897c915fe13a1a520cee9b26ec02 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 15 Jan 2026 17:14:29 -0300 Subject: [PATCH 4/7] avformat/mov: add overflow checks to item offset values Fixes issue #21478. Signed-off-by: James Almer <[email protected]> (cherry picked from commit 52b19773530f332d546360dfd6142674d077d8d9) --- libavformat/mov.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libavformat/mov.c b/libavformat/mov.c index 8dd72b7c2a..fc3ed6a07e 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -10198,6 +10198,9 @@ static int read_image_grid(AVFormatContext *s, const HEIFGrid *grid, offset = c->idat_offset; } + if (offset > INT64_MAX - item->extent_offset) + return AVERROR_INVALIDDATA; + avio_seek(s->pb, item->extent_offset + offset, SEEK_SET); avio_r8(s->pb); /* version */ @@ -10296,6 +10299,9 @@ static int read_image_iovl(AVFormatContext *s, const HEIFGrid *grid, offset = c->idat_offset; } + if (offset > INT64_MAX - item->extent_offset) + return AVERROR_INVALIDDATA; + avio_seek(s->pb, item->extent_offset + offset, SEEK_SET); avio_r8(s->pb); /* version */ @@ -10488,6 +10494,9 @@ static int mov_parse_heif_items(AVFormatContext *s) if (err) return AVERROR_INVALIDDATA; + if (offset > INT64_MAX - item->extent_offset) + return AVERROR_INVALIDDATA; + sc->chunk_offsets[0] = item->extent_offset + offset; if (item->item_id == mov->primary_item_id) -- 2.52.0 >From 6a756fbb21f6e423ad017f3e68162e44912760b2 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sun, 22 Feb 2026 11:05:12 -0300 Subject: [PATCH 5/7] avformat/mov: abort if the queried item doesn't exist instead of overwriting it The check for item presence was insufficient as it would result in the last item in the array being overwritten if it existed even if the id didn't match. Fixes: Assertion ref failed at src/libavformat/mov.c:10649 Fixes: clusterfuzz-testcase-minimized-ffmpeg_dem_MOV_fuzzer-5312542695292928 Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg Signed-off-by: James Almer <[email protected]> (cherry picked from commit 28c330d0f3f3301128cab541774924de9ca78e5b) --- libavformat/mov.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index fc3ed6a07e..17782a614b 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -8867,6 +8867,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) HEIFItem *item = NULL; int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb); int offset_type = (version > 0) ? avio_rb16(pb) & 0xf : 0; + int j; if (avio_feof(pb)) return AVERROR_INVALIDDATA; @@ -8890,7 +8891,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) base_offset > INT64_MAX - extent_offset) return AVERROR_INVALIDDATA; - for (int j = 0; j < c->nb_heif_item; j++) { + for (j = 0; j < c->nb_heif_item; j++) { item = c->heif_item[j]; if (!item) item = c->heif_item[j] = av_mallocz(sizeof(*item)); @@ -8900,6 +8901,8 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) } if (!item) return AVERROR(ENOMEM); + if (j == c->nb_heif_item) + return AVERROR_INVALIDDATA; item->item_id = item_id; @@ -8923,7 +8926,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) int64_t size = atom.size; uint32_t item_type; int item_id; - int version, ret; + int i, version, ret; version = avio_r8(pb); avio_rb24(pb); // flags. @@ -8958,7 +8961,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (size > 0) avio_skip(pb, size); - for (int i = 0; i < c->nb_heif_item; i++) { + for (i = 0; i < c->nb_heif_item; i++) { item = c->heif_item[i]; if (!item) item = c->heif_item[i] = av_mallocz(sizeof(*item)); @@ -8970,6 +8973,8 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_bprint_finalize(&item_name, NULL); return AVERROR(ENOMEM); } + if (i == c->nb_heif_item) + return AVERROR_INVALIDDATA; av_freep(&item->name); av_bprint_finalize(&item_name, ret ? &item->name : NULL); -- 2.52.0 >From f9b61216ae9357433d6a4d16dd37505a870462c9 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sun, 22 Feb 2026 11:12:23 -0300 Subject: [PATCH 6/7] avformat/mov: check for EOF in more loops Signed-off-by: James Almer <[email protected]> (cherry picked from commit c3aa28f23d5098b6ec2e8d537d4b9163c483a3ec) --- libavformat/mov.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index 17782a614b..e39ddce99f 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -9097,8 +9097,13 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version) if (!grid->tile_id_list || !grid->tile_item_list || !grid->tile_idx_list) return AVERROR(ENOMEM); /* 'to' item ids */ - for (i = 0; i < entries; i++) + for (i = 0; i < entries; i++) { grid->tile_id_list[i] = version ? avio_rb32(pb) : avio_rb16(pb); + + if (avio_feof(pb)) + return AVERROR_INVALIDDATA; + } + grid->nb_tiles = entries; grid->item = item; @@ -9125,6 +9130,10 @@ static int mov_read_iref_thmb(MOVContext *c, AVIOContext *pb, int version) /* 'to' item ids */ for (int i = 0; i < entries; i++) { HEIFItem *item = get_heif_item(c, version ? avio_rb32(pb) : avio_rb16(pb)); + + if (avio_feof(pb)) + return AVERROR_INVALIDDATA; + if (!item) { av_log(c->fc, AV_LOG_WARNING, "Missing stream referenced by thmb item\n"); continue; -- 2.52.0 >From 0ef360064353e5b834fb35285c1d9d1775655787 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Sun, 22 Feb 2026 23:15:47 -0300 Subject: [PATCH 7/7] avformat/mov: free item_name on infe entry parsing failure Fixes regression since 28c330d0f3f3. Signed-off-by: James Almer <[email protected]> (cherry picked from commit 40e04631133402701a9365e11f152ed7b8c57a61) --- libavformat/mov.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libavformat/mov.c b/libavformat/mov.c index e39ddce99f..54fe8515d8 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -8973,8 +8973,10 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_bprint_finalize(&item_name, NULL); return AVERROR(ENOMEM); } - if (i == c->nb_heif_item) + if (i == c->nb_heif_item) { + av_bprint_finalize(&item_name, NULL); return AVERROR_INVALIDDATA; + } av_freep(&item->name); av_bprint_finalize(&item_name, ret ? &item->name : NULL); -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
