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.
Showing the changes to libavformat (2 of 2 files). Show all
Unified · Split
| @@ -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; |
| @@ -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 | ||
| 8658 | static int mov_read_iloc(MOVContext *c, AVIOContext *pb, MOVAtom atom) | 8658 | static 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 | ||
| 8736 | static int mov_read_infe(MOVContext *c, AVIOContext *pb, MOVAtom atom, int idx) | 8744 | static 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 | ||
| 8794 | static int mov_read_iinf(MOVContext *c, AVIOContext *pb, MOVAtom atom) | 8809 | static 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; |
| 8834 | fail: | 8851 | fail: |
| 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; |