diff --git a/frameworks/innerkitsimpl/test/fuzztest/BUILD.gn b/frameworks/innerkitsimpl/test/fuzztest/BUILD.gn index 65e6a286ba3340c13b40feb07f7677b1e3f7ef00..983229710f3e117161e8a57d64433b3f3cd76ed7 100644 --- a/frameworks/innerkitsimpl/test/fuzztest/BUILD.gn +++ b/frameworks/innerkitsimpl/test/fuzztest/BUILD.gn @@ -26,6 +26,7 @@ group("fuzztest") { "imagegifencoder_fuzzer:ImageGifEnCoderFuzzTest", "imageheifimpl_fuzzer:ImageHeifImplFuzzTest", "imageheifimpl2_fuzzer:ImageHeifImpl2FuzzTest", + "imageheifparser_fuzzer:ImageHeifParserFuzzTest", "imageinterfacepixelmap_fuzzer:ImageInterfacePixelmapFuzzTest", "imagepixelYuv_fuzzer:ImagePixelYuvFuzzTest", "imagepixelYuv2_fuzzer:ImagePixelYuv2FuzzTest", diff --git a/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/BUILD.gn b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..e3aecfcb790df3b6b4a44a4fd0456b6ee4323a3f --- /dev/null +++ b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/BUILD.gn @@ -0,0 +1,56 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/test.gni") +import("//foundation/multimedia/image_framework/ide/image_decode_config.gni") + +ohos_fuzztest("ImageHeifParserFuzzTest") { + module_out_path = "multimedia_image/image_framework" + fuzz_config_file = "$image_subsystem/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer" + + include_dirs = [ + "./include", + "$image_subsystem/interfaces/innerkits/include", + "$image_subsystem/plugins/common/libs/image/libextplugin/include", + "$image_subsystem/plugins/common/libs/image/libextplugin/include/heif_impl", + "$image_subsystem/plugins/common/libs/image/libextplugin/include/heif_impl/heif_parser", + "$image_subsystem/frameworks/innerkitsimpl/test/fuzztest/common/include", + ] + + sources = [ "src/image_heif_parser_fuzzer.cpp" ] + + defines = [ + "JPEG_HW_DECODE_ENABLE", + "HEIF_HW_DECODE_ENABLE", + ] + + deps = [ + "$image_subsystem/interfaces/innerkits:image_native", + "${image_subsystem}/plugins/common/libs/image/libextplugin:extplugin", + "${image_subsystem}/plugins/common/libs/image/libextplugin:heifimpl", + "${image_subsystem}/plugins/common/libs/image/libextplugin:heifparser", + ] + + external_deps = [ + "drivers_interface_codec:libcodec_proxy_4.0", + "drivers_interface_codec:libimage_proxy_2.1", + "graphic_2d:color_manager", + "graphic_surface:surface", + "openmax:libopenmax_static", + ] + + cflags = [ + "-Dprotected=public", + "-Dprivate=public", + ] +} diff --git a/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/corpus/init b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/corpus/init new file mode 100644 index 0000000000000000000000000000000000000000..7ade8a0faafeaedba7241e7d4a97b8e1f9691932 --- /dev/null +++ b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/corpus/init @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +FUZZ \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/include/image_heif_parser_fuzzer.h b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/include/image_heif_parser_fuzzer.h new file mode 100644 index 0000000000000000000000000000000000000000..711605e5bf868c7084db0e84b41cfe55c9cd5074 --- /dev/null +++ b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/include/image_heif_parser_fuzzer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FRAMEWORKS_INNERKITSIMPL_TEST_FUZZTEST_IMAGEFRAMEWORK_FUZZER_IMAGEHEIFPARSER_FUZZER_H +#define FRAMEWORKS_INNERKITSIMPL_TEST_FUZZTEST_IMAGEFRAMEWORK_FUZZER_IMAGEHEIFPARSER_FUZZER_H + +#define FUZZ_PROJECT_NAME "image_heif_parser_fuzzer" +#endif \ No newline at end of file diff --git a/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/project.xml b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/project.xml new file mode 100644 index 0000000000000000000000000000000000000000..138c61f16cf77f061e500f348d9f227600d43d53 --- /dev/null +++ b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/project.xml @@ -0,0 +1,25 @@ + + + + + + 52428800 + + 300 + + 4096 + + diff --git a/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/src/image_heif_parser_fuzzer.cpp b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/src/image_heif_parser_fuzzer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ce865ad94bc5060bf6afa9c5c873c45dd51445b4 --- /dev/null +++ b/frameworks/innerkitsimpl/test/fuzztest/imageheifparser_fuzzer/src/image_heif_parser_fuzzer.cpp @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "image_heif_parser_fuzzer.h" + +#include +#include +#include +#include + +#include "box/item_info_box.h" +#include "box/heif_box.h" +#include "box/basic_box.h" +#include "box/item_data_box.h" +#include "box/item_ref_box.h" +#include "box/item_property_box.h" +#include "box/item_property_basic_box.h" +#include "box/item_property_aux_box.h" +#include "box/item_property_color_box.h" +#include "box/item_property_display_box.h" +#include "box/item_property_hvcc_box.h" +#include "box/item_property_transform_box.h" +#include "buffer_source_stream.h" +#include "common_fuzztest_function.h" +#include "ext_stream.h" +#include "HeifDecoder.h" +#include "HeifDecoderImpl.h" +#include "heif_parser.h" +#include "heif_image.h" +#include "heif_stream.h" +#include "include/core/SkStream.h" + +namespace OHOS { +namespace Media { +using namespace OHOS::ImagePlugin; +FuzzedDataProvider* FDP; + +namespace { + static constexpr uint32_t MOCK_ITEM_ID = 0; + static constexpr uint32_t MOCK_ITEM_ID2 = 1; + static constexpr uint32_t MOCK_ITEM_GRID = 2; + static constexpr uint32_t MOCK_IMAGE_ID = 3; + static constexpr uint32_t BOX_TYPE_DIMG = fourcc_to_code("dimg"); + static constexpr uint32_t HEIF_MAX_EXIF_SIZE = 128 * 1024; + static constexpr size_t MOCKLEN = 3; + + static constexpr const char *GRID_STR = "grid"; + enum class BoxType : uint8_t { + ILOC = 0, + IDAT, + IINF, + INFE, + PTIM, + META, + FTYP, + TOPB, + CLLI, + IREF, + IPCO, + IPMA, + }; +} + +std::shared_ptr ConstructHeifParser(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return nullptr; + } + std::shared_ptr heifParser; + std::shared_ptr inputStream = std::make_shared(data, size, false); + if (!inputStream) { + return nullptr; + } + if (heif_error_ok != HeifParser::MakeFromStream(inputStream, &heifParser)) { + return std::make_shared(inputStream); + } + return heifParser; +} + +HvccConfig ConstructHvccConfig() +{ + return HvccConfig { + .version = FDP->ConsumeIntegral(), + .generalProfileSpace = FDP->ConsumeIntegral(), + .generalTierFlag = FDP->ConsumeIntegral(), + .generalProfileIdc = FDP->ConsumeIntegral(), + .generalProfileCompatibilityFlags = FDP->ConsumeIntegral(), + .generalConstraintIndicatorFlags = FDP->ConsumeIntegral(), + .generalLevelIdc = FDP->ConsumeIntegral(), + .minSpatialSegmentationIdc = FDP->ConsumeIntegral(), + .parallelismType = FDP->ConsumeIntegral(), + .chromaFormat = FDP->ConsumeIntegral(), + .bitDepthLuma = FDP->ConsumeIntegral(), + .bitDepthChroma = FDP->ConsumeIntegral(), + .avgFrameRate = FDP->ConsumeIntegral(), + .constFrameRate = FDP->ConsumeIntegral(), + .numTemporalLayers = FDP->ConsumeIntegral(), + .temporalIdNested = FDP->ConsumeIntegral(), + }; +} + +std::shared_ptr ConstructHeifColorProfile() +{ + std::vector colorData { + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral() + }; + return std::make_shared( + FDP->ConsumeIntegral(), + colorData); +} + +bool ConstructHeifIlocBox(std::shared_ptr heifParser) +{ + if (heifParser->ilocBox_) { + return true; + } + heifParser->ilocBox_ = std::make_shared(); + if (!heifParser->ilocBox_) { + return false; + } + + std::vector itemIds { + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + MOCK_ITEM_ID + }; + + for (const auto &id : itemIds) { + std::vector mockData(MOCKLEN); + for (auto &data : mockData) { + data = FDP->ConsumeIntegral(); + } + heifParser->AppendIlocData(id, mockData); + } + return true; +} + +bool ConstructHeifIdatBox(std::shared_ptr heifParser) +{ + if (heifParser->idatBox_) { + return true; + } + + heifParser->idatBox_ = std::make_shared(); + if (!heifParser->idatBox_) { + return false; + } + return true; +} + +bool ConstructHeifIinfBox(std::shared_ptr heifParser) +{ + if (heifParser->iinfBox_) { + return true; + } + + heifParser->iinfBox_ = std::make_shared(); + if (!heifParser->iinfBox_) { + return false; + } + return true; +} + +bool ConstructHeifInfeBox(std::shared_ptr heifParser) +{ + if (heifParser->infeBoxes_.count(MOCK_ITEM_ID) && heifParser->infeBoxes_[MOCK_ITEM_ID]) { + return true; + } + if (!ConstructHeifIlocBox(heifParser)) { + return false; + } + + for (size_t i = 0; i < MOCKLEN; i++) { + uint32_t tItemId = i == MOCKLEN - 1 ? MOCK_ITEM_ID2 : FDP->ConsumeIntegral(); + heifParser->infeBoxes_[tItemId] = std::make_shared(); + } + heifParser->infeBoxes_[MOCK_ITEM_ID] = std::make_shared(); + if (!heifParser->infeBoxes_.count(MOCK_ITEM_ID) || !heifParser->infeBoxes_[MOCK_ITEM_ID]) { + return false; + } + heifParser->infeBoxes_[MOCK_ITEM_GRID] = std::make_shared(MOCK_ITEM_GRID, GRID_STR, false); + if (!heifParser->infeBoxes_.count(MOCK_ITEM_GRID) || !heifParser->infeBoxes_[MOCK_ITEM_GRID]) { + return false; + } + return true; +} + +bool ConstructHeifPtimBox(std::shared_ptr heifParser) +{ + if (heifParser->pitmBox_) { + return true; + } + + heifParser->pitmBox_ = std::make_shared(); + if (!heifParser->pitmBox_) { + return false; + } + return true; +} + +bool ConstructHeifTopBoxes(std::shared_ptr heifParser) +{ + if (!heifParser->topBoxes_.empty()) { + return true; + } + std::vector boxes { BoxType::FTYP, BoxType::META, BoxType::CLLI }; + for (uint32_t i = 0; i < MOCKLEN; i++) { + BoxType tType = boxes[FDP->ConsumeIntegral() % MOCKLEN]; + switch (tType) { + case BoxType::FTYP: + heifParser->topBoxes_.emplace_back(std::make_shared()); + break; + case BoxType::META: + heifParser->topBoxes_.emplace_back(std::make_shared()); + break; + case BoxType::CLLI: + heifParser->topBoxes_.emplace_back(std::make_shared()); + break; + default: + break; + } + } + + if (heifParser->topBoxes_.empty()) { + return false; + } + return true; +} + +bool ConstructHeifIrefBox(std::shared_ptr heifParser) +{ + if (heifParser->irefBox_) { + return true; + } + + heifParser->irefBox_ = std::make_shared(); + if (!heifParser->irefBox_) { + return false; + } + std::vector ids; + ids.emplace_back(MOCK_IMAGE_ID); + heifParser->irefBox_->AddReferences(MOCK_ITEM_GRID, BOX_TYPE_DIMG, ids); + std::shared_ptr gridImage = std::make_shared(MOCK_IMAGE_ID); + if (!gridImage) { + return false; + } + heifParser->images_.insert(std::make_pair(MOCK_IMAGE_ID, gridImage)); + if (!heifParser->images_.count(MOCK_IMAGE_ID) || !heifParser->images_[MOCK_IMAGE_ID]) { + return false; + } + return true; +} + +bool ConstructHeifIpcoBox(std::shared_ptr heifParser) +{ + if (heifParser->ipcoBox_) { + return true; + } + + heifParser->ipcoBox_ = std::make_shared(); + if (!heifParser->ipcoBox_) { + return false; + } + return true; +} + +bool ConstructHeifIpmaBox(std::shared_ptr heifParser) +{ + if (heifParser->ipmaBox_) { + return true; + } + + heifParser->ipmaBox_ = std::make_shared(); + if (!heifParser->ipmaBox_) { + return false; + } + return true; +} + +bool ConstructHeifMetaBox(std::shared_ptr heifParser) +{ + if (heifParser->metaBox_) { + return true; + } + + heifParser->metaBox_ = std::make_shared(); + if (!heifParser->metaBox_) { + return false; + } + return true; +} + +bool ConstructHeifBox(std::shared_ptr heifParser, BoxType boxType) +{ + if (!heifParser) { + return false; + } + + switch (boxType) { + case BoxType::ILOC: + return ConstructHeifIlocBox(heifParser); + case BoxType::IDAT: + return ConstructHeifIdatBox(heifParser); + case BoxType::IINF: + return ConstructHeifIinfBox(heifParser); + case BoxType::INFE: + return ConstructHeifInfeBox(heifParser); + case BoxType::PTIM: + return ConstructHeifPtimBox(heifParser); + case BoxType::IREF: + return ConstructHeifIrefBox(heifParser); + case BoxType::IPCO: + return ConstructHeifIpcoBox(heifParser); + case BoxType::IPMA: + return ConstructHeifIpmaBox(heifParser); + case BoxType::META: + return ConstructHeifMetaBox(heifParser); + default: + break; + } + + return false; +} + +void WriteFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifTopBoxes(heifParser) || !ConstructHeifBox(heifParser, BoxType::ILOC)) { + return; + } + HeifStreamWriter writer; + heifParser->Write(writer); +} + +void GetGridLengthFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::INFE)) { + return; + } + std::vector itemIds { + MOCK_ITEM_ID, + MOCK_ITEM_ID2, + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral() + }; + for (const auto &id : itemIds) { + size_t length { 0 }; + heifParser->GetGridLength(id, length); + } +} + +void GetIdenImageFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::INFE) || !ConstructHeifBox(heifParser, BoxType::IREF)) { + return; + } + std::vector itemIds { + MOCK_ITEM_GRID, + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral() + }; + for (const auto &id : itemIds) { + std::shared_ptr out; + heifParser->GetIdenImage(id, out); + } +} + +void AddPropertyFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::IPCO) || !ConstructHeifBox(heifParser, BoxType::IPMA)) { + return; + } + heifParser->AddIspeProperty( + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral()); + heifParser->AddPixiProperty( + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral()); + heifParser->AddHvccProperty(FDP->ConsumeIntegral()); + heifParser->SetAuxcProperty( + FDP->ConsumeIntegral(), + FDP->ConsumeRandomLengthString(MOCKLEN)); + auto colorProfile = ConstructHeifColorProfile(); + heifParser->SetColorProfile( + FDP->ConsumeIntegral(), + colorProfile); +} + +void HeifHvccFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::IPCO) || !ConstructHeifBox(heifParser, BoxType::IPMA)) { + return; + } + uint32_t hvccId = FDP->ConsumeIntegral(); + std::vector hvccData { + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral() + }; + HvccConfig hvccConfig { ConstructHvccConfig() }; + heifParser->AddHvccProperty(hvccId); + heifParser->AppendHvccNalData(hvccId, hvccData); + heifParser->SetHvccConfig(hvccId, hvccConfig); +} + +void AddReferenceFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + + if (!ConstructHeifBox(heifParser, BoxType::META)) { + return; + } + + heifParser->irefBox_.reset(); + std::vector toItemIds { + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral() + }; + heifParser->AddReference( + FDP->ConsumeIntegral(), + FDP->ConsumeIntegral(), + toItemIds); +} + +void SetPrimaryImageFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::PTIM)) { + return; + } + std::shared_ptr heifImage = std::make_shared(FDP->ConsumeIntegral()); + if (!heifImage) { + return; + } + heifParser->SetPrimaryImage(heifImage); + heifParser->SetPrimaryImage(heifImage); + std::shared_ptr heifImageAnother = std::make_shared(FDP->ConsumeIntegral()); + if (!heifImageAnother) { + return; + } + heifParser->SetPrimaryImage(heifImageAnother); +} + +void SetExifMetaDataFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::IINF) || + !ConstructHeifBox(heifParser, BoxType::META) || + !ConstructHeifBox(heifParser, BoxType::ILOC)) { + return; + } + std::shared_ptr heifImage = std::make_shared(FDP->ConsumeIntegral()); + if (!heifImage) { + return; + } + size_t numBytes = FDP->ConsumeIntegralInRange(0, HEIF_MAX_EXIF_SIZE + MOCKLEN); + std::vector metaDataVec = FDP->ConsumeBytes(numBytes); + heifParser->SetExifMetadata(heifImage, metaDataVec.data(), metaDataVec.size()); +} + +void UpdateExifMetaDataFuzzTest(std::shared_ptr heifParser) +{ + if (!heifParser) { + return; + } + if (!ConstructHeifBox(heifParser, BoxType::ILOC)) { + return; + } + uint32_t itemId = FDP->ConsumeIntegral(); + std::shared_ptr heifImage = std::make_shared(itemId); + if (!heifImage) { + return; + } + size_t numBytes = FDP->ConsumeIntegralInRange(0, HEIF_MAX_EXIF_SIZE + MOCKLEN); + std::vector metaDataVec = FDP->ConsumeBytes(numBytes); + heifParser->UpdateExifMetadata(heifImage, metaDataVec.data(), metaDataVec.size(), itemId); +} + +void HeifParserFuzzTest001(const uint8_t *data, size_t size) +{ + if (data == nullptr) { + return; + } + + auto heifParser = ConstructHeifParser(data, size); + if (!heifParser) { + return; + } + + WriteFuzzTest(heifParser); + GetGridLengthFuzzTest(heifParser); + GetIdenImageFuzzTest(heifParser); + AddPropertyFuzzTest(heifParser); + HeifHvccFuzzTest(heifParser); + AddReferenceFuzzTest(heifParser); + SetPrimaryImageFuzzTest(heifParser); + SetExifMetaDataFuzzTest(heifParser); + UpdateExifMetaDataFuzzTest(heifParser); +} + +} // namespace Media +} // namespace OHOS + +/* Fuzzer entry point */ +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + FuzzedDataProvider fdp(data, size); + OHOS::Media::FDP = &fdp; + /* Run your code on data */ + OHOS::Media::HeifParserFuzzTest001(data, size); + return 0; +} \ No newline at end of file