History

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.

James Almer committed 2 years ago

Commit 2e338151 parent 7f51cf72 files · +50 −29Browse files

Showing the changes to libavformat (2 of 2 files). Show all

Unified · Split

2 files
  1. libavformat/isom.h +1 −1
  2. libavformat/mov.c +49 −28
libavformat/isom.h+1−1
@@ -360,7 +360,7 @@ typedef struct MOVContext { · 359 unmodified lines
360 uint32_t max_stts_delta;360 uint32_t max_stts_delta;
361 int primary_item_id;361 int primary_item_id;
362 int cur_item_id;362 int cur_item_id;
363 HEIFItem *heif_item;363 HEIFItem **heif_item;
364 int nb_heif_item;364 int nb_heif_item;
365 HEIFGrid *heif_grid;365 HEIFGrid *heif_grid;
366 int nb_heif_grid;366 int nb_heif_grid;
libavformat/mov.c+49−28
@@ -197,10 +197,10 @@ static HEIFItem *heif_cur_item(MOVContext *c) · 196 unmodified lines
197 HEIFItem *item = NULL;197 HEIFItem *item = NULL;
198 198
199 for (int i = 0; i < c->nb_heif_item; i++) {199 for (int i = 0; i < c->nb_heif_item; i++) {
200 if (c->heif_item[i].item_id != c->cur_item_id)200 if (c->heif_item[i]->item_id != c->cur_item_id)
201 continue;201 continue;
202 202
203 item = &c->heif_item[i];203 item = c->heif_item[i];
204 break;204 break;
205 }205 }
206 206
@@ -8657,7 +8657,7 @@ static int mov_read_idat(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 8450 unmodified lines
8657 8657
8658static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)8658static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom)
8659{8659{
8660 HEIFItem *heif_item;8660 HEIFItem **heif_item;
8661 int version, offset_size, length_size, base_offset_size, index_size;8661 int version, offset_size, length_size, base_offset_size, index_size;
8662 int item_count, extent_count;8662 int item_count, extent_count;
8663 int64_t base_offset, extent_offset, extent_length;8663 int64_t base_offset, extent_offset, extent_length;
@@ -8688,12 +8688,12 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 24 unmodified lines
8688 return AVERROR(ENOMEM);8688 return AVERROR(ENOMEM);
8689 c->heif_item = heif_item;8689 c->heif_item = heif_item;
8690 if (item_count > c->nb_heif_item)8690 if (item_count > c->nb_heif_item)
8691 memset(c->heif_item + c->nb_heif_item, 0,8691 memset(&c->heif_item[c->nb_heif_item], 0,
8692 sizeof(*c->heif_item) * (item_count - c->nb_heif_item));8692 sizeof(*c->heif_item) * (item_count - c->nb_heif_item));
8693 c->nb_heif_item = FFMAX(c->nb_heif_item, item_count);
8694 8693
8695 av_log(c->fc, AV_LOG_TRACE, "iloc: item_count %d\n", item_count);8694 av_log(c->fc, AV_LOG_TRACE, "iloc: item_count %d\n", item_count);
8696 for (int i = 0; i < item_count; i++) {8695 for (int i = 0; i < item_count; i++) {
8696 HEIFItem *item = c->heif_item[i];
8697 int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);8697 int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb);
8698 int offset_type = (version > 0) ? avio_rb16(pb) & 0xf : 0;8698 int offset_type = (version > 0) ? avio_rb16(pb) & 0xf : 0;
8699 8699
@@ -8703,7 +8703,6 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 3 unmodified lines
8703 avpriv_report_missing_feature(c->fc, "iloc offset type %d", offset_type);8703 avpriv_report_missing_feature(c->fc, "iloc offset type %d", offset_type);
8704 return AVERROR_PATCHWELCOME;8704 return AVERROR_PATCHWELCOME;
8705 }8705 }
8706 c->heif_item[i].item_id = item_id;
8707 8706
8708 avio_rb16(pb); // data_reference_index.8707 avio_rb16(pb); // data_reference_index.
8709 if (rb_size(pb, &base_offset, base_offset_size) < 0)8708 if (rb_size(pb, &base_offset, base_offset_size) < 0)
@@ -8714,19 +8713,28 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 4 unmodified lines
8714 avpriv_report_missing_feature(c->fc, "iloc: extent_count > 1");8713 avpriv_report_missing_feature(c->fc, "iloc: extent_count > 1");
8715 return AVERROR_PATCHWELCOME;8714 return AVERROR_PATCHWELCOME;
8716 }8715 }
8717 for (int j = 0; j < extent_count; j++) {8716
8718 if (rb_size(pb, &extent_offset, offset_size) < 0 ||8717 if (rb_size(pb, &extent_offset, offset_size) < 0 ||
8719 rb_size(pb, &extent_length, length_size) < 0 ||8718 rb_size(pb, &extent_length, length_size) < 0 ||
8720 base_offset > INT64_MAX - extent_offset)8719 base_offset > INT64_MAX - extent_offset)
8721 return AVERROR_INVALIDDATA;8720 return AVERROR_INVALIDDATA;
8721
8722 if (!item)
8723 item = c->heif_item[i] = av_mallocz(sizeof(*item));
8724 if (!item)
8725 return AVERROR(ENOMEM);
8726
8727 item->item_id = item_id;
8728
8722 if (offset_type == 1)8729 if (offset_type == 1)
8723 c->heif_item[i].is_idat_relative = 1;8730 item->is_idat_relative = 1;
8724 c->heif_item[i].extent_length = extent_length;8731 item->extent_length = extent_length;
8725 c->heif_item[i].extent_offset = base_offset + extent_offset;8732 item->extent_offset = base_offset + extent_offset;
8726 av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, "8733 av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, "
8727 "extent_offset %"PRId64", extent_length %"PRId64"\n",8734 "extent_offset %"PRId64", extent_length %"PRId64"\n",
8728 i, offset_type, c->heif_item[i].extent_offset, c->heif_item[i].extent_length);8735 i, offset_type, item->extent_offset, item->extent_length);
8729 }8736
8737 c->nb_heif_item = FFMAX(c->nb_heif_item, i + 1);
8730 }8738 }
8731 8739
8732 c->found_iloc = 1;8740 c->found_iloc = 1;
@@ -8735,6 +8743,7 @@ static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 2 unmodified lines
8735 8743
8736static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx)8744static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx)
8737{8745{
8746 HEIFItem *item;
8738 AVBPrint item_name;8747 AVBPrint item_name;
8739 int64_t size = atom.size;8748 int64_t size = atom.size;
8740 uint32_t item_type;8749 uint32_t item_type;
@@ -8774,15 +8783,21 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) · 33 unmodified lines
8774 if (size > 0)8783 if (size > 0)
8775 avio_skip(pb, size);8784 avio_skip(pb, size);
8776 8785
8786 item = c->heif_item[idx];
8787 if (!item)
8788 item = c->heif_item[idx] = av_mallocz(sizeof(*item));
8789 if (!item)
8790 return AVERROR(ENOMEM);
8791
8777 if (ret)8792 if (ret)
8778 av_bprint_finalize(&item_name, &c->heif_item[idx].name);8793 av_bprint_finalize(&item_name, &c->heif_item[idx]->name);
8779 c->heif_item[idx].item_id = item_id;8794 c->heif_item[idx]->item_id = item_id;
8780 c->heif_item[idx].type = item_type;8795 c->heif_item[idx]->type = item_type;
8781 8796
8782 switch (item_type) {8797 switch (item_type) {
8783 case MKTAG('a','v','0','1'):8798 case MKTAG('a','v','0','1'):
8784 case MKTAG('h','v','c','1'):8799 case MKTAG('h','v','c','1'):
8785 ret = heif_add_stream(c, &c->heif_item[idx]);8800 ret = heif_add_stream(c, c->heif_item[idx]);
8786 if (ret < 0)8801 if (ret < 0)
8787 return ret;8802 return ret;
8788 break;8803 break;
@@ -8793,7 +8808,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) · 4 unmodified lines
8793 8808
8794static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom)8809static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom)
8795{8810{
8796 HEIFItem *heif_item;8811 HEIFItem **heif_item;
8797 int entry_count;8812 int entry_count;
8798 int version, got_stream = 0, ret, i;8813 int version, got_stream = 0, ret, i;
8799 8814
@@ -8811,15 +8826,16 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 11 unmodified lines
8811 return AVERROR(ENOMEM);8826 return AVERROR(ENOMEM);
8812 c->heif_item = heif_item;8827 c->heif_item = heif_item;
8813 if (entry_count > c->nb_heif_item)8828 if (entry_count > c->nb_heif_item)
8814 memset(c->heif_item + c->nb_heif_item, 0,8829 memset(&c->heif_item[c->nb_heif_item], 0,
8815 sizeof(*c->heif_item) * (entry_count - c->nb_heif_item));8830 sizeof(*c->heif_item) * (entry_count - c->nb_heif_item));
8816 c->nb_heif_item = FFMAX(c->nb_heif_item, entry_count);
8817 8831
8818 for (i = 0; i < entry_count; i++) {8832 for (i = 0; i < entry_count; i++) {
8819 MOVAtom infe;8833 MOVAtom infe;
8820 8834
8821 if (avio_feof(pb))8835 if (avio_feof(pb)) {
8822 return AVERROR_INVALIDDATA;8836 ret = AVERROR_INVALIDDATA;
8837 goto fail;
8838 }
8823 infe.size = avio_rb32(pb) - 8;8839 infe.size = avio_rb32(pb) - 8;
8824 infe.type = avio_rl32(pb);8840 infe.type = avio_rl32(pb);
8825 ret = mov_read_infe(c, pb, infe, i);8841 ret = mov_read_infe(c, pb, infe, i);
@@ -8827,13 +8843,17 @@ static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) · 1 unmodified line
8827 goto fail;8843 goto fail;
8828 if (!ret)8844 if (!ret)
8829 got_stream = 1;8845 got_stream = 1;
8846 c->nb_heif_item = FFMAX(c->nb_heif_item, i + 1);
8830 }8847 }
8831 8848
8832 c->found_iinf = got_stream;8849 c->found_iinf = got_stream;
8833 return 0;8850 return 0;
8834fail:8851fail:
8835 for (; i >= 0; i--) {8852 for (; i >= 0; i--) {
8836 HEIFItem *item = &c->heif_item[i];8853 HEIFItem *item = c->heif_item[i];
8854
8855 if (!item)
8856 continue;
8837 8857
8838 av_freep(&item->name);8858 av_freep(&item->name);
8839 if (!item->st)8859 if (!item->st)
@@ -8861,9 +8881,9 @@ static int mov_read_iref_dimg(MOVContext *c, AVIOContext *pb, int version) · 21 unmodified lines
8861 }8881 }
8862 }8882 }
8863 for (int i = 0; i < c->nb_heif_item; i++) {8883 for (int i = 0; i < c->nb_heif_item; i++) {
8864 if (c->heif_item[i].item_id != from_item_id)8884 if (c->heif_item[i]->item_id != from_item_id)
8865 continue;8885 continue;
8866 item = &c->heif_item[i];8886 item = c->heif_item[i];
8867 8887
8868 switch (item->type) {8888 switch (item->type) {
8869 case MKTAG('g','r','i','d'):8889 case MKTAG('g','r','i','d'):
@@ -9779,8 +9799,9 @@ static int mov_read_close(AVFormatContext *s) · 909 unmodified lines
9779 av_freep(&mov->aes_decrypt);9799 av_freep(&mov->aes_decrypt);
9780 av_freep(&mov->chapter_tracks);9800 av_freep(&mov->chapter_tracks);
9781 for (i = 0; i < mov->nb_heif_item; i++) {9801 for (i = 0; i < mov->nb_heif_item; i++) {
9782 av_freep(&mov->heif_item[i].name);9802 av_freep(&mov->heif_item[i]->name);
9783 av_freep(&mov->heif_item[i].icc_profile);9803 av_freep(&mov->heif_item[i]->icc_profile);
9804 av_freep(&mov->heif_item[i]);
9784 }9805 }
9785 av_freep(&mov->heif_item);9806 av_freep(&mov->heif_item);
9786 for (i = 0; i < mov->nb_heif_grid; i++) {9807 for (i = 0; i < mov->nb_heif_grid; i++) {
@@ -10164,7 +10185,7 @@ static int mov_parse_tiles(AVFormatContext *s) · 377 unmodified lines
10164 int k;10185 int k;
10165 10186
10166 for (k = 0; k < mov->nb_heif_item; k++) {10187 for (k = 0; k < mov->nb_heif_item; k++) {
10167 HEIFItem *item = &mov->heif_item[k];10188 HEIFItem *item = mov->heif_item[k];
10168 AVStream *st = item->st;10189 AVStream *st = item->st;
10169 10190
10170 if (item->item_id != tile_id)10191 if (item->item_id != tile_id)
@@ -10233,7 +10254,7 @@ static int mov_parse_heif_items(AVFormatContext *s) · 62 unmodified lines
10233 int err;10254 int err;
10234 10255
10235 for (int i = 0; i < mov->nb_heif_item; i++) {10256 for (int i = 0; i < mov->nb_heif_item; i++) {
10236 HEIFItem *item = &mov->heif_item[i];10257 HEIFItem *item = mov->heif_item[i];
10237 MOVStreamContext *sc;10258 MOVStreamContext *sc;
10238 AVStream *st;10259 AVStream *st;
10239 int64_t offset = 0;10260 int64_t offset = 0;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t