已合并
Fix heif bugs 0909 #5861
hehaokun创建于 9月9日
Fix heif bugs 0909 #5861
已合并
共 4 个文件变更+33-6
| @@ -92,7 +92,7 @@ public: | |||
| 92 | return (int) children_.size() - 1; | 92 | return (int) children_.size() - 1; |
| 93 | } | 93 | } |
| 94 | 94 | ||
| 95 | - const uint32_t MAX_RECURSION_COUNT = 300; | 95 | + static const uint32_t MAX_RECURSION_COUNT = 300; |
| 96 | 96 | ||
| 97 | private: | 97 | private: |
| 98 | uint64_t boxSize_ = 0; | 98 | uint64_t boxSize_ = 0; |
| @@ -144,7 +144,7 @@ const std::map<PixelFormat, GraphicPixelFormat> SURFACE_FORMAT_MAP = { | |||
| 144 | #endif | 144 | #endif |
| 145 | 145 | ||
| 146 | namespace { | 146 | namespace { |
| 147 | - const static size_t DEFAULT_OUTPUT_SIZE = 35 * 1024 * 1024; // 35M | 147 | + const static size_t DEFAULT_OUTPUT_SIZE = 80 * 1024 * 1024; // 80M |
| 148 | const static uint16_t STATIC_METADATA_COLOR_SCALE = 50000; | 148 | const static uint16_t STATIC_METADATA_COLOR_SCALE = 50000; |
| 149 | const static uint16_t STATIC_METADATA_LUM_SCALE = 10000; | 149 | const static uint16_t STATIC_METADATA_LUM_SCALE = 10000; |
| 150 | const static uint8_t INDEX_ZERO = 0; | 150 | const static uint8_t INDEX_ZERO = 0; |
| @@ -49,6 +49,17 @@ heif_error HeifIlocBox::ParseExtents(Item& item, HeifStreamReader &reader, | |||
| 49 | if (extentNum > MAX_HEIF_EXTENT_NUM) { | 49 | if (extentNum > MAX_HEIF_EXTENT_NUM) { |
| 50 | return heif_error_extent_num_too_large; | 50 | return heif_error_extent_num_too_large; |
| 51 | } | 51 | } |
| 52 | + // Cross-validate: each extent consumes indexSize + offsetSize + lengthSize bytes. | ||
| 53 | + // When all field widths are 0, extents consume zero input but still allocate a 48-byte | ||
| 54 | + // struct each, causing uncontrolled memory allocation. Reject such zero-width extents | ||
| 55 | + // with a non-trivial count since they carry no useful data. | ||
| 56 | + size_t perExtentBytes = static_cast<size_t>(indexSize) + static_cast<size_t>(offsetSize) + | ||
| 57 | + static_cast<size_t>(lengthSize); | ||
| 58 | + if (perExtentBytes == 0 && extentNum > 1) { | ||
| 59 | + return heif_error_invalid_data; | ||
| 60 | + } else if (static_cast<size_t>(extentNum) * perExtentBytes > reader.GetRemainSize()) { | ||
| 61 | + return heif_error_invalid_data; | ||
| 62 | + } | ||
| 52 | item.extents.resize(extentNum); | 63 | item.extents.resize(extentNum); |
| 53 | for (int extentIndex = 0; extentIndex < extentNum; extentIndex++) { | 64 | for (int extentIndex = 0; extentIndex < extentNum; extentIndex++) { |
| 54 | // indexSize is taken from the set {0, 4, 8} and indicates the length in bytes of 'index' | 65 | // indexSize is taken from the set {0, 4, 8} and indicates the length in bytes of 'index' |
| @@ -102,6 +113,18 @@ heif_error HeifIlocBox::ParseContent(HeifStreamReader &reader) | |||
| 102 | if (itemCount > MAX_HEIF_ITEM_COUNT) { | 113 | if (itemCount > MAX_HEIF_ITEM_COUNT) { |
| 103 | return heif_error_too_many_item; | 114 | return heif_error_too_many_item; |
| 104 | } | 115 | } |
| 116 | + // Cross-validate declared item count against remaining input bytes to prevent memory exhaustion. | ||
| 117 | + // Only validate per-item fixed headers here; per-extent input bytes are validated in ParseExtents | ||
| 118 | + // for each item individually. | ||
| 119 | + // Per-item fixed header: itemId(2 or 4) + constructionMethod(0 or 2) + dataRefIndex(2) + | ||
| 120 | + // baseOffset(baseOffsetSize) + extent_count(2) | ||
| 121 | + size_t perItemFixed = (GetVersion() < HEIF_BOX_VERSION_TWO ? UINT16_BYTES_NUM : UINT32_BYTES_NUM) + | ||
| 122 | + (GetVersion() >= HEIF_BOX_VERSION_ONE ? UINT16_BYTES_NUM : 0) + | ||
| 123 | + UINT16_BYTES_NUM + static_cast<size_t>(baseOffsetSize) + UINT16_BYTES_NUM; | ||
| 124 | + size_t totalMinBytes = static_cast<size_t>(itemCount) * perItemFixed; | ||
| 125 | + if (totalMinBytes > reader.GetRemainSize()) { | ||
| 126 | + return heif_error_invalid_data; | ||
| 127 | + } | ||
| 105 | for (uint32_t itemIndex = 0; itemIndex < itemCount; ++itemIndex) { | 128 | for (uint32_t itemIndex = 0; itemIndex < itemCount; ++itemIndex) { |
| 106 | Item item; | 129 | Item item; |
| 107 | item.itemId = GetVersion() < HEIF_BOX_VERSION_TWO ? reader.Read16() : reader.Read32(); | 130 | item.itemId = GetVersion() < HEIF_BOX_VERSION_TWO ? reader.Read16() : reader.Read32(); |
| @@ -297,7 +297,8 @@ heif_error HeifDrefBox::ParseContent(HeifStreamReader &reader) | |||
| 297 | return heif_error_invalid_dref; | 297 | return heif_error_invalid_dref; |
| 298 | } | 298 | } |
| 299 | for (uint32_t i = 0; i < entryCount_; i++) { | 299 | for (uint32_t i = 0; i < entryCount_; i++) { |
| 300 | - uint32_t recursionCount = recursionDepth_; | 300 | + uint32_t recursionCount = recursionDepth_ + 1; |
| 301 | + CHECK_ERROR_RETURN_RET(recursionCount > MAX_RECURSION_COUNT, heif_error_too_many_recursion); | ||
| 301 | std::shared_ptr<HeifBox> entry; | 302 | std::shared_ptr<HeifBox> entry; |
| 302 | heif_error error = HeifBox::MakeFromReader(reader, &entry, recursionCount); | 303 | heif_error error = HeifBox::MakeFromReader(reader, &entry, recursionCount); |
| 303 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); | 304 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); |
| @@ -330,7 +331,8 @@ heif_error HeifStsdBox::ParseContent(HeifStreamReader &reader) | |||
| 330 | return heif_error_invalid_stsd; | 331 | return heif_error_invalid_stsd; |
| 331 | } | 332 | } |
| 332 | for (uint32_t i = 0; i < entryCount_; i++) { | 333 | for (uint32_t i = 0; i < entryCount_; i++) { |
| 333 | - uint32_t recursionCount = recursionDepth_; | 334 | + uint32_t recursionCount = recursionDepth_ + 1; |
| 335 | + CHECK_ERROR_RETURN_RET(recursionCount > MAX_RECURSION_COUNT, heif_error_too_many_recursion); | ||
| 334 | std::shared_ptr<HeifBox> entry; | 336 | std::shared_ptr<HeifBox> entry; |
| 335 | heif_error error = HeifBox::MakeFromReader(reader, &entry, recursionCount); | 337 | heif_error error = HeifBox::MakeFromReader(reader, &entry, recursionCount); |
| 336 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); | 338 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); |
| @@ -599,7 +601,8 @@ heif_error HeifHvc1Box::ParseContent(HeifStreamReader &reader) | |||
| 599 | for (uint32_t i = 0; i < HVC1_SKIP_OFFSET; i++) { | 601 | for (uint32_t i = 0; i < HVC1_SKIP_OFFSET; i++) { |
| 600 | reader.Read8(); | 602 | reader.Read8(); |
| 601 | } | 603 | } |
| 602 | - uint32_t recursionCount = recursionDepth_; | 604 | + uint32_t recursionCount = recursionDepth_ + 1; |
| 605 | + CHECK_ERROR_RETURN_RET(recursionCount > MAX_RECURSION_COUNT, heif_error_too_many_recursion); | ||
| 603 | heif_error error = HeifBox::MakeFromReader(reader, &hvccBox_, recursionCount); | 606 | heif_error error = HeifBox::MakeFromReader(reader, &hvccBox_, recursionCount); |
| 604 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); | 607 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); |
| 605 | return reader.GetError(); | 608 | return reader.GetError(); |
| @@ -627,7 +630,8 @@ heif_error HeifAv01Box::ParseContent(HeifStreamReader &reader) | |||
| 627 | depth_ = reader.Read16(); | 630 | depth_ = reader.Read16(); |
| 628 | SkipBytes(reader, PRE_DEFINED3_SIZE); | 631 | SkipBytes(reader, PRE_DEFINED3_SIZE); |
| 629 | 632 | ||
| 630 | - uint32_t recursionCount = recursionDepth_; | 633 | + uint32_t recursionCount = recursionDepth_ + 1; |
| 634 | + CHECK_ERROR_RETURN_RET(recursionCount > MAX_RECURSION_COUNT, heif_error_too_many_recursion); | ||
| 631 | heif_error error = HeifBox::MakeFromReader(reader, &av1cBox_, recursionCount); | 635 | heif_error error = HeifBox::MakeFromReader(reader, &av1cBox_, recursionCount); |
| 632 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); | 636 | CHECK_ERROR_RETURN_RET(error != heif_error_ok, error); |
| 633 | return reader.GetError(); | 637 | return reader.GetError(); |