[FFmpeg-cvslog] avformat/mov: use an array of pointers for heif_item
James Almer
git at videolan.org
Sun Nov 17 17:37:31 EET 2024
ffmpeg | branch: release/7.1 | James Almer <jamrial at gmail.com> | Fri Nov 8 20:43:39 2024 -0300| [f8fcebae95f711ce980c954eb41d2e2e703d5e14] | committer: James Almer
avformat/mov: use an array of pointers for heif_item
Pointers to specific entries in the array are stored in other structs, so
in the scenario where heif_item was reallocated when parsing an iloc box after
and iinf one, the pointers may end up referencing freed memory.
Fixes use-after-free with such samples.
Signed-off-by: James Almer <jamrial at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=f8fcebae95f711ce980c954eb41d2e2e703d5e14
---
libavformat/isom.h | 2 +-
libavformat/mov.c | 93 ++++++++++++++++++++++++++++++++++--------------------
2 files changed, 60 insertions(+), 35 deletions(-)
diff --git a/libavformat/isom.h b/libavformat/isom.h
index 4723397048..ffabc01a2d 100644
--- a/libavformat/isom.h
+++ b/libavformat/isom.h
@@ -355,7 +355,7 @@ typedef struct MOVContext {
uint32_t max_stts_delta;
int primary_item_id;
int cur_item_id;
- HEIFItem *heif_item;
+ HEIFItem **heif_item;
int nb_heif_item;
HEIFGrid *heif_grid;
int nb_heif_grid;
diff --git a/libavformat/mov.c b/libavformat/mov.c
index 11ee8b8d7f..54f8594f67 100644
--- a/libavformat/mov.c
+++ b/libavformat/mov.c
@@ -196,10 +196,10 @@ static HEIFItem *heif_cur_item(MOVContext *c)
HEIFItem *item = NULL;
for (int i = 0; i < c->nb_heif_item; i++) {
- if (c->heif_item[i].item_id != c->cur_item_id)
+ if (!c->heif_item[i] || c->heif_item[i]->item_id != c->cur_item_id)
continue;
- item = &c->heif_item[i];
+ item = c->heif_item[i];
break;
}
@@ -8612,7 +8612,7 @@ static int mov_read_idat(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
- HEIFItem *heif_item;
+ HEIFItem **heif_item;
int version, offset_size, length_size, base_offset_size, index_size;
int item_count, extent_count;
int64_t base_offset, extent_offset, extent_length;
@@ -8643,12 +8643,13 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR(ENOMEM);
c->heif_item = heif_item;
if (item_count > c->nb_heif_item)
- memset(c->heif_item + c->nb_heif_item, 0,
+ memset(&c->heif_item[c->nb_heif_item], 0,
sizeof(*c->heif_item) * (item_count - c->nb_heif_item));
c->nb_heif_item = FFMAX(c->nb_heif_item, item_count);
av_log(c->fc, AV_LOG_TRACE, "iloc: item_count %d\n", item_count);
for (int i = 0; i < item_count; i++) {
+ HEIFItem *item = c->heif_item[i];
int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);
int offset_type = (version > 0) ? avio_rb16(pb) & 0xf : 0;
@@ -8658,7 +8659,6 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avpriv_report_missing_feature(c->fc, "iloc offset type %d", offset_type);
return AVERROR_PATCHWELCOME;
}
- c->heif_item[i].item_id = item_id;
avio_rb16(pb); // data_reference_index.
if (rb_size(pb, &base_offset, base_offset_size) < 0)
@@ -8669,19 +8669,26 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
avpriv_report_missing_feature(c->fc, "iloc: extent_count > 1");
return AVERROR_PATCHWELCOME;
}
- for (int j = 0; j < extent_count; j++) {
- if (rb_size(pb, &extent_offset, offset_size) < 0 ||
- rb_size(pb, &extent_length, length_size) < 0 ||
- base_offset > INT64_MAX - extent_offset)
- return AVERROR_INVALIDDATA;
- if (offset_type == 1)
- c->heif_item[i].is_idat_relative = 1;
- c->heif_item[i].extent_length = extent_length;
- c->heif_item[i].extent_offset = base_offset + extent_offset;
- av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, "
- "extent_offset %"PRId64", extent_length %"PRId64"\n",
- i, offset_type, c->heif_item[i].extent_offset, c->heif_item[i].extent_length);
- }
+
+ if (rb_size(pb, &extent_offset, offset_size) < 0 ||
+ rb_size(pb, &extent_length, length_size) < 0 ||
+ base_offset > INT64_MAX - extent_offset)
+ return AVERROR_INVALIDDATA;
+
+ if (!item)
+ item = c->heif_item[i] = av_mallocz(sizeof(*item));
+ if (!item)
+ return AVERROR(ENOMEM);
+
+ item->item_id = item_id;
+
+ if (offset_type == 1)
+ item->is_idat_relative = 1;
+ item->extent_length = extent_length;
+ item->extent_offset = base_offset + extent_offset;
+ av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, "
+ "extent_offset %"PRId64", extent_length %"PRId64"\n",
+ i, offset_type, item->extent_offset, item->extent_length);
}
c->found_iloc = 1;
@@ -8690,6 +8697,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx)
{
+ HEIFItem *item;
AVBPrint item_name;
int64_t size = atom.size;
uint32_t item_type;
@@ -8729,15 +8737,21 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx)
if (size > 0)
avio_skip(pb, size);
+ item = c->heif_item[idx];
+ if (!item)
+ item = c->heif_item[idx] = av_mallocz(sizeof(*item));
+ if (!item)
+ return AVERROR(ENOMEM);
+
if (ret)
- av_bprint_finalize(&item_name, &c->heif_item[idx].name);
- c->heif_item[idx].item_id = item_id;
- c->heif_item[idx].type = item_type;
+ av_bprint_finalize(&item_name, &c->heif_item[idx]->name);
+ c->heif_item[idx]->item_id = item_id;
+ c->heif_item[idx]->type = item_type;
switch (item_type) {
case MKTAG('a','v','0','1'):
case MKTAG('h','v','c','1'):
- ret = heif_add_stream(c, &c->heif_item[idx]);
+ ret = heif_add_stream(c, c->heif_item[idx]);
if (ret < 0)
return ret;
break;
@@ -8748,7 +8762,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx)
static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
{
- HEIFItem *heif_item;
+ HEIFItem **heif_item;
int entry_count;
int version, got_stream = 0, ret, i;
@@ -8766,15 +8780,17 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return AVERROR(ENOMEM);
c->heif_item = heif_item;
if (entry_count > c->nb_heif_item)
- memset(c->heif_item + c->nb_heif_item, 0,
+ memset(&c->heif_item[c->nb_heif_item], 0,
sizeof(*c->heif_item) * (entry_count - c->nb_heif_item));
c->nb_heif_item = FFMAX(c->nb_heif_item, entry_count);
for (i = 0; i < entry_count; i++) {
MOVAtom infe;
- if (avio_feof(pb))
- return AVERROR_INVALIDDATA;
+ if (avio_feof(pb)) {
+ ret = AVERROR_INVALIDDATA;
+ goto fail;
+ }
infe.size = avio_rb32(pb) - 8;
infe.type = avio_rl32(pb);
ret = mov_read_infe(c, pb, infe, i);
@@ -8788,7 +8804,10 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
return 0;
fail:
for (; i >= 0; i--) {
- HEIFItem *item = &c->heif_item[i];
+ HEIFItem *item = c->heif_item[i];
+
+ if (!item)
+ continue;
av_freep(&item->name);
if (!item->st)
@@ -8816,9 +8835,9 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version)
}
}
for (int i = 0; i < c->nb_heif_item; i++) {
- if (c->heif_item[i].item_id != from_item_id)
+ if (!c->heif_item[i] || c->heif_item[i]->item_id != from_item_id)
continue;
- item = &c->heif_item[i];
+ item = c->heif_item[i];
switch (item->type) {
case MKTAG('g','r','i','d'):
@@ -9692,8 +9711,12 @@ static int mov_read_close(AVFormatContext *s)
av_freep(&mov->aes_decrypt);
av_freep(&mov->chapter_tracks);
- for (i = 0; i < mov->nb_heif_item; i++)
- av_freep(&mov->heif_item[i].name);
+ for (i = 0; i < mov->nb_heif_item; i++) {
+ if (!mov->heif_item[i])
+ continue;
+ av_freep(&mov->heif_item[i]->name);
+ av_freep(&mov->heif_item[i]);
+ }
av_freep(&mov->heif_item);
for (i = 0; i < mov->nb_heif_grid; i++) {
av_freep(&mov->heif_grid[i].tile_id_list);
@@ -10009,10 +10032,10 @@ static int mov_parse_tiles(AVFormatContext *s)
int k;
for (k = 0; k < mov->nb_heif_item; k++) {
- HEIFItem *item = &mov->heif_item[k];
+ HEIFItem *item = mov->heif_item[k];
AVStream *st = item->st;
- if (item->item_id != tile_id)
+ if (!item || item->item_id != tile_id)
continue;
if (!st) {
av_log(s, AV_LOG_WARNING, "HEIF item id %d from grid id %d doesn't "
@@ -10078,11 +10101,13 @@ static int mov_parse_heif_items(AVFormatContext *s)
int err;
for (int i = 0; i < mov->nb_heif_item; i++) {
- HEIFItem *item = &mov->heif_item[i];
+ HEIFItem *item = mov->heif_item[i];
MOVStreamContext *sc;
AVStream *st;
int64_t offset = 0;
+ if (!item)
+ continue;
if (!item->st) {
if (item->item_id == mov->thmb_item_id) {
av_log(s, AV_LOG_ERROR, "HEIF thumbnail doesn't reference a stream\n");
More information about the ffmpeg-cvslog
mailing list