diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp new file mode 100644 index 000000000..bdeb377bf --- /dev/null +++ b/fs_mgr/liblp/fuzzer/Android.bp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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. + * + */ + +cc_defaults { + name: "liblp_fuzz_defaults", + header_libs: [ + "libstorage_literals_headers", + ], + shared_libs: [ + "liblp", + "libbase", + "liblog", + ], + static_libs: [ + "libcutils", + ], + include_dirs: [ + "system/core/fs_mgr/liblp", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 59148, + hotlists: ["4593311"], + description: "The fuzzers target the APIs of all liblp modules", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped" + } +} + +cc_fuzz { + name: "liblp_builder_fuzzer", + srcs: ["liblp_builder_fuzzer.cpp"], + defaults: ["liblp_fuzz_defaults"], +} + +cc_fuzz { + name: "liblp_super_layout_builder_fuzzer", + srcs: ["liblp_super_layout_builder_fuzzer.cpp"], + defaults: ["liblp_fuzz_defaults"], +} diff --git a/fs_mgr/liblp/fuzzer/README.md b/fs_mgr/liblp/fuzzer/README.md new file mode 100644 index 000000000..be9adbd8e --- /dev/null +++ b/fs_mgr/liblp/fuzzer/README.md @@ -0,0 +1,93 @@ +# Fuzzers for liblp +## Table of contents ++ [liblp_builder_fuzzer](#Builder) ++ [liblp_super_layout_builder_fuzzer](#SuperBuilder) + +# Fuzzer for LiblpBuilder + +LiblpBuilder supports the following parameters: +1. kAttributeTypes (parameter name: "attribute") +2. blockDevSize (parameter name: "blockdev_size") +3. metadataMaxSize (parameter name: "metadata_max_size") +4. metadataSlotCount (parameter name: "metadata_slot_count") +5. partitionName (parameter name: "partition_name") +6. superBlockDeviceName (parameter name: "block_device_name") +7. blockDeviceInfoSize (parameter name: "block_device_info_size") +8. alignment (parameter name: "alignment") +9. alignmentOffset (parameter name: "alignment_offset") +10. logicalBlockSize (parameter name: "logical_block_size") +11. maxMetadataSize (parameter name: "max_metadata_size") +12. numSlots (parameter name: "metadata_slot_count") +13. deviceIndex (parameter name: "device_index") +14. start (parameter name: "start") +15. end (parameter name: "end") +16. addedGroupName (parameter name: "group_name") +17. partitionGroupName (parameter name: "partition_name") +18. numSectors (parameter name: "num_sectors") +19. physicalSector (parameter name: "physical_sector") +20. resizedPartitionSize (parameter name: "requested_size") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`kAttributeTypes`| 1.`LP_PARTITION_ATTR_NONE`,
2.`LP_PARTITION_ATTR_READONLY`,
3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,
4.`LP_PARTITION_ATTR_UPDATED`,
5.`LP_PARTITION_ATTR_DISABLED`|Value obtained from FuzzedDataProvider| +|`blockDevSize`| Integer value from `0` to `100000`|Value obtained from FuzzedDataProvider| +|`metadataMaxSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`metadataSlotCount`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`partitionName`| String |Value obtained from FuzzedDataProvider| +|`superBlockDeviceName`| String |Value obtained from FuzzedDataProvider| +|`blockDeviceInfoSize`| Integer |Value obtained from FuzzedDataProvider| +|`alignment`| Integer |Value obtained from FuzzedDataProvider| +|`alignmentOffset`| Integer |Value obtained from FuzzedDataProvider| +|`logicalBlockSize`| Integer |Value obtained from FuzzedDataProvider| +|`maxMetadataSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`numSlots`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`deviceIndex`| Integer |Value obtained from FuzzedDataProvider| +|`start`| Integer |Value obtained from FuzzedDataProvider| +|`end`| Integer |Value obtained from FuzzedDataProvider| +|`partitionGroupName`| String |Value obtained from FuzzedDataProvider| +|`numSectors`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`physicalSector`| Integer value from `1` to `1000000` |Value obtained from FuzzedDataProvider| +|`resizedPartitionSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) liblp_builder_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/liblp_builder_fuzzer/liblp_builder_fuzzer +``` + +# Fuzzer for LiblpSuperLayoutBuilder + +SuperLayoutBuilder supports the following parameters: +1. kAttributeTypes (parameter name: "attribute") +2. blockDevSize (parameter name: "blockdev_size") +3. metadataMaxSize (parameter name: "metadata_max_size") +4. metadataSlotCount (parameter name: "metadata_slot_count") +5. partitionName (parameter name: "partition_name") +6. data (parameter name: "data") +7. imageName (parameter name: "image_name") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`kAttributeTypes`| 1.`LP_PARTITION_ATTR_NONE`,
2.`LP_PARTITION_ATTR_READONLY`,
3.`LP_PARTITION_ATTR_SLOT_SUFFIXED`,
4.`LP_PARTITION_ATTR_UPDATED`,
5.`LP_PARTITION_ATTR_DISABLED`|Value obtained from FuzzedDataProvider| +|`blockDevSize`| Integer value from `0` to `100000`|Value obtained from FuzzedDataProvider| +|`metadataMaxSize`| Integer value from `0` to `10000` |Value obtained from FuzzedDataProvider| +|`metadataSlotCount`| Integer value from `0` to `2` |Value obtained from FuzzedDataProvider| +|`partitionName`| String |Value obtained from FuzzedDataProvider| +|`data`| String |Value obtained from FuzzedDataProvider| +|`imageName`| String |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) liblp_super_layout_builder_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/liblp_super_layout_builder_fuzzer/liblp_super_layout_builder_fuzzer +``` diff --git a/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp new file mode 100644 index 000000000..e5fbe272a --- /dev/null +++ b/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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 +#include +#include +#include + +using namespace android::fs_mgr; +using namespace std; +using namespace android::storage_literals; + +static constexpr uint64_t kValidBlockSize = 4096 * 50; +static constexpr uint64_t kBlockDeviceInfoSize = 1024 * 1024; +static constexpr uint64_t kValidBlockDeviceInfoSize = 8_GiB; +static constexpr uint64_t kValidMaxGroupSize = 40960; +static constexpr uint64_t kMinBlockDevValue = 0; +static constexpr uint64_t kMaxBlockDevValue = 100000; +static constexpr uint64_t kMinSectorValue = 1; +static constexpr uint64_t kMaxSectorValue = 1000000; +static constexpr uint64_t kMinValue = 0; +static constexpr uint64_t kMaxValue = 10000; +static constexpr uint64_t kValidNumSectors = 1901568; +static constexpr uint64_t kValidPhysicalSector = 3608576; +static constexpr uint64_t kMinElements = 0; +static constexpr uint64_t kMaxElements = 10; +static constexpr uint32_t kValidAlignment = 786432; +static constexpr uint32_t kValidMetadataSize = 40960; +static constexpr uint32_t kValidAlignmentOffset = 229376; +static constexpr uint32_t kValidLogicalBlockSize = 4096; +static constexpr uint32_t kValidMaxMetadataSize = 65536; +static constexpr uint32_t kMinMetadataValue = 0; +static constexpr uint32_t kMaxMetadataValue = 10000; +static constexpr uint32_t kZeroAlignment = 0; +static constexpr uint32_t kZeroAlignmentOffset = 0; +static constexpr uint32_t kMaxBytes = 20; +static constexpr uint32_t kMinSlot = 0; +static constexpr uint32_t kMaxSlot = 10; +static constexpr uint32_t kMinBuilder = 0; +static constexpr uint32_t kMaxBuilder = 4; + +const uint64_t kAttributeTypes[] = { + LP_PARTITION_ATTR_NONE, LP_PARTITION_ATTR_READONLY, LP_PARTITION_ATTR_SLOT_SUFFIXED, + LP_PARTITION_ATTR_UPDATED, LP_PARTITION_ATTR_DISABLED, +}; + +const string kFuzzPartitionName = "fuzz_partition_name"; +const string kSuperPartitionName = "super_partition"; +const string kDeviceInfoName = "super"; +const string kDefaultGroupName = "default"; + +class BuilderFuzzer { + public: + BuilderFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + FuzzedDataProvider mFdp; + void invokeBuilderAPIs(); + void selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName); + void setupBuilder(string superBlockDeviceName); + void callChangePartitionGroup(); + void callVerifyExtentsAgainstSourceMetadata(); + vector mBlockDevices; + unique_ptr mBuilder; + string mResizePartitionName; + string mGroupNames[4] = { + "default", + "group_a", + "group_b", + mFdp.ConsumeRandomLengthString(kMaxBytes), + }; + string mPartitionNames[5] = { + "system_a", + "vendor_a", + "system_b", + "vendor_b", + mFdp.ConsumeRandomLengthString(kMaxBytes), + }; + Partition* mPartition; + Partition* mFuzzPartition; + Partition* mResizePartition; + template + T getParamValue(T validValue) { + T parameter = validValue; + if (mFdp.ConsumeBool()) { + parameter = mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + } + return parameter; + } +}; + +void BuilderFuzzer::selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName) { + switch (randomBuilder) { + case 0: { + uint32_t maxMetadataSize = getParamValue(kValidMaxMetadataSize); + uint32_t numSlots = mFdp.ConsumeBool() + ? kMaxSlot + : mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(mBlockDevices, superBlockDeviceName, maxMetadataSize, + numSlots); + break; + } + case 1: { + uint64_t blockDevSize = + mFdp.ConsumeIntegralInRange(kMinBlockDevValue, kMaxBlockDevValue); + uint32_t metadataMaxSize = + mFdp.ConsumeIntegralInRange(kMinMetadataValue, kMaxMetadataValue); + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount); + break; + } + case 2: { + uint64_t blockDevSize = getParamValue(kValidBlockSize); + uint32_t metadataSize = getParamValue(kValidMetadataSize); + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mBuilder = MetadataBuilder::New(blockDevSize, metadataSize, metadataSlotCount); + break; + } + case 3: { + string superPartitionName = mFdp.ConsumeBool() + ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder = MetadataBuilder::New(PartitionOpener(), superPartitionName, + mFdp.ConsumeIntegralInRange(0, 1) /* slot_number */); + break; + } + case 4: { + string superPartitionName = mFdp.ConsumeBool() + ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder = MetadataBuilder::New( + superPartitionName, + mFdp.ConsumeIntegralInRange(0, 1) /* slot_number */); + break; + } + } +} + +void BuilderFuzzer::setupBuilder(string superBlockDeviceName) { + uint64_t blockDeviceInfoSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidBlockDeviceInfoSize; + uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignment; + uint32_t alignmentOffset = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidAlignmentOffset; + uint32_t logicalBlockSize = + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kValidLogicalBlockSize; + BlockDeviceInfo super(superBlockDeviceName, blockDeviceInfoSize, alignment, alignmentOffset, + logicalBlockSize); + mBlockDevices.push_back(super); + + mBuilder->AddGroup(kDefaultGroupName, mFdp.ConsumeIntegral() /* max_size */); + mPartition = mBuilder->AddPartition(kSuperPartitionName, LP_PARTITION_ATTR_READONLY); + + mFuzzPartition = mBuilder->AddPartition(kFuzzPartitionName, kDefaultGroupName, + LP_PARTITION_ATTR_READONLY); + + string mResizePartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes); + if (!mResizePartitionName.size()) { + mResizePartitionName = "resize_partition"; + } + mResizePartition = mBuilder->AddPartition(mResizePartitionName, kDefaultGroupName, + LP_PARTITION_ATTR_READONLY); + + string changePartitionDeviceInfoName = + mFdp.ConsumeBool() ? kDeviceInfoName : mFdp.ConsumeRandomLengthString(kMaxBytes); + BlockDeviceInfo changePartitionDeviceInfo( + changePartitionDeviceInfoName, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() : kBlockDeviceInfoSize /* size */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kZeroAlignmentOffset /* alignment */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kZeroAlignmentOffset /* alignment_offset */, + mFdp.ConsumeBool() ? mFdp.ConsumeIntegral() + : kValidLogicalBlockSize /* logical_block_size */); + mBlockDevices.push_back(changePartitionDeviceInfo); +} + +void BuilderFuzzer::callChangePartitionGroup() { + string group1 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group1"; + uint64_t group1Size = getParamValue(0); + + string group2 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group2"; + uint64_t group2Size = getParamValue(0); + + bool group1Added = mBuilder->AddGroup(group1, group1Size); + bool group2Added = mBuilder->AddGroup(group2, group2Size); + + string changeGroupPartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes); + if (changeGroupPartitionName.size() && group1Added && group2Added) { + Partition* changeGroupPartition = mBuilder->AddPartition(changeGroupPartitionName, group1, + LP_PARTITION_ATTR_READONLY); + if (changeGroupPartition) { + mBuilder->ChangePartitionGroup(changeGroupPartition, group2); + } + } +} + +void BuilderFuzzer::callVerifyExtentsAgainstSourceMetadata() { + uint64_t sourceBlockDevSize = getParamValue(kValidBlockSize); + uint32_t sourceMetadataMaxSize = getParamValue(kValidMetadataSize); + uint32_t sourceSlotCount = mFdp.ConsumeIntegralInRange(0, 2); + auto sourceBuilder = + MetadataBuilder::New(sourceBlockDevSize, sourceMetadataMaxSize, sourceSlotCount); + + uint64_t targetBlockDevSize = getParamValue(kValidBlockSize); + uint32_t targetMetadataMaxSize = getParamValue(kValidMetadataSize); + uint32_t targetSlotCount = mFdp.ConsumeIntegralInRange(0, 2); + auto targetBuilder = + MetadataBuilder::New(targetBlockDevSize, targetMetadataMaxSize, targetSlotCount); + + if (sourceBuilder && targetBuilder) { + int64_t sourceGroups = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < sourceGroups; ++idx) { + sourceBuilder->AddGroup( + mFdp.PickValueInArray(mGroupNames), + mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral()); + } + + int64_t sourcePartitions = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < sourcePartitions; ++idx) { + sourceBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames), + LP_PARTITION_ATTR_READONLY); + } + + int64_t targetGroups = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < targetGroups; ++idx) { + targetBuilder->AddGroup( + mFdp.PickValueInArray(mGroupNames), + mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral()); + } + + int64_t targetPartitions = mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < targetPartitions; ++idx) { + targetBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames), + LP_PARTITION_ATTR_READONLY); + } + + MetadataBuilder::VerifyExtentsAgainstSourceMetadata( + *sourceBuilder, mFdp.ConsumeBool() ? 0 : 1 /* source_slot_number */, *targetBuilder, + mFdp.ConsumeBool() ? 0 : 1 /* target_slot_number */, + vector{"system", "vendor", mFdp.ConsumeRandomLengthString(kMaxBytes)}); + } +} + +void BuilderFuzzer::invokeBuilderAPIs() { + string superBlockDeviceName = + mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kDeviceInfoName; + uint32_t randomBuilder = mFdp.ConsumeIntegralInRange(kMinBuilder, kMaxBuilder); + selectRandomBuilder(randomBuilder, superBlockDeviceName); + + if (mBuilder.get()) { + setupBuilder(superBlockDeviceName); + + while (mFdp.remaining_bytes()) { + auto invokeAPIs = mFdp.PickValueInArray>({ + [&]() { callChangePartitionGroup(); }, + [&]() { + string addedGroupName = mFdp.PickValueInArray(mGroupNames); + mBuilder->AddGroup(addedGroupName, + mFdp.ConsumeIntegralInRange( + kMinValue, kMaxValue) /* max_size */); + }, + [&]() { + string partitionName = mFdp.PickValueInArray(mPartitionNames); + Partition* addedPartition = mBuilder->AddPartition( + partitionName, mFdp.PickValueInArray(kAttributeTypes)); + }, + [&]() { + int64_t numSectors = mFdp.ConsumeBool() + ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidNumSectors; + int64_t physicalSector = mFdp.ConsumeBool() + ? mFdp.ConsumeIntegralInRange( + kMinSectorValue, kMaxSectorValue) + : kValidPhysicalSector; + + int64_t numExtents = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + bool extentAdded = false; + for (int64_t i = 0; i <= numExtents; ++i) { + extentAdded = mBuilder->AddLinearExtent(mFuzzPartition, kDeviceInfoName, + numSectors, physicalSector); + } + + if (extentAdded) { + unique_ptr metadata = mBuilder->Export(); + uint64_t alignedSize = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + mFuzzPartition->GetBeginningExtents(LP_SECTOR_SIZE * numExtents); + } + }, + [&]() { callVerifyExtentsAgainstSourceMetadata(); }, + [&]() { mBuilder->ListPartitionsInGroup(mFdp.PickValueInArray(mGroupNames)); }, + [&]() { + int64_t maxSize = mFdp.ConsumeIntegral(); + mBuilder->ChangeGroupSize(mFdp.PickValueInArray(mGroupNames), maxSize); + }, + [&]() { + string deviceInfoName = mFdp.ConsumeBool() + ? kDeviceInfoName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder->GetBlockDeviceInfo(deviceInfoName, &mBlockDevices[1]); + }, + [&]() { + string deviceInfoName = mFdp.ConsumeBool() + ? kDeviceInfoName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + mBuilder->UpdateBlockDeviceInfo(deviceInfoName, mBlockDevices[1]); + }, + [&]() { + unique_ptr metadata = mBuilder->Export(); + mBuilder->ImportPartitions(*metadata.get(), + {mFdp.PickValueInArray(mPartitionNames)}); + }, + [&]() { mBuilder->HasBlockDevice(mFdp.PickValueInArray(mPartitionNames)); }, + [&]() { mBuilder->SetVirtualABDeviceFlag(); }, + [&]() { mBuilder->SetAutoSlotSuffixing(); }, + [&]() { mBuilder->ListGroups(); }, + [&]() { mBuilder->UsedSpace(); }, + [&]() { mBuilder->RequireExpandedMetadataHeader(); }, + [&]() { + uint64_t resizedPartitionSize = getParamValue(0); + mBuilder->ResizePartition(mResizePartition, resizedPartitionSize); + }, + [&]() { + uint32_t sourceSlot = mFdp.ConsumeBool() ? 0 : 1; + uint32_t targetSlot = mFdp.ConsumeBool() ? 0 : 1; + PartitionOpener partitionOpener; + string sourcePartition = + mFdp.ConsumeBool() ? kFuzzPartitionName : kDeviceInfoName; + + MetadataBuilder::NewForUpdate(partitionOpener, sourcePartition, sourceSlot, + targetSlot); + partitionOpener.GetDeviceString(mFdp.PickValueInArray(mPartitionNames)); + }, + [&]() { + unique_ptr metadata = mBuilder->Export(); + MetadataBuilder::New(*metadata.get()); + }, + [&]() { mBuilder->AllocatableSpace(); }, + [&]() { + PartitionOpener pOpener; + string superPartitionName = + mFdp.ConsumeBool() ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + pOpener.Open(superPartitionName, O_RDONLY); + pOpener.GetInfo(superPartitionName, &mBlockDevices[0]); + }, + [&]() { + PartitionOpener pOpener; + string superPartitionName = + mFdp.ConsumeBool() ? kSuperPartitionName + : mFdp.ConsumeRandomLengthString(kMaxBytes); + pOpener.Open(superPartitionName, O_RDONLY); + pOpener.GetDeviceString(superPartitionName); + }, + [&]() { + Interval::Intersect( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral()) /* end */, + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + }, + [&]() { + vector intervalVectorA; + int64_t internalVectorAElements = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < internalVectorAElements; ++idx) { + intervalVectorA.push_back( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + } + + vector intervalVectorB; + int64_t internalVectorBElements = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + for (int64_t idx = 0; idx < internalVectorBElements; ++idx) { + intervalVectorB.push_back( + Interval(mFdp.ConsumeIntegral() /* device _index */, + mFdp.ConsumeIntegral() /* start */, + mFdp.ConsumeIntegral() /* end */)); + } + + Interval::Intersect(intervalVectorA, intervalVectorB); + }, + [&]() { + uint64_t numSectors = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + uint32_t deviceIndex = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + uint64_t physicalSector = + mFdp.ConsumeIntegralInRange(kMinValue, kMaxValue); + LinearExtent extent(numSectors, deviceIndex, physicalSector); + extent.AsInterval(); + }, + [&]() { + IPropertyFetcher::OverrideForTesting(std::make_unique()); + }, + }); + invokeAPIs(); + } + if (mFdp.ConsumeBool()) { + mBuilder->RemoveGroupAndPartitions(mFdp.PickValueInArray(mGroupNames)); + } else { + string removePartition = mFdp.PickValueInArray(mPartitionNames); + mBuilder->RemovePartition(removePartition); + } + } +} + +void BuilderFuzzer::process() { + invokeBuilderAPIs(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + BuilderFuzzer builderFuzzer(data, size); + builderFuzzer.process(); + return 0; +} diff --git a/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp b/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp new file mode 100644 index 000000000..887093c88 --- /dev/null +++ b/fs_mgr/liblp/fuzzer/liblp_super_layout_builder_fuzzer.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +using namespace android::fs_mgr; +using namespace std; +using unique_fd = android::base::unique_fd; +using namespace android::storage_literals; + +static constexpr uint64_t kSuperLayoutValidBlockDevSize = 4_MiB; +static constexpr uint64_t kMinBlockDevValue = 0; +static constexpr uint64_t kMaxBlockDevValue = 100000; +static constexpr uint64_t kMinElements = 0; +static constexpr uint64_t kMaxElements = 10; +static constexpr uint32_t kSuperLayoutValidMetadataSize = 8_KiB; +static constexpr uint32_t kMinMetadataValue = 0; +static constexpr uint32_t kMaxMetadataValue = 10000; +static constexpr uint32_t kMaxBytes = 20; +static constexpr uint32_t kMinSlot = 0; +static constexpr uint32_t kMaxSlot = 10; +static constexpr uint32_t kMinOpen = 0; +static constexpr uint32_t kMaxOpen = 2; + +const uint64_t kAttributeTypes[] = { + LP_PARTITION_ATTR_NONE, LP_PARTITION_ATTR_READONLY, LP_PARTITION_ATTR_SLOT_SUFFIXED, + LP_PARTITION_ATTR_UPDATED, LP_PARTITION_ATTR_DISABLED, +}; + +class SuperLayoutBuilderFuzzer { + public: + SuperLayoutBuilderFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + + private: + FuzzedDataProvider mFdp; + void invokeSuperLayoutBuilderAPIs(); + void callRandomOpen(int32_t open); + void addMultiplePartitions(int32_t numPartitions); + void setupSuperLayoutBuilder(string fuzzPartitionName); + SuperLayoutBuilder mSuperLayoutBuilder; + unique_ptr mSuperBuilder; + unique_ptr mMetadata; + bool mOpenSuccess = false; +}; + +void SuperLayoutBuilderFuzzer::setupSuperLayoutBuilder(string fuzzPartitionName) { + uint64_t randomBlockDevSize = + mFdp.ConsumeIntegralInRange(kMinBlockDevValue, kMaxBlockDevValue); + uint64_t blockDevSize = mFdp.ConsumeBool() ? kSuperLayoutValidBlockDevSize : randomBlockDevSize; + uint32_t randomMetadataMaxSize = + mFdp.ConsumeIntegralInRange(kMinMetadataValue, kMaxMetadataValue); + uint32_t metadataMaxSize = + mFdp.ConsumeBool() ? kSuperLayoutValidMetadataSize : randomMetadataMaxSize; + uint32_t metadataSlotCount = mFdp.ConsumeIntegralInRange(kMinSlot, kMaxSlot); + mSuperBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount); + + if (mSuperBuilder.get()) { + if (mFdp.ConsumeBool()) { + int32_t numPartitions = + mFdp.ConsumeIntegralInRange(kMinElements, kMaxElements); + addMultiplePartitions(numPartitions); + } + + uint32_t randomOpen = mFdp.ConsumeIntegralInRange(kMinOpen, kMaxOpen); + callRandomOpen(randomOpen); + + if (!fuzzPartitionName.size()) { + fuzzPartitionName = "builder_partition"; + } + } +} + +void SuperLayoutBuilderFuzzer::addMultiplePartitions(int32_t numPartitions) { + for (int32_t idx = 0; idx < numPartitions; ++idx) { + string partitionName = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) + : "builder_partition"; + mSuperBuilder->AddPartition(partitionName, mFdp.PickValueInArray(kAttributeTypes)); + } +} + +void SuperLayoutBuilderFuzzer::callRandomOpen(int32_t open) { + mMetadata = mSuperBuilder->Export(); + switch (open) { + case 0: { + vector imageData = mFdp.ConsumeBytes(kMaxBytes); + mOpenSuccess = mSuperLayoutBuilder.Open((void*)(imageData.data()), imageData.size()); + break; + } + case 1: { + mOpenSuccess = mSuperLayoutBuilder.Open(*mMetadata.get()); + break; + } + case 2: { + unique_fd fd(syscall(__NR_memfd_create, "image_file", 0)); + WriteToImageFile(fd, *mMetadata.get()); + mOpenSuccess = mSuperLayoutBuilder.Open(fd); + break; + } + } +} + +void SuperLayoutBuilderFuzzer::invokeSuperLayoutBuilderAPIs() { + string imageName = mFdp.ConsumeRandomLengthString(kMaxBytes); + string fuzzPartitionName = + mFdp.ConsumeBool() ? "builder_partition" : mFdp.ConsumeRandomLengthString(kMaxBytes); + setupSuperLayoutBuilder(fuzzPartitionName); + if (mOpenSuccess) { + while (mFdp.remaining_bytes()) { + auto invokeSuperAPIs = mFdp.PickValueInArray>({ + [&]() { mSuperLayoutBuilder.GetImageLayout(); }, + [&]() { + mSuperLayoutBuilder.AddPartition(fuzzPartitionName, imageName, + mFdp.ConsumeIntegral()); + }, + }); + invokeSuperAPIs(); + } + } +} + +void SuperLayoutBuilderFuzzer::process() { + invokeSuperLayoutBuilderAPIs(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + SuperLayoutBuilderFuzzer superLayoutBuilderFuzzer(data, size); + superLayoutBuilderFuzzer.process(); + return 0; +}