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.
Unified · Split
| @@ -360,7 +360,7 @@ typedef struct MOVContext { · 359 unmodified lines | ||
| 360 | 360 | uint32_t max_stts_delta; |
| 361 | 361 | int primary_item_id; |
| 362 | 362 | int cur_item_id; |
| 363 | − HEIFItem *heif_item; | |
| 363 | + HEIFItem **heif_item; | |
| 364 | 364 | int nb_heif_item; |
| 365 | 365 | HEIFGrid *heif_grid; |
| 366 | 366 | int nb_heif_grid; |
| @@ -197,10 +197,10 @@ static HEIFItem *heif_cur_item(MOVContext *c) · 196 unmodified lines | ||
| 197 | 197 | HEIFItem *item = NULL; |
| 198 | 198 | |
| 199 | 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 | 201 | continue; |
| 202 | 202 | |
| 203 | − item = &c->heif_item[i]; | |
| 203 | + item = c->heif_item[i]; | |
| 204 | 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 | |
| 8658 | 8658 | static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) |
| 8659 | 8659 | { |
| 8660 | − HEIFItem *heif_item; | |
| 8660 | + HEIFItem **heif_item; | |
| 8661 | 8661 | int version, offset_size, length_size, base_offset_size, index_size; |
| 8662 | 8662 | int item_count, extent_count; |
| 8663 | 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 | 8688 | return AVERROR(ENOMEM); |
| 8689 | 8689 | c->heif_item = heif_item; |
| 8690 | 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 | 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 | 8694 | av_log(c->fc, AV_LOG_TRACE, "iloc: item_count %d\n", item_count); |
| 8696 | 8695 | for (int i = 0; i < item_count; i++) { |
| 8696 | + HEIFItem *item = c->heif_item[i]; | |
| 8697 | 8697 | int item_id = (version < 2) ? avio_rb16(pb) : avio_rb32(pb); |
| 8698 | 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 | 8703 | avpriv_report_missing_feature(c->fc, "iloc offset type %d", offset_type); |
| 8704 | 8704 | return AVERROR_PATCHWELCOME; |
| 8705 | 8705 | } |
| 8706 | − c->heif_item[i].item_id = item_id; | |
| 8707 | 8706 | |
| 8708 | 8707 | avio_rb16(pb); // data_reference_index. |
| 8709 | 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 | 8713 | avpriv_report_missing_feature(c->fc, "iloc: extent_count > 1"); |
| 8715 | 8714 | return AVERROR_PATCHWELCOME; |
| 8716 | 8715 | } |
| 8717 | − for (int j = 0; j < extent_count; j++) { | |
| 8716 | + | |
| 8718 | 8717 | if (rb_size(pb, &extent_offset, offset_size) < 0 || |
| 8719 | 8718 | rb_size(pb, &extent_length, length_size) < 0 || |
| 8720 | 8719 | base_offset > INT64_MAX - extent_offset) |
| 8721 | 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 | 8729 | if (offset_type == 1) |
| 8723 | − c->heif_item[i].is_idat_relative = 1; | |
| 8724 | − c->heif_item[i].extent_length = extent_length; | |
| 8725 | − c->heif_item[i].extent_offset = base_offset + extent_offset; | |
| 8730 | + item->is_idat_relative = 1; | |
| 8731 | + item->extent_length = extent_length; | |
| 8732 | + item->extent_offset = base_offset + extent_offset; | |
| 8726 | 8733 | av_log(c->fc, AV_LOG_TRACE, "iloc: item_idx %d, offset_type %d, " |
| 8727 | 8734 | "extent_offset %"PRId64", extent_length %"PRId64"\n", |
| 8728 | − i, offset_type, c->heif_item[i].extent_offset, c->heif_item[i].extent_length); | |
| 8729 | − } | |
| 8735 | + i, offset_type, item->extent_offset, item->extent_length); | |
| 8736 | + | |
| 8737 | + c->nb_heif_item = FFMAX(c->nb_heif_item, i + 1); | |
| 8730 | 8738 | } |
| 8731 | 8739 | |
| 8732 | 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 | |
| 8736 | 8744 | static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) |
| 8737 | 8745 | { |
| 8746 | + HEIFItem *item; | |
| 8738 | 8747 | AVBPrint item_name; |
| 8739 | 8748 | int64_t size = atom.size; |
| 8740 | 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 | 8783 | if (size > 0) |
| 8775 | 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 | 8792 | if (ret) |
| 8778 | − av_bprint_finalize(&item_name, &c->heif_item[idx].name); | |
| 8779 | − c->heif_item[idx].item_id = item_id; | |
| 8780 | − c->heif_item[idx].type = item_type; | |
| 8793 | + av_bprint_finalize(&item_name, &c->heif_item[idx]->name); | |
| 8794 | + c->heif_item[idx]->item_id = item_id; | |
| 8795 | + c->heif_item[idx]->type = item_type; | |
| 8781 | 8796 | |
| 8782 | 8797 | switch (item_type) { |
| 8783 | 8798 | case MKTAG('a','v','0','1'): |
| 8784 | 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 | 8801 | if (ret < 0) |
| 8787 | 8802 | return ret; |
| 8788 | 8803 | break; |
| @@ -8793,7 +8808,7 @@ static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) · 4 unmodified lines | ||
| 8793 | 8808 | |
| 8794 | 8809 | static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) |
| 8795 | 8810 | { |
| 8796 | − HEIFItem *heif_item; | |
| 8811 | + HEIFItem **heif_item; | |
| 8797 | 8812 | int entry_count; |
| 8798 | 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 | 8826 | return AVERROR(ENOMEM); |
| 8812 | 8827 | c->heif_item = heif_item; |
| 8813 | 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 | 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 | 8832 | for (i = 0; i < entry_count; i++) { |
| 8819 | 8833 | MOVAtom infe; |
| 8820 | 8834 | |
| 8821 | − if (avio_feof(pb)) | |
| 8822 | − return AVERROR_INVALIDDATA; | |
| 8835 | + if (avio_feof(pb)) { | |
| 8836 | + ret = AVERROR_INVALIDDATA; | |
| 8837 | + goto fail; | |
| 8838 | + } | |
| 8823 | 8839 | infe.size = avio_rb32(pb) - 8; |
| 8824 | 8840 | infe.type = avio_rl32(pb); |
| 8825 | 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 | 8843 | goto fail; |
| 8828 | 8844 | if (!ret) |
| 8829 | 8845 | got_stream = 1; |
| 8846 | + c->nb_heif_item = FFMAX(c->nb_heif_item, i + 1); | |
| 8830 | 8847 | } |
| 8831 | 8848 | |
| 8832 | 8849 | c->found_iinf = got_stream; |
| 8833 | 8850 | return 0; |
| 8834 | 8851 | fail: |
| 8835 | 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 | 8858 | av_freep(&item->name); |
| 8839 | 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 | 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 | 8885 | continue; |
| 8866 | − item = &c->heif_item[i]; | |
| 8886 | + item = c->heif_item[i]; | |
| 8867 | 8887 | |
| 8868 | 8888 | switch (item->type) { |
| 8869 | 8889 | case MKTAG('g','r','i','d'): |
| @@ -9779,8 +9799,9 @@ static int mov_read_close(AVFormatContext *s) · 909 unmodified lines | ||
| 9779 | 9799 | av_freep(&mov->aes_decrypt); |
| 9780 | 9800 | av_freep(&mov->chapter_tracks); |
| 9781 | 9801 | for (i = 0; i < mov->nb_heif_item; i++) { |
| 9782 | − av_freep(&mov->heif_item[i].name); | |
| 9783 | − av_freep(&mov->heif_item[i].icc_profile); | |
| 9802 | + av_freep(&mov->heif_item[i]->name); | |
| 9803 | + av_freep(&mov->heif_item[i]->icc_profile); | |
| 9804 | + av_freep(&mov->heif_item[i]); | |
| 9784 | 9805 | } |
| 9785 | 9806 | av_freep(&mov->heif_item); |
| 9786 | 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 | 10185 | int k; |
| 10165 | 10186 | |
| 10166 | 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 | 10189 | AVStream *st = item->st; |
| 10169 | 10190 | |
| 10170 | 10191 | if (item->item_id != tile_id) |
| @@ -10233,7 +10254,7 @@ static int mov_parse_heif_items(AVFormatContext *s) · 62 unmodified lines | ||
| 10233 | 10254 | int err; |
| 10234 | 10255 | |
| 10235 | 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 | 10258 | MOVStreamContext *sc; |
| 10238 | 10259 | AVStream *st; |
| 10239 | 10260 | int64_t offset = 0; |